diff --git a/404.html b/404.html index 0c5a30e..d96ba69 100644 --- a/404.html +++ b/404.html @@ -1,261 +1 @@ - - - - - - - - - - - - - - Page not found | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - -
- -
-
-
- - - -
- - -
- -
-

Page not found

-

Looks like there has been a mistake. Nothing exists here.

-
- -
-

You will be redirected to the main page within 3 seconds. If not redirected, please go back to the home page.

- -
- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Page not found | Andrew M. Zhang

Page not found

Looks like there has been a mistake. Nothing exists here.

You will be redirected to the main page within 3 seconds. If not redirected, please go back to the home page.

\ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 349456b..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,25 +0,0 @@ -# Contributing to al-folio -Thank you for considering to contribute to al-folio! - - -## Pull Requests -We welcome your pull requests (PRs). -For minor fixes (e.g., documentation improvements), feel free to submit a PR directly. -If you would like to implement a new feature or a bug, please make sure you (or someone else) has opened an appropriate issue first; in your PR, please mention the issue it addresses. - - -## Issues -We use GitHub issues to track bugs and feature requests. -Before submitting an issue, please make sure: - -1. You have read [the FAQ section](https://github.com/alshedivat/al-folio#faq) of the README and your question is NOT addressed there. -2. You have done your best to ensure that your issue is NOT a duplicate of one of [the previous issues](https://github.com/alshedivat/al-folio/issues). -3. Your issue is either a bug (unexpected/undesirable behavior) or a feature request. -If it is just a question, please ask it in the [Discussions](https://github.com/alshedivat/al-folio/discussions) forum. - -When submitting an issue, please make sure to use the appropriate template. - - -## License -By contributing to al-folio, you agree that your contributions will be licensed -under the LICENSE file in the root directory of the source tree. diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index a1eb21a..0000000 --- a/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM bitnami/minideb:latest -Label MAINTAINER Amir Pourmand -RUN apt-get update -y -# add locale -RUN apt-get -y install locales -# Set the locale -RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ - locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -# add ruby and jekyll -RUN apt-get install --no-install-recommends ruby-full build-essential zlib1g-dev -y -RUN apt-get install imagemagick -y -RUN apt-get clean \ - && rm -rf /var/lib/apt/lists/ -# ENV GEM_HOME='root/gems' \ -# PATH="root/gems/bin:${PATH}" -RUN gem install jekyll bundler -RUN mkdir /srv/jekyll -ADD Gemfile /srv/jekyll -WORKDIR /srv/jekyll -RUN bundle install \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f2b8681..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 Maruan Al-Shedivat. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 2d6254c..0000000 --- a/README.md +++ /dev/null @@ -1,656 +0,0 @@ -# al-folio - -[maintainers]: https://img.shields.io/badge/maintainers-4-success.svg 'Number of maintainers' - - -[![deploy](https://github.com/alshedivat/al-folio/actions/workflows/deploy.yml/badge.svg)](https://github.com/alshedivat/al-folio/actions/workflows/deploy.yml) -[![demo](https://img.shields.io/badge/theme-demo-brightgreen.svg)](https://alshedivat.github.io/al-folio/) -[![GitHub contributors](https://img.shields.io/github/contributors/alshedivat/al-folio.svg)](https://github.com/alshedivat/al-folio/graphs/contributors/) -[![Maintainers][maintainers]](#maintainers) -[![GitHub release](https://img.shields.io/github/v/release/alshedivat/al-folio)](https://github.com/alshedivat/al-folio/releases/latest) -[![GitHub license](https://img.shields.io/github/license/alshedivat/al-folio?color=blue)](https://github.com/alshedivat/al-folio/blob/master/LICENSE) -[![GitHub stars](https://img.shields.io/github/stars/alshedivat/al-folio)](https://github.com/alshedivat/al-folio) -[![GitHub forks](https://img.shields.io/github/forks/alshedivat/al-folio)](https://github.com/alshedivat/al-folio/fork) - -[![Docker Image Version](https://img.shields.io/docker/v/amirpourmand/al-folio?sort=semver&label=docker%20image&color=blueviolet)](https://hub.docker.com/r/amirpourmand/al-folio) -[![Docker Image Size](https://img.shields.io/docker/image-size/amirpourmand/al-folio?sort=date&label=docker%20image%20size&color=blueviolet)](https://hub.docker.com/r/amirpourmand/al-folio) -[![Docker Pulls](https://img.shields.io/docker/pulls/amirpourmand/al-folio?color=blueviolet)](https://hub.docker.com/r/amirpourmand/al-folio) - -A simple, clean, and responsive [Jekyll](https://jekyllrb.com/) theme for academics. -If you like the theme, give it a star! - -[![Preview](https://raw.githubusercontent.com/alshedivat/al-folio/master/assets/img/al-folio-preview.png)](https://alshedivat.github.io/al-folio/) - -## User community - -The vibrant community of **al-folio** users is growing! -Academics around the world use this theme for their homepages, blogs, lab pages, as well as webpages for courses, workshops, conferences, meetups, and more. -Check out the community webpages below. -Feel free to add your own page(s) by sending a PR. - - - - - - - - - - - - - - - - - - -
Academics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Labs - - - - - - - -
Courses -CMU PGM (S-19)
-CMU DeepRL (F-19, S-20, F-20, S-21, F-21, S-22)
-CMU MMML (F-20, F-22)
-CMU AMMML (S-22, S-23)
-CMU ASI (S-23)
-CMU Distributed Systems (S-21) -
Conferences & workshops -ICLR Blog Post Track (2023)
-ML Retrospectives (NeurIPS: 2019, 2020; ICML: 2020)
-HAMLETS (NeurIPS: 2020)
-ICBINB (NeurIPS: 2020, 2021)
-Neural Compression (ICLR: 2021)
-Score Based Methods (NeurIPS: 2022)
-Images2Symbols (CogSci: 2022) -
- -## Lighthouse PageSpeed Insights - -[![Google PageSpeed](https://raw.githubusercontent.com/alshedivat/al-folio/master/assets/img/pagespeed.svg)](https://pagespeed.web.dev/report?url=https%3A%2F%2Falshedivat.github.io%2Fal-folio%2F&form_factor=desktop) - -## Table Of Contents - - * [User community](#user-community) - * [Lighthouse PageSpeed Insights](#lighthouse-pagespeed-insights) - * [Getting started](#getting-started) - + [Installation](#installation) - - [Local setup using Docker (Recommended on Windows)](#local-setup-using-docker-recommended-on-windows) - - [Local Setup (Standard)](#local-setup-standard) - - [Deployment](#deployment) - - [Upgrading from a previous version](#upgrading-from-a-previous-version) - + [FAQ](#faq) - * [Features](#features) - + [Publications](#publications) - + [Collections](#collections) - + [Layouts](#layouts) - - [The iconic style of Distill](#the-iconic-style-of-distill) - - [Full support for math & code](#full-support-for-math--code) - - [Photos](#photos) - + [Other features](#other-features) - - [GitHub repositories and user stats](#github-repositories-and-user-stats) - - [Theming](#theming) - - [Social media previews](#social-media-previews) - - [Atom (RSS-like) Feed](#atom-rss-like-feed) - - [Related posts](#related-posts) - * [Contributing](#contributing) - + [Core Contributors](#core-contributors) - * [License](#license) - -## Getting started - -Want to learn more about Jekyll? Check out [this tutorial](https://www.taniarascia.com/make-a-static-website-with-jekyll/). -Why Jekyll? Read [Andrej Karpathy's blog post](https://karpathy.github.io/2014/07/01/switching-to-jekyll/)! - -### Installation - -For a hands-on walkthrough of al-folio installation, check out [this cool video tutorial](https://www.youtube.com/watch?v=g6AJ9qPPoyc) by one of the community members! 🎬 🍿 - -The preferred way of using this template is by clicking in [Use this template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template#creating-a-repository-from-a-template) above the file list. -Then, create a new repository at `github.com:/`. If you plan to upload your site to `.github.io`, -note that the name of your repository must be `.github.io` or `.github.io`, as stated in the [GitHub pages docs](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages#types-of-github-pages-sites). -For more information on how to deploy your site, check the [Deployment](#deployment) section below. After you created your new repository, just download it to your machine: - -```bash -$ git clone git@github.com:/.git -$ cd -``` - ---- - -#### Local setup using Docker (Recommended on Windows) - -You need to take the following steps to get `al-folio` up and running in your local machine: - -- First, install [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/). -- Finally, run the following command that will pull a pre-built image from DockerHub and will run your website. - -```bash -$ docker-compose up -``` - -Note that when you run it for the first time, it will download a docker image of size 300MB or so. - -Now, feel free to customize the theme however you like (don't forget to change the name!). After you are done, you can use the same command (`docker-compose up`) to render the webpage with all you changes. Also, make sure to commit your final changes. - -> To change port number, you can edit `docker-compose.yml` file. - -
(click to expand) Build your own docker image: - -> Note: this approach is only necessary if you would like to build an older or very custom version of al-folio. - -Build and run a new docker image using: - -```bash -$ docker-compose -f docker-local.yml up -``` - -> If you want to update jekyll, install new ruby packages, etc., all you have to do is build the image again using `--force-recreate` argument at the end of previous command! It will download ruby and jekyll and install all ruby packages again from scratch. - -
- ---- - -#### Local Setup (Standard) - -Assuming you have [Ruby](https://www.ruby-lang.org/en/downloads/) and [Bundler](https://bundler.io/) installed on your system (*hint: for ease of managing ruby gems, consider using [rbenv](https://github.com/rbenv/rbenv)*). - -```bash -$ bundle install -$ bundle exec jekyll serve --lsi -``` - -Now, feel free to customize the theme however you like (don't forget to change the name!). -After you are done, **commit** your final changes. - ---- - -#### Deployment - -Deploying your website to [GitHub Pages](https://pages.github.com/) is the most popular option. -Starting version [v0.3.5](https://github.com/alshedivat/al-folio/releases/tag/v0.3.5), **al-folio** will automatically re-deploy your webpage each time you push new changes to your repository! :sparkles: - -**For personal and organization webpages:** - -1. The name of your repository **MUST BE** `.github.io` or `.github.io`. -2. In `_config.yml`, set `url` to `https://.github.io` and leave `baseurl` empty. -3. Set up automatic deployment of your webpage (see instructions below). -4. Make changes, commit, and push! -5. After deployment, the webpage will become available at `.github.io`. - -**For project pages:** - -1. In `_config.yml`, set `url` to `https://.github.io` and `baseurl` to `//`. -2. Set up automatic deployment of your webpage (see instructions below). -3. Make changes, commit, and push! -4. After deployment, the webpage will become available at `.github.io//`. - -**To enable automatic deployment:** - -1. Click on **Actions** tab and **Enable GitHub Actions**; do not worry about creating any workflows as everything has already been set for you. -2. Go to Settings -> Actions -> General -> Workflow permissions, and give **Read and write permissions** to GitHub Actions -3. Make any other changes to your webpage, commit, and push. This will automatically trigger the **Deploy** action. -4. Wait for a few minutes and let the action complete. You can see the progress in the **Actions** tab. If completed successfully, in addition to the `master` branch, your repository should now have a newly built `gh-pages` branch. -5. Finally, in the **Settings** of your repository, in the Pages section, set the branch to `gh-pages` (**NOT** to `master`). For more details, see [Configuring a publishing source for your GitHub Pages site](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#choosing-a-publishing-source). - -If you keep your site on another branch, open `.github/workflows/deploy.yml` **on the branch you keep your website on** and change on->push->branches and on->pull\_request->branches to the branch you keep your website on. This will trigger the action on pulls/pushes on that branch. The action will then deploy the website on the branch it was triggered from. - -
(click to expand) Manual deployment to GitHub Pages: - -If you need to manually re-deploy your website to GitHub pages, go to Actions, click "Deploy" in the left sidebar, then "Run workflow." - -
- -
(click to expand) Deployment to another hosting server (non GitHub Pages): - -If you decide to not use GitHub Pages and host your page elsewhere, simply run: - -```bash -$ bundle exec jekyll build --lsi -``` - -which will (re-)generate the static webpage in the `_site/` folder. -Then simply copy the contents of the `_site/` directory to your hosting server. - -**Note:** Make sure to correctly set the `url` and `baseurl` fields in `_config.yml` before building the webpage. If you are deploying your webpage to `your-domain.com/your-project/`, you must set `url: your-domain.com` and `baseurl: /your-project/`. If you are deploying directly to `your-domain.com`, leave `baseurl` blank. - -
- -
(click to expand) Deployment to a separate repository (advanced users only): - -**Note:** Do not try using this method unless you know what you are doing (make sure you are familiar with [publishing sources](https://help.github.com/en/github/working-with-github-pages/about-github-pages#publishing-sources-for-github-pages-sites)). This approach allows to have the website's source code in one repository and the deployment version in a different repository. - -Let's assume that your website's publishing source is a `publishing-source` subdirectory of a git-versioned repository cloned under `$HOME/repo/`. -For a user site this could well be something like `$HOME/.github.io`. - -Firstly, from the deployment repo dir, checkout the git branch hosting your publishing source. - -Then from the website sources dir (commonly your al-folio fork's clone): - -```bash -$ bundle exec jekyll build --lsi --destination $HOME/repo/publishing-source -``` - -This will instruct jekyll to deploy the website under `$HOME/repo/publishing-source`. - -**Note:** Jekyll will clean `$HOME/repo/publishing-source` before building! - -The quote below is taken directly from the [jekyll configuration docs](https://jekyllrb.com/docs/configuration/options/): - -> Destination folders are cleaned on site builds -> -> The contents of `` are automatically cleaned, by default, when the site is built. Files or folders that are not created by your site will be removed. Some files could be retained by specifying them within the `` configuration directive. -> -> Do not use an important location for ``; instead, use it as a staging area and copy files from there to your web server. - -If `$HOME/repo/publishing-source` contains files that you want jekyll to leave untouched, specify them under `keep_files` in `_config.yml`. -In its default configuration, al-folio will copy the top-level `README.md` to the publishing source. If you want to change this behavior, add `README.md` under `exclude` in `_config.yml`. - -**Note:** Do _not_ run `jekyll clean` on your publishing source repo as this will result in the entire directory getting deleted, irrespective of the content of `keep_files` in `_config.yml`. - -
- ---- - -#### Upgrading from a previous version - -If you installed **al-folio** as described above, you can configure a [GitHub action](https://github.com/AndreasAugustin/actions-template-sync) to automatically sync your repository with the latest version of the theme. - -Go to Settings -> Actions -> General -> Workflow permissions, give Read and write permissions to GitHub Actions, check "Allow GitHub Actions to create and approve pull requests", and save your changes. - -Then go to Actions -> New workflow -> set up a workflow yourself, setup the following workflow and commit your changes: - -```yaml -name: Sync from template -on: - # cronjob trigger - schedule: - - cron: "0 0 1 * *" - # manual trigger - workflow_dispatch: -jobs: - repo-sync: - runs-on: ubuntu-latest - steps: - # To use this repository's private action, you must check out the repository - - name: Checkout - uses: actions/checkout@v3 - - name: actions-template-sync - uses: AndreasAugustin/actions-template-sync@v0.7.3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - source_repo_path: alshedivat/al-folio - upstream_branch: master -``` - -You will receive a pull request within your repository if there are some changes available in the template. - -Another option is to manually update your code by following the steps below: - -```bash -# Assuming the current directory is -$ git remote add upstream https://github.com/alshedivat/al-folio.git -$ git fetch upstream -$ git rebase v0.9.0 -``` - -If you have extensively customized a previous version, it might be trickier to upgrade. -You can still follow the steps above, but `git rebase` may result in merge conflicts that must be resolved. -See [git rebase manual](https://help.github.com/en/github/using-git/about-git-rebase) and how to [resolve conflicts](https://help.github.com/en/github/using-git/resolving-merge-conflicts-after-a-git-rebase) for more information. -If rebasing is too complicated, we recommend re-installing the new version of the theme from scratch and port over your content and changes from the previous version manually. - ---- - -### FAQ - -Here are some frequently asked questions. -If you have a different question, please ask using [Discussions](https://github.com/alshedivat/al-folio/discussions/categories/q-a). - -1. **Q:** After I create a new repository from this template and setup the repo, I get a deployment error. - Isn't the website supposed to correctly deploy automatically?
- **A:** Yes, if you are using release `v0.3.5` or later, the website will automatically and correctly re-deploy right after your first commit. - Please make some changes (e.g., change your website info in `_config.yml`), commit, and push. - Make sure to follow [deployment instructions](https://github.com/alshedivat/al-folio#deployment) in the previous section. - (Relevant issue: [209](https://github.com/alshedivat/al-folio/issues/209#issuecomment-798849211).) - -2. **Q:** I am using a custom domain (e.g., `foo.com`). - My custom domain becomes blank in the repository settings after each deployment. - How do I fix that?
- **A:** You need to add `CNAME` file to the `master` or `source` branch of your repository. - The file should contain your custom domain name. - (Relevant issue: [130](https://github.com/alshedivat/al-folio/issues/130).) - -3. **Q:** My webpage works locally. - But after deploying, it is not displayed correctly (CSS and JS is not loaded properly). - How do I fix that?
- **A:** Make sure to correctly specify the `url` and `baseurl` paths in `_config.yml`. - Set `url` to `https://.github.io` or to `https://` if you are using a custom domain. - If you are deploying a personal or organization website, leave `baseurl` blank. - If you are deploying a project page, set `baseurl: //`. - -4. **Q:** Atom feed doesn't work. Why? -
- **A:** Make sure to correctly specify the `url` and `baseurl` paths in `_config.yml`. - RSS Feed plugin works with these correctly set up fields: `title`, `url`, `description` and `author`. - Make sure to fill them in an appropriate way and try again. - -5. **Q:** My site doesn't work when I enable `related_blog_posts`. Why?
- **A:** This is probably due to the [classifier reborn](https://github.com/jekyll/classifier-reborn) plugin, which is used to calculate - related posts. If the error states `Liquid Exception: Zero vectors can not be normalized...`, it means that it could not calculate related - posts for a specific post. This is usually caused by [empty or minimal blog posts](https://github.com/jekyll/classifier-reborn/issues/64) - without meaningful words (i.e. only [stop words](https://en.wikipedia.org/wiki/Stop_words)) or even - [specific characters](https://github.com/jekyll/classifier-reborn/issues/194) you used in your posts. Also, the calculus for similar posts are - made for every `post`, which means every page that uses `layout: post`, including the announcements. To change this behavior, simply add - `related_posts: false` to the front matter of the page you don't want to display related posts on. - -## Features - -### Publications - -Your publications' page is generated automatically from your BibTex bibliography. -Simply edit `_bibliography/papers.bib`. -You can also add new `*.bib` files and customize the look of your publications however you like by editing `_pages/publications.md`. - -

- -
(click to expand) Author annotation: - -In publications, the author entry for yourself is identified by string array `scholar:last_name` and string array `scholar:first_name` in `_config.yml`: - -```yaml -scholar: - last_name: [Einstein] - first_name: [Albert, A.] -``` - -If the entry matches one form of the last names and the first names, it will be underlined. -Keep meta-information about your co-authors in `_data/coauthors.yml` and Jekyll will insert links to their webpages automatically. -The co-author data format in `_data/coauthors.yml` is as follows, - -```yaml -"Adams": - - firstname: ["Edwin", "E.", "E. P.", "Edwin Plimpton"] - url: https://en.wikipedia.org/wiki/Edwin_Plimpton_Adams - -"Podolsky": - - firstname: ["Boris", "B.", "B. Y.", "Boris Yakovlevich"] - url: https://en.wikipedia.org/wiki/Boris_Podolsky - -"Rosen": - - firstname: ["Nathan", "N."] - url: https://en.wikipedia.org/wiki/Nathan_Rosen - -"Bach": - - firstname: ["Johann Sebastian", "J. S."] - url: https://en.wikipedia.org/wiki/Johann_Sebastian_Bach - - - firstname: ["Carl Philipp Emanuel", "C. P. E."] - url: https://en.wikipedia.org/wiki/Carl_Philipp_Emanuel_Bach -``` - -If the entry matches one of the combinations of the last names and the first names, it will be highlighted and linked to the url provided. - -
- -
(click to expand) Buttons (through custom bibtex keywords): - -There are several custom bibtex keywords that you can use to affect how the entries are displayed on the webpage: - -- `abbr`: Adds an abbreviation to the left of the entry. You can add links to these by creating a venue.yaml-file in the _data folder and adding entries that match. -- `abstract`: Adds an "Abs" button that expands a hidden text field when clicked to show the abstract text -- `arxiv`: Adds a link to the Arxiv website (Note: only add the arxiv identifier here - the link is generated automatically) -- `bibtex_show`: Adds a "Bib" button that expands a hidden text field with the full bibliography entry -- `html`: Inserts an "HTML" button redirecting to the user-specified link -- `pdf`: Adds a "PDF" button redirecting to a specified file (if a full link is not specified, the file will be assumed to be placed in the /assets/pdf/ directory) -- `supp`: Adds a "Supp" button to a specified file (if a full link is not specified, the file will be assumed to be placed in the /assets/pdf/ directory) -- `blog`: Adds a "Blog" button redirecting to the specified link -- `code`: Adds a "Code" button redirecting to the specified link -- `poster`: Adds a "Poster" button redirecting to a specified file (if a full link is not specified, the file will be assumed to be placed in the /assets/pdf/ directory) -- `slides`: Adds a "Slides" button redirecting to a specified file (if a full link is not specified, the file will be assumed to be placed in the /assets/pdf/ directory) -- `website`: Adds a "Website" button redirecting to the specified link -- `altmetric`: Adds an [Altmetric](https://www.altmetric.com/) badge (Note: if DOI is provided just use `true`, otherwise only add the altmetric identifier here - the link is generated automatically) -- `dimensions`: Adds a [Dimensions](https://www.dimensions.ai/) badge (Note: if DOI or PMID is provided just use `true`, otherwise only add the Dimensions' identifier here - the link is generated automatically) - -You can implement your own buttons by editing the bib.html file. - -
- ---- - -### Collections - -This Jekyll theme implements `collections` to let you break up your work into categories. -The theme comes with two default collections: `news` and `projects`. -Items from the `news` collection are automatically displayed on the home page. -Items from the `projects` collection are displayed on a responsive grid on projects page. - -

- -You can easily create your own collections, apps, short stories, courses, or whatever your creative work is. -To do this, edit the collections in the `_config.yml` file, create a corresponding folder, and create a landing page for your collection, similar to `_pages/projects.md`. - ---- - -### Layouts - -**al-folio** comes with stylish layouts for pages and blog posts. - -#### The iconic style of Distill - -The theme allows you to create blog posts in the [distill.pub](https://distill.pub/) style: - -

- -For more details on how to create distill-styled posts using `` tags, please refer to [the example](https://alshedivat.github.io/al-folio/blog/2021/distill/). - -#### Full support for math & code - -**al-folio** supports fast math typesetting through [MathJax](https://www.mathjax.org/) and code syntax highlighting using [GitHub style](https://github.com/jwarby/jekyll-pygments-themes): - -

- - -

- -#### Photos - -Photo formatting is made simple using [Bootstrap's grid system](https://getbootstrap.com/docs/4.4/layout/grid/). -Easily create beautiful grids within your blog posts and project pages: - -

- - - -

- ---- - -### Other features - -#### GitHub's repositories and user stats - -**al-folio** uses [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) and [github-profile-trophy](https://github.com/ryo-ma/github-profile-trophy) -to display GitHub repositories and user stats on the `/repositories/` page. - -Edit the `_data/repositories.yml` and change the `github_users` and `github_repos` lists to include your own GitHub profile and repositories to the `/repositories/` page. - -You may also use the following codes for displaying this in any other pages. - -```html - -{% if site.data.repositories.github_users %} -
- {% for user in site.data.repositories.github_users %} - {% include repository/repo_user.html username=user %} - {% endfor %} -
-{% endif %} - - -{% if site.repo_trophies.enabled %} -{% for user in site.data.repositories.github_users %} - {% if site.data.repositories.github_users.size > 1 %} -

{{ user }}

- {% endif %} -
- {% include repository/repo_trophies.html username=user %} -
-{% endfor %} -{% endif %} - - -{% if site.data.repositories.github_repos %} -
- {% for repo in site.data.repositories.github_repos %} - {% include repository/repo.html repository=repo %} - {% endfor %} -
-{% endif %} -``` - -#### Theming - -A variety of beautiful theme colors have been selected for you to choose from. -The default is purple, but you can quickly change it by editing the -`--global-theme-color` variable in the `_sass/_themes.scss` file. -Other color variables are listed there as well. -The stock theme color options available can be found at `_sass/variables.scss`. -You can also add your own colors to this file assigning each a name for ease of -use across the template. - -#### Social media previews - -**al-folio** supports preview images on social media. -To enable this functionality you will need to set `serve_og_meta` to `true` in your `_config.yml`. -Once you have done so, all your site's pages will include Open Graph data in the HTML head element. - -You will then need to configure what image to display in your site's social media previews. -This can be configured on a per-page basis, by setting the `og_image` page variable. -If for an individual page this variable is not set, then the theme will fall back to a site-wide `og_image` variable, configurable in your `_config.yml`. -In both the page-specific and site-wide cases, the `og_image` variable needs to hold the URL for the image you wish to display in social media previews. - -#### Atom (RSS-like) Feed - -It generates an Atom (RSS-like) feed of your posts, useful for Atom and RSS readers. -The feed is reachable simply by typing after your homepage `/feed.xml`. -E.g. assuming your website mountpoint is the main folder, you can type `yourusername.github.io/feed.xml` - -#### Related posts - -By default, there will be a related posts section on the bottom of the blog posts. -These are generated by selecting the `max_related` most recent posts that share at least `min_common_tags` tags with the current post. -If you do not want to display related posts on a specific post, simply add `related_posts: false` to the front matter of the post. -If you want to disable it for all posts, simply set `enabled` to false in the `related_blog_posts` section in `_config.yml`. - -## Contributing - -Contributions to al-folio are very welcome! -Before you get started, please take a look at [the guidelines](CONTRIBUTING.md). - -If you would like to improve documentation, add your webpage to the list below, or fix a minor inconsistency or bug, please feel free to send a PR directly to `master`. -For more complex issues/bugs or feature requests, please open an issue using the appropriate template. - -### Maintainers - -Our most active contributors are welcome to join the maintainers team. -If you are interested, please reach out! - - - - - - - - - - - - - -

Maruan

Rohan Deb Sarkar

Amir Pourmand

George
- - - - - - -## License - -The theme is available as open source under the terms of the [MIT License](https://github.com/alshedivat/al-folio/blob/master/LICENSE). - -Originally, **al-folio** was based on the [\*folio theme](https://github.com/bogoli/-folio) (published by [Lia Bogoev](https://liabogoev.com) and under the MIT license). -Since then, it got a full re-write of the styles and many additional cool features. diff --git a/_pages/dropdown/index.html b/_pages/dropdown/index.html new file mode 100644 index 0000000..9748929 --- /dev/null +++ b/_pages/dropdown/index.html @@ -0,0 +1 @@ + submenus | Andrew M. Zhang

submenus

\ No newline at end of file diff --git a/assets/css/academicons.min.css b/assets/css/academicons.min.css new file mode 100644 index 0000000..5d92887 --- /dev/null +++ b/assets/css/academicons.min.css @@ -0,0 +1 @@ + @font-face {font-family: 'Academicons';font-style: normal;font-weight: 400;font-display: block;src:url('../fonts/academicons.eot');src:url('../fonts/academicons.eot') format('embedded-opentype'), url('../fonts/academicons.ttf') format('truetype'), url('../fonts/academicons.woff') format('woff'), url('../fonts/academicons.svg') format('svg');}.ai {font-family: 'Academicons';font-weight: 400;-moz-osx-font-smoothing: grayscale;-webkit-font-smoothing: antialiased;display: inline-block;font-style: normal;font-variant: normal;text-rendering: auto;line-height: 1;} diff --git a/assets/css/bootstrap-toc.min.css b/assets/css/bootstrap-toc.min.css new file mode 100644 index 0000000..3c62107 --- /dev/null +++ b/assets/css/bootstrap-toc.min.css @@ -0,0 +1,4 @@ +/*! + * Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */nav[data-toggle=toc] .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}nav[data-toggle=toc] .nav>li>a:focus,nav[data-toggle=toc] .nav>li>a:hover{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}nav[data-toggle=toc] .nav-link.active,nav[data-toggle=toc] .nav-link.active:focus,nav[data-toggle=toc] .nav-link.active:hover{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}nav[data-toggle=toc] .nav-link+ul{display:none;padding-bottom:10px}nav[data-toggle=toc] .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}nav[data-toggle=toc] .nav .nav>li>a:focus,nav[data-toggle=toc] .nav .nav>li>a:hover{padding-left:29px}nav[data-toggle=toc] .nav .nav>li>.active,nav[data-toggle=toc] .nav .nav>li>.active:focus,nav[data-toggle=toc] .nav .nav>li>.active:hover{padding-left:28px;font-weight:500}nav[data-toggle=toc] .nav-link.active+ul{display:block} \ No newline at end of file diff --git a/assets/css/bootstrap.min.css b/assets/css/bootstrap.min.css new file mode 100644 index 0000000..1acb2c4 --- /dev/null +++ b/assets/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v4.6.2 (https://getbootstrap.com/) + * Copyright 2011-2022 The Bootstrap Authors + * Copyright 2011-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],button{-webkit-appearance:button}[type=button]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:.875em;font-weight:400}.blockquote{margin-bottom:1rem;font-size:1.25rem}.img-fluid{max-width:100%;height:auto}.figure{display:inline-block}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.col,.col-md-10,.col-md-2,.col-md-6,.col-sm-2,.col-sm-3,.col-sm-8,.col-sm-9{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}@media (min-width:576px){.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}}@media (min-width:768px){.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled{pointer-events:none}.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.width{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.width{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar .container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (max-width:575.98px){.navbar-expand-sm>.container{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-title{margin-bottom:.75rem}.card-text:last-child{margin-bottom:0}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{-ms-flex-preferred-size:350px;flex-basis:350px;max-width:350px;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal.modal-static .modal-dialog{-webkit-transform:scale(1.02);transform:scale(1.02)}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}.align-middle{vertical-align:middle!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.rounded{border-radius:.25rem!important}.clearfix::after{display:block;clear:both;content:""}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.float-left{float:left!important}.float-right{float:right!important}.position-static{position:static!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.w-100{width:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.ml-1{margin-left:.25rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.mt-3{margin-top:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mt-5{margin-top:3rem!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.pr-2{padding-right:.5rem!important}.pl-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.ml-auto{margin-left:auto!important}@media (min-width:768px){.mt-md-0{margin-top:0!important}.ml-md-4{margin-left:1.5rem!important}}.text-right{text-align:right!important}.text-center{text-align:center!important}.text-uppercase{text-transform:uppercase!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-bold{font-weight:700!important}.visible{visibility:visible!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}} \ No newline at end of file diff --git a/assets/css/bootstrap.min.css.map b/assets/css/bootstrap.min.css.map new file mode 100644 index 0000000..4eb4637 --- /dev/null +++ b/assets/css/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","bootstrap.css","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_forms.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_forms.scss","../../scss/mixins/_gradients.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/utilities/_interactions.scss","../../scss/utilities/_overflow.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_shadows.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_stretched-link.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/_print.scss"],"names":[],"mappings":"AAAA;;;;;ACAA,MAGI,OAAA,QAAA,SAAA,QAAA,SAAA,QAAA,OAAA,QAAA,MAAA,QAAA,SAAA,QAAA,SAAA,QAAA,QAAA,QAAA,OAAA,QAAA,OAAA,QAAA,QAAA,KAAA,OAAA,QAAA,YAAA,QAIA,UAAA,QAAA,YAAA,QAAA,UAAA,QAAA,OAAA,QAAA,UAAA,QAAA,SAAA,QAAA,QAAA,QAAA,OAAA,QAIA,gBAAA,EAAA,gBAAA,MAAA,gBAAA,MAAA,gBAAA,MAAA,gBAAA,OAKF,yBAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBACA,wBAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UCCF,ECqBA,QADA,SDjBE,WAAA,WAGF,KACE,YAAA,WACA,YAAA,KACA,yBAAA,KACA,4BAAA,YAMF,QAAA,MAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,IAAA,QACE,QAAA,MAUF,KACE,OAAA,EACA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBEqII,UAAA,KFnIJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,KACA,iBAAA,KGYF,0CHCE,QAAA,YASF,GACE,WAAA,YACA,OAAA,EACA,SAAA,QAaF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KChBF,0BD2BA,YAEE,gBAAA,UACA,wBAAA,UAAA,OAAA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EACA,iCAAA,KAAA,yBAAA,KAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QCrBF,GDwBA,GCzBA,GD4BE,WAAA,EACA,cAAA,KAGF,MCxBA,MACA,MAFA,MD6BE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,ECzBA,OD2BE,YAAA,OAGF,MEII,UAAA,IFKJ,IC9BA,IDgCE,SAAA,SEPE,UAAA,IFSF,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YIhLA,QJmLE,MAAA,QACA,gBAAA,UASJ,2BACE,MAAA,QACA,gBAAA,KI/LA,iCJkME,MAAA,QACA,gBAAA,KC/BJ,KACA,IDuCA,ICtCA,KD0CE,YAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UExDE,UAAA,IF4DJ,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAGA,mBAAA,UAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,IAGE,SAAA,OACA,eAAA,OAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAOF,GAEE,WAAA,QACA,WAAA,qBAQF,MAEE,QAAA,aACA,cAAA,MAMF,OAEE,cAAA,EAQF,iCACE,QAAA,EChFF,ODmFA,MCjFA,SADA,OAEA,SDqFE,OAAA,EACA,YAAA,QEhKE,UAAA,QFkKF,YAAA,QAGF,OCnFA,MDqFE,SAAA,QAGF,OCnFA,ODqFE,eAAA,KGnFF,cH0FE,OAAA,QAMF,OACE,UAAA,OCtFF,cACA,aACA,cD2FA,OAIE,mBAAA,OC1FF,6BACA,4BACA,6BD6FE,sBAKI,OAAA,QC7FN,gCACA,+BACA,gCDiGA,yBAIE,QAAA,EACA,aAAA,KChGF,qBDmGA,kBAEE,WAAA,WACA,QAAA,EAIF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,ME9OI,UAAA,OFgPJ,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SG7GF,yCFGA,yCDgHE,OAAA,KG9GF,cHsHE,eAAA,KACA,mBAAA,KGlHF,yCH0HE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UACA,OAAA,QAGF,SACE,QAAA,KG/HF,SHqIE,QAAA,eC9HF,IAAK,IAAK,IAAK,IAAK,IAAK,II9VzB,GAAA,GAAA,GAAA,GAAA,GAAA,GAEE,cAAA,MAEA,YAAA,IACA,YAAA,IAIF,IAAA,GHqKM,UAAA,OGpKN,IAAA,GHoKM,UAAA,KGnKN,IAAA,GHmKM,UAAA,QGlKN,IAAA,GHkKM,UAAA,OGjKN,IAAA,GHiKM,UAAA,QGhKN,IAAA,GHgKM,UAAA,KG9JN,MH8JM,UAAA,QG5JJ,YAAA,IAIF,WHwJM,UAAA,KGtJJ,YAAA,IACA,YAAA,IAEF,WHmJM,UAAA,OGjJJ,YAAA,IACA,YAAA,IAEF,WH8IM,UAAA,OG5IJ,YAAA,IACA,YAAA,IAEF,WHyIM,UAAA,OGvIJ,YAAA,IACA,YAAA,IL6BF,GKpBE,WAAA,KACA,cAAA,KACA,OAAA,EACA,WAAA,IAAA,MAAA,eJ6WF,OIrWA,MHkGI,UAAA,OG/FF,YAAA,IJwWF,MIrWA,KAEE,QAAA,KACA,iBAAA,QAQF,eC/EE,aAAA,EACA,WAAA,KDmFF,aCpFE,aAAA,EACA,WAAA,KDsFF,kBACE,QAAA,aADF,mCAII,aAAA,MAUJ,YH2DI,UAAA,IGzDF,eAAA,UAIF,YACE,cAAA,KHoEI,UAAA,QGhEN,mBACE,QAAA,MH+CE,UAAA,OG7CF,MAAA,QAHF,2BAMI,QAAA,aEnHJ,WCIE,UAAA,KAGA,OAAA,KDDF,eACE,QAAA,OACA,iBAAA,KACA,OAAA,IAAA,MAAA,QEEE,cAAA,ODPF,UAAA,KAGA,OAAA,KDcF,QAEE,QAAA,aAGF,YACE,cAAA,MACA,YAAA,EAGF,gBL8HI,UAAA,IK5HF,MAAA,QGvCF,KRmKI,UAAA,MQjKF,MAAA,QACA,UAAA,WAGA,OACE,MAAA,QAKJ,IACE,QAAA,MAAA,MRsJE,UAAA,MQpJF,MAAA,KACA,iBAAA,QDCE,cAAA,MCLJ,QASI,QAAA,ER8IA,UAAA,KQ5IA,YAAA,IVwMJ,IUjME,QAAA,MRqIE,UAAA,MQnIF,MAAA,QAHF,SRsII,UAAA,QQ9HA,MAAA,QACA,WAAA,OAKJ,gBACE,WAAA,MACA,WAAA,OCxCA,WVwhBF,iBAGA,cADA,cADA,cAGA,cW7hBE,MAAA,KACA,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KCmDE,yBFzCE,WAAA,cACE,UAAA,OEwCJ,yBFzCE,WAAA,cAAA,cACE,UAAA,OEwCJ,yBFzCE,WAAA,cAAA,cAAA,cACE,UAAA,OEwCJ,0BFzCE,WAAA,cAAA,cAAA,cAAA,cACE,UAAA,QA4BN,KCnCA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,MACA,YAAA,MDsCA,YACE,aAAA,EACA,YAAA,EAFF,iBV2hBF,0BUrhBM,cAAA,EACA,aAAA,EGtDJ,KAAA,OAAA,QAAA,QAAA,QAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,ObglBF,UAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFkJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACnG,aAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aanlBI,SAAA,SACA,MAAA,KACA,cAAA,KACA,aAAA,KAsBE,KACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAKE,cFwBN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,UAAA,KEzBM,cFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,cFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEzBM,cFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,cFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,cFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEnBE,UFCJ,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KEGQ,OFbR,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UESQ,OFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,OFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,OFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,OFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,OFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,OFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,OFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,OFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,QFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,QFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,QFbR,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEeI,aAAwB,eAAA,GAAA,MAAA,GAExB,YAAuB,eAAA,GAAA,MAAA,GAGrB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,UAAwB,eAAA,GAAA,MAAA,GAAxB,UAAwB,eAAA,GAAA,MAAA,GAAxB,UAAwB,eAAA,GAAA,MAAA,GAOpB,UFhBV,YAAA,UEgBU,UFhBV,YAAA,WEgBU,UFhBV,YAAA,IEgBU,UFhBV,YAAA,WEgBU,UFhBV,YAAA,WEgBU,UFhBV,YAAA,IEgBU,UFhBV,YAAA,WEgBU,UFhBV,YAAA,WEgBU,UFhBV,YAAA,IEgBU,WFhBV,YAAA,WEgBU,WFhBV,YAAA,WCKE,yBC3BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAKE,iBFwBN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,UAAA,KEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEnBE,aFCJ,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KEGQ,UFbR,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEeI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAOpB,aFhBV,YAAA,EEgBU,aFhBV,YAAA,UEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,cFhBV,YAAA,WEgBU,cFhBV,YAAA,YCKE,yBC3BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAKE,iBFwBN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,UAAA,KEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEnBE,aFCJ,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KEGQ,UFbR,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEeI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAOpB,aFhBV,YAAA,EEgBU,aFhBV,YAAA,UEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,cFhBV,YAAA,WEgBU,cFhBV,YAAA,YCKE,yBC3BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAKE,iBFwBN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,UAAA,KEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEnBE,aFCJ,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KEGQ,UFbR,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEeI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAOpB,aFhBV,YAAA,EEgBU,aFhBV,YAAA,UEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,cFhBV,YAAA,WEgBU,cFhBV,YAAA,YCKE,0BC3BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAKE,iBFwBN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,UAAA,KEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IACA,UAAA,IEzBM,iBFwBN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WACA,UAAA,WEnBE,aFCJ,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KEGQ,UFbR,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,UFbR,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WESQ,WFbR,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEeI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAOpB,aFhBV,YAAA,EEgBU,aFhBV,YAAA,UEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,WEgBU,aFhBV,YAAA,IEgBU,cFhBV,YAAA,WEgBU,cFhBV,YAAA,YGnDF,OACE,MAAA,KACA,cAAA,KACA,MAAA,Qd4nDF,Uc/nDA,UAQI,QAAA,OACA,eAAA,IACA,WAAA,IAAA,MAAA,QAVJ,gBAcI,eAAA,OACA,cAAA,IAAA,MAAA,QAfJ,mBAmBI,WAAA,IAAA,MAAA,Qd4nDJ,acnnDA,aAGI,QAAA,MASJ,gBACE,OAAA,IAAA,MAAA,Qd+mDF,mBchnDA,mBAKI,OAAA,IAAA,MAAA,QdgnDJ,yBcrnDA,yBAWM,oBAAA,IdinDN,8BAFA,qBc1mDA,qBd2mDA,2BctmDI,OAAA,EAQJ,yCAEI,iBAAA,gBX/DF,4BW2EI,MAAA,QACA,iBAAA,iBCnFJ,efkrDF,kBADA,kBe7qDM,iBAAA,QfqrDN,2BAFA,kBevrDE,kBfwrDF,wBe5qDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCf+qDF,qCetqDU,iBAAA,QA5BR,iBfwsDF,oBADA,oBensDM,iBAAA,Qf2sDN,6BAFA,oBe7sDE,oBf8sDF,0BelsDQ,aAAA,QZLN,oCYiBM,iBAAA,QALN,uCfqsDF,uCe5rDU,iBAAA,QA5BR,ef8tDF,kBADA,kBeztDM,iBAAA,QfiuDN,2BAFA,kBenuDE,kBfouDF,wBextDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCf2tDF,qCeltDU,iBAAA,QA5BR,YfovDF,eADA,ee/uDM,iBAAA,QfuvDN,wBAFA,eezvDE,ef0vDF,qBe9uDQ,aAAA,QZLN,+BYiBM,iBAAA,QALN,kCfivDF,kCexuDU,iBAAA,QA5BR,ef0wDF,kBADA,kBerwDM,iBAAA,Qf6wDN,2BAFA,kBe/wDE,kBfgxDF,wBepwDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCfuwDF,qCe9vDU,iBAAA,QA5BR,cfgyDF,iBADA,iBe3xDM,iBAAA,QfmyDN,0BAFA,iBeryDE,iBfsyDF,uBe1xDQ,aAAA,QZLN,iCYiBM,iBAAA,QALN,oCf6xDF,oCepxDU,iBAAA,QA5BR,afszDF,gBADA,gBejzDM,iBAAA,QfyzDN,yBAFA,gBe3zDE,gBf4zDF,sBehzDQ,aAAA,QZLN,gCYiBM,iBAAA,QALN,mCfmzDF,mCe1yDU,iBAAA,QA5BR,Yf40DF,eADA,eev0DM,iBAAA,Qf+0DN,wBAFA,eej1DE,efk1DF,qBet0DQ,aAAA,QZLN,+BYiBM,iBAAA,QALN,kCfy0DF,kCeh0DU,iBAAA,QA5BR,cfk2DF,iBADA,iBe71DM,iBAAA,iBZGJ,iCYiBM,iBAAA,iBALN,oCfw1DF,oCe/0DU,iBAAA,iBD8EV,sBAGM,MAAA,KACA,iBAAA,QACA,aAAA,QALN,uBAWM,MAAA,QACA,iBAAA,QACA,aAAA,QAKN,YACE,MAAA,KACA,iBAAA,QdmwDF,ecrwDA,edswDA,qBc/vDI,aAAA,QAPJ,2BAWI,OAAA,EAXJ,oDAgBM,iBAAA,sBXrIJ,uCW4IM,MAAA,KACA,iBAAA,uBFhFJ,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,6BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GAdV,kBAOQ,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MAVR,kCAcU,OAAA,EE7KV,cACE,QAAA,MACA,MAAA,KACA,OAAA,2BACA,QAAA,QAAA,Of0KI,UAAA,KevKJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,QRAE,cAAA,OSFE,WAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAIA,uCDdN,cCeQ,WAAA,MDfR,0BAsBI,iBAAA,YACA,OAAA,EEhBF,oBACE,MAAA,QACA,iBAAA,KACA,aAAA,QACA,QAAA,EAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBFhBN,yCA+BI,MAAA,QAEA,QAAA,EAjCJ,gCA+BI,MAAA,QAEA,QAAA,EAjCJ,oCA+BI,MAAA,QAEA,QAAA,EAjCJ,qCA+BI,MAAA,QAEA,QAAA,EAjCJ,2BA+BI,MAAA,QAEA,QAAA,EAjCJ,uBAAA,wBA2CI,iBAAA,QAEA,QAAA,EAIJ,8BhB+9DA,wCACA,+BAFA,8BgBz9DI,mBAAA,KAAA,gBAAA,KAAA,WAAA,KAIJ,mCAGI,MAAA,YACA,YAAA,EAAA,EAAA,EAAA,QAJJ,qCAaI,MAAA,QACA,iBAAA,KAKJ,mBhBq9DA,oBgBn9DE,QAAA,MACA,MAAA,KAUF,gBACE,YAAA,oBACA,eAAA,oBACA,cAAA,EfiEE,UAAA,Qe/DF,YAAA,IAGF,mBACE,YAAA,kBACA,eAAA,kBf0EI,UAAA,QexEJ,YAAA,IAGF,mBACE,YAAA,mBACA,eAAA,mBfmEI,UAAA,QejEJ,YAAA,IASF,wBACE,QAAA,MACA,MAAA,KACA,QAAA,QAAA,EACA,cAAA,EfoDI,UAAA,KelDJ,YAAA,IACA,MAAA,QACA,iBAAA,YACA,OAAA,MAAA,YACA,aAAA,IAAA,EAVF,wCAAA,wCAcI,cAAA,EACA,aAAA,EAYJ,iBACE,OAAA,0BACA,QAAA,OAAA,Mf2BI,UAAA,QezBJ,YAAA,IRzIE,cAAA,MQ6IJ,iBACE,OAAA,yBACA,QAAA,MAAA,KfmBI,UAAA,QejBJ,YAAA,IRjJE,cAAA,MQsJJ,8BAAA,0BAGI,OAAA,KAIJ,sBACE,OAAA,KAQF,YACE,cAAA,KAGF,WACE,QAAA,MACA,WAAA,OAQF,UACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,KACA,YAAA,KAJF,ehB07DA,wBgBl7DI,cAAA,IACA,aAAA,IASJ,YACE,SAAA,SACA,QAAA,MACA,aAAA,QAGF,kBACE,SAAA,SACA,WAAA,MACA,YAAA,ShBi7DF,6CgBp7DA,8CAQI,MAAA,QAIJ,kBACE,cAAA,EAGF,mBACE,QAAA,mBAAA,QAAA,YACA,eAAA,OAAA,YAAA,OACA,aAAA,EACA,aAAA,OAJF,qCAQI,SAAA,OACA,WAAA,EACA,aAAA,SACA,YAAA,EE7MF,gBACE,QAAA,KACA,MAAA,KACA,WAAA,OjBqHA,UAAA,OiBnHA,MAAA,QAGF,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,EACA,QAAA,KACA,UAAA,KACA,QAAA,OAAA,MACA,WAAA,MjBwHE,UAAA,QiBtHF,YAAA,IACA,MAAA,KACA,iBAAA,mBV9CA,cAAA,OUmDA,8BlB8nEJ,uCkB5nEM,KAAA,IlBkoEN,0BACA,yBkB1qEI,sClBwqEJ,qCkB1nEM,QAAA,MA9CF,uBAAA,mCAoDE,aAAA,QAGE,cAAA,+BACA,iBAAA,gQACA,kBAAA,UACA,oBAAA,MAAA,wBAAA,OACA,gBAAA,sBAAA,sBA3DJ,6BAAA,yCA+DI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAhEJ,yCAAA,6BAyEI,cAAA,eACA,oBAAA,MAAA,OAAA,OA1EJ,2CAAA,+BAmFI,cAAA,qBACA,oBAAA,IAAA,wBAAA,MAAA,wBApFJ,wBAAA,oCA2FE,aAAA,QAGE,cAAA,kCACA,WAAA,+KAAA,MAAA,OAAA,MAAA,CAAA,IAAA,KAAA,SAAA,CAAA,KAAA,gQAAA,OAAA,MAAA,OAAA,CAAA,sBAAA,sBAAA,UA/FJ,8BAAA,0CAmGI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBApGJ,6CAAA,yDA4GI,MAAA,QlB0mEiD,2CACzD,0CkBvtEI,uDlBstEJ,sDkBrmEQ,QAAA,MAjHJ,qDAAA,iEAyHI,MAAA,QAzHJ,6DAAA,yEA4HM,aAAA,QA5HN,qEAAA,iFAkIM,aAAA,QC5JN,iBAAA,QD0BA,mEAAA,+EAyIM,WAAA,EAAA,EAAA,EAAA,MAAA,oBAzIN,iFAAA,6FA6IM,aAAA,QA7IN,+CAAA,2DAuJI,aAAA,QAvJJ,qDAAA,iEA4JM,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAjJR,kBACE,QAAA,KACA,MAAA,KACA,WAAA,OjBqHA,UAAA,OiBnHA,MAAA,QAGF,iBACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,EACA,QAAA,KACA,UAAA,KACA,QAAA,OAAA,MACA,WAAA,MjBwHE,UAAA,QiBtHF,YAAA,IACA,MAAA,KACA,iBAAA,mBV9CA,cAAA,OUmDA,gClB6uEJ,yCkB3uEM,KAAA,IlBivEN,8BACA,6BkBzxEI,0ClBuxEJ,yCkBzuEM,QAAA,MA9CF,yBAAA,qCAoDE,aAAA,QAGE,cAAA,+BACA,iBAAA,2TACA,kBAAA,UACA,oBAAA,MAAA,wBAAA,OACA,gBAAA,sBAAA,sBA3DJ,+BAAA,2CA+DI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAhEJ,2CAAA,+BAyEI,cAAA,eACA,oBAAA,MAAA,OAAA,OA1EJ,6CAAA,iCAmFI,cAAA,qBACA,oBAAA,IAAA,wBAAA,MAAA,wBApFJ,0BAAA,sCA2FE,aAAA,QAGE,cAAA,kCACA,WAAA,+KAAA,MAAA,OAAA,MAAA,CAAA,IAAA,KAAA,SAAA,CAAA,KAAA,2TAAA,OAAA,MAAA,OAAA,CAAA,sBAAA,sBAAA,UA/FJ,gCAAA,4CAmGI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBApGJ,+CAAA,2DA4GI,MAAA,QlBytEqD,+CAC7D,8CkBt0EI,2DlBq0EJ,0DkBptEQ,QAAA,MAjHJ,uDAAA,mEAyHI,MAAA,QAzHJ,+DAAA,2EA4HM,aAAA,QA5HN,uEAAA,mFAkIM,aAAA,QC5JN,iBAAA,QD0BA,qEAAA,iFAyIM,WAAA,EAAA,EAAA,EAAA,MAAA,oBAzIN,mFAAA,+FA6IM,aAAA,QA7IN,iDAAA,6DAuJI,aAAA,QAvJJ,uDAAA,mEA4JM,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBFqFV,aACE,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OAHF,yBASI,MAAA,KJ/NA,yBIsNJ,mBAeM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,cAAA,EAlBN,yBAuBM,QAAA,YAAA,QAAA,KACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,EA3BN,2BAgCM,QAAA,aACA,MAAA,KACA,eAAA,OAlCN,qCAuCM,QAAA,ahB0nEJ,4BgBjqEF,0BA4CM,MAAA,KA5CN,yBAkDM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,KACA,aAAA,EAtDN,+BAyDM,SAAA,SACA,kBAAA,EAAA,YAAA,EACA,WAAA,EACA,aAAA,OACA,YAAA,EA7DN,6BAiEM,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OAlEN,mCAqEM,cAAA,GIjVN,KACE,QAAA,aAEA,YAAA,IACA,MAAA,QACA,WAAA,OAGA,eAAA,OACA,oBAAA,KAAA,iBAAA,KAAA,gBAAA,KAAA,YAAA,KACA,iBAAA,YACA,OAAA,IAAA,MAAA,YCuFA,QAAA,QAAA,OpB4EI,UAAA,KoB1EJ,YAAA,IbxFE,cAAA,OSFE,WAAA,MAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAIA,uCGdN,KHeQ,WAAA,MdTN,WiBUE,MAAA,QACA,gBAAA,KAjBJ,WAAA,WAsBI,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAvBJ,cAAA,cA6BI,QAAA,IA7BJ,mCAkCI,OAAA,QAcJ,epBy8EA,wBoBv8EE,eAAA,KASA,aC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,sBAAA,sBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrBm/EF,mCqBh/EI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrBg/EJ,yCqB3+EQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDQN,eC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,qBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,qBAAA,qBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAKJ,wBAAA,wBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,oDAAA,oDrBwhFF,qCqBrhFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,0DAAA,0DrBqhFJ,2CqBhhFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDQN,aC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAKJ,sBAAA,sBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrB6jFF,mCqB1jFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrB0jFJ,yCqBrjFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDQN,UC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,gBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,gBAAA,gBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,mBAAA,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,+CAAA,+CrBkmFF,gCqB/lFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,qDAAA,qDrB+lFJ,sCqB1lFQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDQN,aC3DA,MAAA,QFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,QFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAEE,MAAA,QFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,sBAAA,sBAEE,MAAA,QACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrBuoFF,mCqBpoFI,MAAA,QACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrBooFJ,yCqB/nFQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDQN,YC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,kBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,kBAAA,kBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAKJ,qBAAA,qBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,iDAAA,iDrB4qFF,kCqBzqFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,uDAAA,uDrByqFJ,wCqBpqFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDQN,WC3DA,MAAA,QFAE,iBAAA,QEEF,aAAA,QlBIA,iBkBAE,MAAA,QFNA,iBAAA,QEQA,aAAA,QAGF,iBAAA,iBAEE,MAAA,QFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAKJ,oBAAA,oBAEE,MAAA,QACA,iBAAA,QACA,aAAA,QAOF,gDAAA,gDrBitFF,iCqB9sFI,MAAA,QACA,iBAAA,QAIA,aAAA,QAEA,sDAAA,sDrB8sFJ,uCqBzsFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDQN,UC3DA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,gBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,gBAAA,gBAEE,MAAA,KFbA,iBAAA,QEeA,aAAA,QAKE,WAAA,EAAA,EAAA,EAAA,MAAA,kBAKJ,mBAAA,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,+CAAA,+CrBsvFF,gCqBnvFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,qDAAA,qDrBmvFJ,sCqB9uFQ,WAAA,EAAA,EAAA,EAAA,MAAA,kBDcN,qBCPA,MAAA,QACA,aAAA,QlBrDA,2BkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrB4uFF,2CqBzuFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErB4uFJ,iDqBvuFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDzBN,uBCPA,MAAA,QACA,aAAA,QlBrDA,6BkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,6BAAA,6BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAGF,gCAAA,gCAEE,MAAA,QACA,iBAAA,YAGF,4DAAA,4DrB4wFF,6CqBzwFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,kEAAA,kErB4wFJ,mDqBvwFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDzBN,qBCPA,MAAA,QACA,aAAA,QlBrDA,2BkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrB4yFF,2CqBzyFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErB4yFJ,iDqBvyFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDzBN,kBCPA,MAAA,QACA,aAAA,QlBrDA,wBkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,uDAAA,uDrB40FF,wCqBz0FI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,6DAAA,6DrB40FJ,8CqBv0FQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDzBN,qBCPA,MAAA,QACA,aAAA,QlBrDA,2BkBwDE,MAAA,QACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrB42FF,2CqBz2FI,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErB42FJ,iDqBv2FQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDzBN,oBCPA,MAAA,QACA,aAAA,QlBrDA,0BkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,0BAAA,0BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,6BAAA,6BAEE,MAAA,QACA,iBAAA,YAGF,yDAAA,yDrB44FF,0CqBz4FI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,+DAAA,+DrB44FJ,gDqBv4FQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDzBN,mBCPA,MAAA,QACA,aAAA,QlBrDA,yBkBwDE,MAAA,QACA,iBAAA,QACA,aAAA,QAGF,yBAAA,yBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAGF,4BAAA,4BAEE,MAAA,QACA,iBAAA,YAGF,wDAAA,wDrB46FF,yCqBz6FI,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,8DAAA,8DrB46FJ,+CqBv6FQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDzBN,kBCPA,MAAA,QACA,aAAA,QlBrDA,wBkBwDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,kBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,uDAAA,uDrB48FF,wCqBz8FI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,6DAAA,6DrB48FJ,8CqBv8FQ,WAAA,EAAA,EAAA,EAAA,MAAA,kBDdR,UACE,YAAA,IACA,MAAA,QACA,gBAAA,KjBzEA,gBiB4EE,MAAA,QACA,gBAAA,UAPJ,gBAAA,gBAYI,gBAAA,UAZJ,mBAAA,mBAiBI,MAAA,QACA,eAAA,KAWJ,mBAAA,QCPE,QAAA,MAAA,KpB4EI,UAAA,QoB1EJ,YAAA,IbxFE,cAAA,MYiGJ,mBAAA,QCXE,QAAA,OAAA,MpB4EI,UAAA,QoB1EJ,YAAA,IbxFE,cAAA,MY0GJ,WACE,QAAA,MACA,MAAA,KAFF,sBAMI,WAAA,MpBs9FJ,6BADA,4BoBh9FA,6BAII,MAAA,KE3IJ,MLgBM,WAAA,QAAA,KAAA,OAIA,uCKpBN,MLqBQ,WAAA,MKrBR,iBAII,QAAA,EAIJ,qBAEI,QAAA,KAIJ,YACE,SAAA,SACA,OAAA,EACA,SAAA,OLDI,WAAA,OAAA,KAAA,KAIA,uCKNN,YLOQ,WAAA,MKPR,kBAOI,MAAA,EACA,OAAA,KLNE,WAAA,MAAA,KAAA,KAIA,uCKNN,kBLOQ,WAAA,MjBonGR,UACA,UAFA,WuBvoGA,QAIE,SAAA,SAGF,iBACE,YAAA,OCoBE,wBACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAhCJ,WAAA,KAAA,MACA,aAAA,KAAA,MAAA,YACA,cAAA,EACA,YAAA,KAAA,MAAA,YAqDE,8BACE,YAAA,ED1CN,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,MAAA,EACA,OAAA,QAAA,EAAA,EtB2JI,UAAA,KsBzJJ,MAAA,QACA,WAAA,KACA,WAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,gBfdE,cAAA,OeuBA,oBACE,MAAA,KACA,KAAA,EAGF,qBACE,MAAA,EACA,KAAA,KXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,0BWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MAON,uBAEI,IAAA,KACA,OAAA,KACA,WAAA,EACA,cAAA,QC/BA,gCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAzBJ,WAAA,EACA,aAAA,KAAA,MAAA,YACA,cAAA,KAAA,MACA,YAAA,KAAA,MAAA,YA8CE,sCACE,YAAA,EDUN,0BAEI,IAAA,EACA,MAAA,KACA,KAAA,KACA,WAAA,EACA,YAAA,QC7CA,mCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAlBJ,WAAA,KAAA,MAAA,YACA,aAAA,EACA,cAAA,KAAA,MAAA,YACA,YAAA,KAAA,MAuCE,yCACE,YAAA,EA7BF,mCDmDE,eAAA,EAKN,yBAEI,IAAA,EACA,MAAA,KACA,KAAA,KACA,WAAA,EACA,aAAA,QC9DA,kCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAJF,kCAgBI,QAAA,KAGF,mCACE,QAAA,aACA,aAAA,OACA,eAAA,OACA,QAAA,GA9BN,WAAA,KAAA,MAAA,YACA,aAAA,KAAA,MACA,cAAA,KAAA,MAAA,YAiCE,wCACE,YAAA,EAVA,mCDiDA,eAAA,EAON,oCAAA,kCAAA,mCAAA,iCAKI,MAAA,KACA,OAAA,KAKJ,kBE9GE,OAAA,EACA,OAAA,MAAA,EACA,SAAA,OACA,WAAA,IAAA,MAAA,QFkHF,eACE,QAAA,MACA,MAAA,KACA,QAAA,OAAA,OACA,MAAA,KACA,YAAA,IACA,MAAA,QACA,WAAA,QAEA,YAAA,OACA,iBAAA,YACA,OAAA,EpBrHA,qBAAA,qBoBoIE,MAAA,QACA,gBAAA,KJ/IA,iBAAA,QIoHJ,sBAAA,sBAiCI,MAAA,KACA,gBAAA,KJtJA,iBAAA,QIoHJ,wBAAA,wBAwCI,MAAA,QACA,eAAA,KACA,iBAAA,YAQJ,oBACE,QAAA,MAIF,iBACE,QAAA,MACA,QAAA,MAAA,OACA,cAAA,EtBAI,UAAA,QsBEJ,MAAA,QACA,YAAA,OAIF,oBACE,QAAA,MACA,QAAA,OAAA,OACA,MAAA,QG3LF,W1B63GA,oB0B33GE,SAAA,SACA,QAAA,mBAAA,QAAA,YACA,eAAA,O1Bi4GF,yB0Br4GA,gBAOI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,K1Bo4GJ,+BGn4GE,sBuBII,QAAA,E1Bs4GN,gCADA,gCADA,+B0Bj5GA,uBAAA,uBAAA,sBAkBM,QAAA,EAMN,aACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,cAAA,MAAA,gBAAA,WAHF,0BAMI,MAAA,K1Bu4GJ,wC0Bn4GA,kCAII,YAAA,K1Bo4GJ,4C0Bx4GA,uDlBHI,wBAAA,EACA,2BAAA,ERg5GJ,6C0B94GA,kClBWI,uBAAA,EACA,0BAAA,EkBmBJ,uBACE,cAAA,SACA,aAAA,SAFF,8B1B23GA,yCADA,sC0Bn3GI,YAAA,EAGF,yCACE,aAAA,EAIJ,0CAAA,+BACE,cAAA,QACA,aAAA,QAGF,0CAAA,+BACE,cAAA,OACA,aAAA,OAoBF,oBACE,mBAAA,OAAA,eAAA,OACA,eAAA,MAAA,YAAA,WACA,cAAA,OAAA,gBAAA,OAHF,yB1B62GA,+B0Bt2GI,MAAA,K1B22GJ,iD0Bl3GA,2CAYI,WAAA,K1B22GJ,qD0Bv3GA,gElBrEI,2BAAA,EACA,0BAAA,ERi8GJ,sD0B73GA,2ClBnFI,uBAAA,EACA,wBAAA,EkB0HJ,uB1B21GA,kC0Bx1GI,cAAA,E1B61GJ,4C0Bh2GA,yC1Bk2GA,uDADA,oD0B11GM,SAAA,SACA,KAAA,cACA,eAAA,KCzJN,aACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,QAAA,YAAA,QACA,MAAA,K3BigHF,0BADA,4B2BrgHA,2B3BogHA,qC2Bz/GI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,GACA,UAAA,EACA,cAAA,E3B2gHJ,uCADA,yCADA,wCADA,yCADA,2CADA,0CAJA,wCADA,0C2BhhHA,yC3BohHA,kDADA,oDADA,mD2B9/GM,YAAA,K3B4gHN,sEADA,kC2B/hHA,iCA4BI,QAAA,EA5BJ,mDAiCI,QAAA,E3BwgHJ,8C2BziHA,6CnB0CI,uBAAA,EACA,0BAAA,EmB3CJ,0BA4CI,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OA7CJ,8D3BsjHA,qEQ1hHI,wBAAA,EACA,2BAAA,EmB7BJ,+DnB0CI,uBAAA,EACA,0BAAA,ERuhHJ,mFACA,0FAFA,kE2BjkHA,iEnB4BI,wBAAA,EACA,2BAAA,ER6iHJ,gFACA,uFAFA,+D2BzkHA,8DnB4BI,wBAAA,EACA,2BAAA,ERojHJ,oB2BngHA,qBAEE,QAAA,YAAA,QAAA,K3BugHF,yB2BzgHA,0BAQI,SAAA,SACA,QAAA,E3BsgHJ,+B2B/gHA,gCAYM,QAAA,E3B2gHN,8BACA,2CAEA,2CADA,wD2BzhHA,+B3BohHA,4CAEA,4CADA,yD2BjgHI,YAAA,KAIJ,qBAAuB,aAAA,KACvB,oBAAsB,YAAA,KAQtB,kBACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,QAAA,QAAA,OACA,cAAA,E1B2DI,UAAA,K0BzDJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,OACA,YAAA,OACA,iBAAA,QACA,OAAA,IAAA,MAAA,QnB/GE,cAAA,OR2nHJ,uC2BxhHA,oCAkBI,WAAA,E3B2gHJ,+B2BjgHA,4CAEE,OAAA,yB3BogHF,+B2BjgHA,8B3BqgHA,yCAFA,sDACA,0CAFA,uD2B5/GE,QAAA,MAAA,K1BwBI,UAAA,Q0BtBJ,YAAA,InB5IE,cAAA,MRipHJ,+B2BjgHA,4CAEE,OAAA,0B3BogHF,+B2BjgHA,8B3BqgHA,yCAFA,sDACA,0CAFA,uD2B5/GE,QAAA,OAAA,M1BOI,UAAA,Q0BLJ,YAAA,InB7JE,cAAA,MmBiKJ,+B3BigHA,+B2B//GE,cAAA,Q3BugHF,yEACA,sFAHA,4EACA,yFAGA,wFACA,+E2B//GA,uC3By/GA,oDQvpHI,wBAAA,EACA,2BAAA,EmBwKJ,sC3B0/GA,mDAGA,qEACA,kFAHA,yDACA,sEQvpHI,uBAAA,EACA,0BAAA,EoBxCJ,gBACE,SAAA,SACA,QAAA,EACA,QAAA,MACA,WAAA,OACA,aAAA,OACA,2BAAA,MAAA,aAAA,MAAA,mBAAA,MAGF,uBACE,QAAA,mBAAA,QAAA,YACA,aAAA,KAGF,sBACE,SAAA,SACA,KAAA,EACA,QAAA,GACA,MAAA,KACA,OAAA,QACA,QAAA,EANF,4DASI,MAAA,KACA,aAAA,QT3BA,iBAAA,QSiBJ,0DAoBM,WAAA,EAAA,EAAA,EAAA,MAAA,oBApBN,wEAyBI,aAAA,QAzBJ,0EA6BI,MAAA,KACA,iBAAA,QACA,aAAA,QA/BJ,qDAAA,sDAuCM,MAAA,QAvCN,6DAAA,8DA0CQ,iBAAA,QAUR,sBACE,SAAA,SACA,cAAA,EAEA,eAAA,IAJF,8BASI,SAAA,SACA,IAAA,OACA,KAAA,QACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,eAAA,KACA,QAAA,GACA,iBAAA,KACA,OAAA,IAAA,MAAA,QAlBJ,6BAwBI,SAAA,SACA,IAAA,OACA,KAAA,QACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,QAAA,GACA,WAAA,GAAA,CAAA,IAAA,IAAA,UASJ,+CpBjGI,cAAA,OoBiGJ,4EAOM,iBAAA,iNAPN,mFAaM,aAAA,QT1HF,iBAAA,QS6GJ,kFAkBM,iBAAA,8JAlBN,sFT7GI,iBAAA,mBS6GJ,4FT7GI,iBAAA,mBSiJJ,4CAGI,cAAA,IAHJ,yEAQM,iBAAA,6JARN,mFTjJI,iBAAA,mBSyKJ,eACE,aAAA,QADF,6CAKM,KAAA,SACA,MAAA,QACA,eAAA,IAEA,cAAA,MATN,4CAaM,IAAA,mBACA,KAAA,qBACA,MAAA,iBACA,OAAA,iBACA,iBAAA,QAEA,cAAA,MXlLA,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,WAAA,CAAA,kBAAA,KAAA,YAAA,WAAA,UAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAAA,WAAA,UAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,WAAA,CAAA,kBAAA,KAAA,YAIA,uCW2JN,4CX1JQ,WAAA,MW0JR,0EA0BM,iBAAA,KACA,kBAAA,mBAAA,UAAA,mBA3BN,oFTzKI,iBAAA,mBSsNJ,eACE,QAAA,aACA,MAAA,KACA,OAAA,2BACA,QAAA,QAAA,QAAA,QAAA,O3B5CI,UAAA,K2B+CJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,eAAA,OACA,WAAA,KAAA,+KAAA,MAAA,OAAA,MAAA,CAAA,IAAA,KAAA,UACA,OAAA,IAAA,MAAA,QpBtNE,cAAA,OoByNF,mBAAA,KAAA,gBAAA,KAAA,WAAA,KAfF,qBAkBI,aAAA,QACA,QAAA,EAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAxBN,gCAiCM,MAAA,QACA,iBAAA,KAlCN,yBAAA,qCAwCI,OAAA,KACA,cAAA,OACA,iBAAA,KA1CJ,wBA8CI,MAAA,QACA,iBAAA,QA/CJ,2BAoDI,QAAA,KApDJ,8BAyDI,MAAA,YACA,YAAA,EAAA,EAAA,EAAA,QAIJ,kBACE,OAAA,0BACA,YAAA,OACA,eAAA,OACA,aAAA,M3B1GI,UAAA,Q2B8GN,kBACE,OAAA,yBACA,YAAA,MACA,eAAA,MACA,aAAA,K3BlHI,UAAA,Q2B2HN,aACE,SAAA,SACA,QAAA,aACA,MAAA,KACA,OAAA,2BACA,cAAA,EAGF,mBACE,SAAA,SACA,QAAA,EACA,MAAA,KACA,OAAA,2BACA,OAAA,EACA,SAAA,OACA,QAAA,EAPF,4CAUI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oB5BqoHJ,+C4BhpHA,gDAiBI,iBAAA,QAjBJ,sDAsBM,QAAA,SAtBN,0DA2BI,QAAA,kBAIJ,mBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,EACA,OAAA,2BACA,QAAA,QAAA,OACA,SAAA,OAEA,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,QpBlVE,cAAA,OoBoUJ,0BAmBI,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,QAAA,EACA,QAAA,MACA,OAAA,qBACA,QAAA,QAAA,OACA,YAAA,IACA,MAAA,QACA,QAAA,ST7WA,iBAAA,QS+WA,YAAA,QpBnWA,cAAA,EAAA,OAAA,OAAA,EoB8WJ,cACE,MAAA,KACA,OAAA,OACA,QAAA,EACA,iBAAA,YACA,mBAAA,KAAA,gBAAA,KAAA,WAAA,KALF,oBAQI,QAAA,EARJ,0CAY8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAZ9B,sCAa8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAb9B,+BAc8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAd9B,gCAkBI,OAAA,EAlBJ,oCAsBI,MAAA,KACA,OAAA,KACA,WAAA,QTlZA,iBAAA,QSoZA,OAAA,EpBxYA,cAAA,KSFE,mBAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAAA,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YW8YF,mBAAA,KAAA,WAAA,KX1YE,uCW4WN,oCX3WQ,mBAAA,KAAA,WAAA,MW2WR,2CT1XI,iBAAA,QS0XJ,6CAsCI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,QACA,aAAA,YpBzZA,cAAA,KoB8WJ,gCAiDI,MAAA,KACA,OAAA,KT5aA,iBAAA,QS8aA,OAAA,EpBlaA,cAAA,KSFE,gBAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAAA,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YWwaF,gBAAA,KAAA,WAAA,KXpaE,uCW4WN,gCX3WQ,gBAAA,KAAA,WAAA,MW2WR,uCT1XI,iBAAA,QS0XJ,gCAgEI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,QACA,aAAA,YpBnbA,cAAA,KoB8WJ,yBA2EI,MAAA,KACA,OAAA,KACA,WAAA,EACA,aAAA,MACA,YAAA,MTzcA,iBAAA,QS2cA,OAAA,EpB/bA,cAAA,KSFE,eAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAAA,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YWqcF,WAAA,KXjcE,uCW4WN,yBX3WQ,eAAA,KAAA,WAAA,MW2WR,gCT1XI,iBAAA,QS0XJ,yBA6FI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,YACA,aAAA,YACA,aAAA,MAnGJ,8BAwGI,iBAAA,QpBtdA,cAAA,KoB8WJ,8BA6GI,aAAA,KACA,iBAAA,QpB5dA,cAAA,KoB8WJ,6CAoHM,iBAAA,QApHN,sDAwHM,OAAA,QAxHN,yCA4HM,iBAAA,QA5HN,yCAgIM,OAAA,QAhIN,kCAoIM,iBAAA,QAKN,8B5BgpHA,mBACA,eiB1oIM,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAIA,uCWqfN,8B5BupHE,mBACA,eiB5oIM,WAAA,MYhBR,KACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,EACA,cAAA,EACA,WAAA,KAGF,UACE,QAAA,MACA,QAAA,MAAA,K1BCA,gBAAA,gB0BGE,gBAAA,KANJ,mBAWI,MAAA,QACA,eAAA,KACA,OAAA,QAQJ,UACE,cAAA,IAAA,MAAA,QADF,oBAII,cAAA,KACA,iBAAA,YACA,OAAA,IAAA,MAAA,YrBbA,uBAAA,OACA,wBAAA,OLZF,0BAAA,0B0B6BI,UAAA,QACA,aAAA,QAAA,QAAA,QAZN,6BAgBM,MAAA,QACA,iBAAA,YACA,aAAA,Y7BmqIN,mC6BrrIA,2BAwBI,MAAA,QACA,iBAAA,KACA,aAAA,QAAA,QAAA,KA1BJ,yBA+BI,WAAA,KrBtCA,uBAAA,EACA,wBAAA,EqBgDJ,qBAEI,WAAA,IACA,OAAA,ErB7DA,cAAA,OqB0DJ,4B7B8pIA,2B6BrpII,MAAA,KACA,iBAAA,Q7B0pIJ,oB6BjpIA,oBAGI,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,WAAA,O7BopIJ,yB6BhpIA,yBAGI,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,WAAA,OASJ,uBAEI,QAAA,KAFJ,qBAKI,QAAA,MCzGJ,QACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cACA,QAAA,MAAA,KANF,mB9BowIA,yBAAwE,sBAAvB,sBAAvB,sBAAqE,sB8BzvI3F,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cAoBJ,cACE,QAAA,aACA,YAAA,SACA,eAAA,SACA,aAAA,K7B6HI,UAAA,Q6B3HJ,YAAA,QACA,YAAA,O3B1CA,oBAAA,oB2B6CE,gBAAA,KASJ,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,aAAA,EACA,cAAA,EACA,WAAA,KALF,sBAQI,cAAA,EACA,aAAA,EATJ,2BAaI,SAAA,OACA,MAAA,KASJ,aACE,QAAA,aACA,YAAA,MACA,eAAA,MAYF,iBACE,wBAAA,KAAA,WAAA,KACA,kBAAA,EAAA,UAAA,EAGA,eAAA,OAAA,YAAA,OAIF,gBACE,QAAA,OAAA,O7B8DI,UAAA,Q6B5DJ,YAAA,EACA,iBAAA,YACA,OAAA,IAAA,MAAA,YtBxGE,cAAA,OLFF,sBAAA,sB2B8GE,gBAAA,KAMJ,qBACE,QAAA,aACA,MAAA,MACA,OAAA,MACA,eAAA,OACA,QAAA,GACA,WAAA,GAAA,CAAA,KAAA,KAAA,UAGF,mBACE,WAAA,KACA,WAAA,KlBtEE,4BkBgFC,6B9BqtIH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8BltIvI,cAAA,EACA,aAAA,GlBjGN,yBkB6FA,kBAoBI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WArBH,8BAwBK,mBAAA,IAAA,eAAA,IAxBL,6CA2BO,SAAA,SA3BP,wCA+BO,cAAA,MACA,aAAA,MAhCP,6B9B8uIH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8BxsIvI,cAAA,OAAA,UAAA,OAtCL,qCAqDK,SAAA,QArDL,mCAyDK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KA5DL,kCAgEK,QAAA,MlBhJN,4BkBgFC,6B9BkwIH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8B/vIvI,cAAA,EACA,aAAA,GlBjGN,yBkB6FA,kBAoBI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WArBH,8BAwBK,mBAAA,IAAA,eAAA,IAxBL,6CA2BO,SAAA,SA3BP,wCA+BO,cAAA,MACA,aAAA,MAhCP,6B9B2xIH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8BrvIvI,cAAA,OAAA,UAAA,OAtCL,qCAqDK,SAAA,QArDL,mCAyDK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KA5DL,kCAgEK,QAAA,MlBhJN,4BkBgFC,6B9B+yIH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8B5yIvI,cAAA,EACA,aAAA,GlBjGN,yBkB6FA,kBAoBI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WArBH,8BAwBK,mBAAA,IAAA,eAAA,IAxBL,6CA2BO,SAAA,SA3BP,wCA+BO,cAAA,MACA,aAAA,MAhCP,6B9Bw0IH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8BlyIvI,cAAA,OAAA,UAAA,OAtCL,qCAqDK,SAAA,QArDL,mCAyDK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KA5DL,kCAgEK,QAAA,MlBhJN,6BkBgFC,6B9B41IH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8Bz1IvI,cAAA,EACA,aAAA,GlBjGN,0BkB6FA,kBAoBI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WArBH,8BAwBK,mBAAA,IAAA,eAAA,IAxBL,6CA2BO,SAAA,SA3BP,wCA+BO,cAAA,MACA,aAAA,MAhCP,6B9Bq3IH,mCAA4G,gCAAnC,gCAAnC,gCAAyG,gC8B/0IvI,cAAA,OAAA,UAAA,OAtCL,qCAqDK,SAAA,QArDL,mCAyDK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KA5DL,kCAgEK,QAAA,MArEV,eAyBQ,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WA1BR,0B9Bo5IA,gCAAmG,6BAAhC,6BAAhC,6BAAgG,6B8B54IzH,cAAA,EACA,aAAA,EATV,2BA6BU,mBAAA,IAAA,eAAA,IA7BV,0CAgCY,SAAA,SAhCZ,qCAoCY,cAAA,MACA,aAAA,MArCZ,0B9Bw6IA,gCAAmG,6BAAhC,6BAAhC,6BAAgG,6B8B73IzH,cAAA,OAAA,UAAA,OA3CV,kCA0DU,SAAA,QA1DV,gCA8DU,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KAjEV,+BAqEU,QAAA,KAaV,4BAEI,MAAA,e3BxNF,kCAAA,kC2B2NI,MAAA,eALN,oCAWM,MAAA,e3BjOJ,0CAAA,0C2BoOM,MAAA,eAdR,6CAkBQ,MAAA,e9B62IR,4CAEA,2CADA,yC8Bh4IA,0CA0BM,MAAA,eA1BN,8BA+BI,MAAA,eACA,aAAA,eAhCJ,mCAoCI,iBAAA,kQApCJ,2BAwCI,MAAA,eAxCJ,6BA0CM,MAAA,e3BhQJ,mCAAA,mC2BmQM,MAAA,eAOR,2BAEI,MAAA,K3B5QF,iCAAA,iC2B+QI,MAAA,KALN,mCAWM,MAAA,qB3BrRJ,yCAAA,yC2BwRM,MAAA,sBAdR,4CAkBQ,MAAA,sB9By2IR,2CAEA,0CADA,wC8B53IA,yCA0BM,MAAA,KA1BN,6BA+BI,MAAA,qBACA,aAAA,qBAhCJ,kCAoCI,iBAAA,wQApCJ,0BAwCI,MAAA,qBAxCJ,4BA0CM,MAAA,K3BpTJ,kCAAA,kC2BuTM,MAAA,KCnUR,MACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,UAAA,EAEA,UAAA,WACA,iBAAA,KACA,gBAAA,WACA,OAAA,IAAA,MAAA,iBvBKE,cAAA,OuBdJ,SAaI,aAAA,EACA,YAAA,EAdJ,kBAkBI,WAAA,QACA,cAAA,QAnBJ,8BAsBM,iBAAA,EvBCF,uBAAA,mBACA,wBAAA,mBuBxBJ,6BA2BM,oBAAA,EvBUF,2BAAA,mBACA,0BAAA,mBuBtCJ,+B/BitJA,+B+B7qJI,WAAA,EAIJ,WAGE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAGA,WAAA,IACA,QAAA,QAIF,YACE,cAAA,OAGF,eACE,WAAA,SACA,cAAA,EAGF,sBACE,cAAA,E5BrDA,iB4B0DE,gBAAA,KAFJ,sBAMI,YAAA,QAQJ,aACE,QAAA,OAAA,QACA,cAAA,EAEA,iBAAA,gBACA,cAAA,IAAA,MAAA,iBALF,yBvBhEI,cAAA,mBAAA,mBAAA,EAAA,EuB4EJ,aACE,QAAA,OAAA,QAEA,iBAAA,gBACA,WAAA,IAAA,MAAA,iBAJF,wBvB5EI,cAAA,EAAA,EAAA,mBAAA,mBuB4FJ,kBACE,aAAA,SACA,cAAA,QACA,YAAA,SACA,cAAA,EAGF,mBACE,aAAA,SACA,YAAA,SAIF,kBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,QvB/GE,cAAA,mBuBmHJ,U/B6pJA,iBADA,c+BzpJE,kBAAA,EAAA,YAAA,EACA,MAAA,KAGF,U/B6pJA,cQ9wJI,uBAAA,mBACA,wBAAA,mBuBqHJ,U/B8pJA,iBQtwJI,2BAAA,mBACA,0BAAA,mBuB+GJ,iBAEI,cAAA,KnB/FA,yBmB6FJ,WAMI,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,aAAA,MACA,YAAA,MATJ,iBAaM,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GACA,aAAA,KACA,cAAA,EACA,YAAA,MAUN,kBAII,cAAA,KnB3HA,yBmBuHJ,YAQI,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KATJ,kBAcM,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GACA,cAAA,EAfN,wBAkBQ,YAAA,EACA,YAAA,EAnBR,mCvBjJI,wBAAA,EACA,2BAAA,ERg0JF,gD+BhrJF,iDA8BY,wBAAA,E/BspJV,gD+BprJF,oDAmCY,2BAAA,EAnCZ,oCvBnII,uBAAA,EACA,0BAAA,ER8zJF,iD+B5rJF,kDA6CY,uBAAA,E/BmpJV,iD+BhsJF,qDAkDY,0BAAA,GAaZ,oBAEI,cAAA,OnBxLA,yBmBsLJ,cAMI,qBAAA,EAAA,kBAAA,EAAA,aAAA,EACA,mBAAA,QAAA,gBAAA,QAAA,WAAA,QACA,QAAA,EACA,OAAA,EATJ,oBAYM,QAAA,aACA,MAAA,MAUN,WACE,gBAAA,KADF,iBAII,SAAA,OAJJ,oCAOM,cAAA,EvBvOF,2BAAA,EACA,0BAAA,EuB+NJ,qCvB9OI,uBAAA,EACA,wBAAA,EuB6OJ,8BvBvPI,cAAA,EuBwQE,cAAA,KC1RN,YACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,QAAA,OAAA,KACA,cAAA,KAEA,WAAA,KACA,iBAAA,QxBWE,cAAA,OwBPJ,kCAGI,aAAA,MAHJ,0CAMM,MAAA,KACA,cAAA,MACA,MAAA,QACA,QAAA,IATN,gDAoBI,gBAAA,UApBJ,gDAwBI,gBAAA,KAxBJ,wBA4BI,MAAA,QCvCJ,YACE,QAAA,YAAA,QAAA,K5BGA,aAAA,EACA,WAAA,KGaE,cAAA,OyBZJ,WACE,SAAA,SACA,QAAA,MACA,QAAA,MAAA,OACA,YAAA,KACA,YAAA,KACA,MAAA,QAEA,iBAAA,KACA,OAAA,IAAA,MAAA,QATF,iBAYI,QAAA,EACA,MAAA,QACA,gBAAA,KACA,iBAAA,QACA,aAAA,QAhBJ,iBAoBI,QAAA,EACA,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAIJ,kCAGM,YAAA,EzBaF,uBAAA,OACA,0BAAA,OyBjBJ,iCzBEI,wBAAA,OACA,2BAAA,OyBHJ,6BAcI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QAjBJ,+BAqBI,MAAA,QACA,eAAA,KAEA,OAAA,KACA,iBAAA,KACA,aAAA,QCvDF,0BACE,QAAA,OAAA,OjCgLE,UAAA,QiC9KF,YAAA,IAKE,iD1BqCF,uBAAA,MACA,0BAAA,M0BjCE,gD1BkBF,wBAAA,MACA,2BAAA,M0BhCF,0BACE,QAAA,OAAA,MjCgLE,UAAA,QiC9KF,YAAA,IAKE,iD1BqCF,uBAAA,MACA,0BAAA,M0BjCE,gD1BkBF,wBAAA,MACA,2BAAA,M2B9BJ,OACE,QAAA,aACA,QAAA,MAAA,KlC6JE,UAAA,IkC3JF,YAAA,IACA,YAAA,EACA,WAAA,OACA,YAAA,OACA,eAAA,S3BKE,cAAA,OSFE,WAAA,MAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAIA,uCkBfN,OlBgBQ,WAAA,MdLN,cAAA,cgCGI,gBAAA,KAdN,aAoBI,QAAA,KAKJ,YACE,SAAA,SACA,IAAA,KAOF,YACE,cAAA,KACA,aAAA,K3BvBE,cAAA,M2BgCF,eCjDA,MAAA,KACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,KACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,iBCjDA,MAAA,KACA,iBAAA,QjCcA,wBAAA,wBiCVI,MAAA,KACA,iBAAA,QAHI,wBAAA,wBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,qBDqCJ,eCjDA,MAAA,KACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,KACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,YCjDA,MAAA,KACA,iBAAA,QjCcA,mBAAA,mBiCVI,MAAA,KACA,iBAAA,QAHI,mBAAA,mBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBDqCJ,eCjDA,MAAA,QACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,QACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,cCjDA,MAAA,KACA,iBAAA,QjCcA,qBAAA,qBiCVI,MAAA,KACA,iBAAA,QAHI,qBAAA,qBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,aCjDA,MAAA,QACA,iBAAA,QjCcA,oBAAA,oBiCVI,MAAA,QACA,iBAAA,QAHI,oBAAA,oBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,qBDqCJ,YCjDA,MAAA,KACA,iBAAA,QjCcA,mBAAA,mBiCVI,MAAA,KACA,iBAAA,QAHI,mBAAA,mBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,kBCbN,WACE,QAAA,KAAA,KACA,cAAA,KAEA,iBAAA,Q7BcE,cAAA,MI0CA,yByB5DJ,WAQI,QAAA,KAAA,MAIJ,iBACE,cAAA,EACA,aAAA,E7BIE,cAAA,E8BdJ,OACE,SAAA,SACA,QAAA,OAAA,QACA,cAAA,KACA,OAAA,IAAA,MAAA,Y9BUE,cAAA,O8BLJ,eAEE,MAAA,QAIF,YACE,YAAA,IAQF,mBACE,cAAA,KADF,0BAKI,SAAA,SACA,IAAA,EACA,MAAA,EACA,QAAA,EACA,QAAA,OAAA,QACA,MAAA,QAUF,eC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDsCF,iBC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,oBACE,iBAAA,QAGF,6BACE,MAAA,QDsCF,eC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDsCF,YC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QDsCF,eC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDsCF,cC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,iBACE,iBAAA,QAGF,0BACE,MAAA,QDsCF,aC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,gBACE,iBAAA,QAGF,yBACE,MAAA,QDsCF,YC/CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QCRF,wCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAFP,gCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAIT,UACE,QAAA,YAAA,QAAA,KACA,OAAA,KACA,SAAA,OACA,YAAA,EvCwKI,UAAA,OuCtKJ,iBAAA,QhCIE,cAAA,OgCCJ,cACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,cAAA,OAAA,gBAAA,OACA,SAAA,OACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,iBAAA,QvBXI,WAAA,MAAA,IAAA,KAIA,uCuBDN,cvBEQ,WAAA,MuBUR,sBrBYE,iBAAA,iKqBVA,gBAAA,KAAA,KAIA,uBACE,kBAAA,GAAA,OAAA,SAAA,qBAAA,UAAA,GAAA,OAAA,SAAA,qBAGE,uCAJJ,uBAKM,kBAAA,KAAA,UAAA,MC1CR,OACE,QAAA,YAAA,QAAA,KACA,eAAA,MAAA,YAAA,WAGF,YACE,SAAA,EAAA,KAAA,ECFF,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAGA,aAAA,EACA,cAAA,ElCQE,cAAA,OkCEJ,wBACE,MAAA,KACA,MAAA,QACA,WAAA,QvCPA,8BAAA,8BuCWE,QAAA,EACA,MAAA,QACA,gBAAA,KACA,iBAAA,QAVJ,+BAcI,MAAA,QACA,iBAAA,QASJ,iBACE,SAAA,SACA,QAAA,MACA,QAAA,OAAA,QAGA,iBAAA,KACA,OAAA,IAAA,MAAA,iBAPF,6BlCjBI,uBAAA,QACA,wBAAA,QkCgBJ,4BlCHI,2BAAA,QACA,0BAAA,QkCEJ,0BAAA,0BAmBI,MAAA,QACA,eAAA,KACA,iBAAA,KArBJ,wBA0BI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QA7BJ,kCAiCI,iBAAA,EAjCJ,yCAoCM,WAAA,KACA,iBAAA,IAcF,uBACE,mBAAA,IAAA,eAAA,IADF,oDlCtBA,0BAAA,OAZA,wBAAA,EkCkCA,mDlClCA,wBAAA,OAYA,0BAAA,EkCsBA,+CAeM,WAAA,EAfN,yDAmBM,iBAAA,IACA,kBAAA,EApBN,gEAuBQ,YAAA,KACA,kBAAA,I9B3DR,yB8BmCA,0BACE,mBAAA,IAAA,eAAA,IADF,uDlCtBA,0BAAA,OAZA,wBAAA,EkCkCA,sDlClCA,wBAAA,OAYA,0BAAA,EkCsBA,kDAeM,WAAA,EAfN,4DAmBM,iBAAA,IACA,kBAAA,EApBN,mEAuBQ,YAAA,KACA,kBAAA,K9B3DR,yB8BmCA,0BACE,mBAAA,IAAA,eAAA,IADF,uDlCtBA,0BAAA,OAZA,wBAAA,EkCkCA,sDlClCA,wBAAA,OAYA,0BAAA,EkCsBA,kDAeM,WAAA,EAfN,4DAmBM,iBAAA,IACA,kBAAA,EApBN,mEAuBQ,YAAA,KACA,kBAAA,K9B3DR,yB8BmCA,0BACE,mBAAA,IAAA,eAAA,IADF,uDlCtBA,0BAAA,OAZA,wBAAA,EkCkCA,sDlClCA,wBAAA,OAYA,0BAAA,EkCsBA,kDAeM,WAAA,EAfN,4DAmBM,iBAAA,IACA,kBAAA,EApBN,mEAuBQ,YAAA,KACA,kBAAA,K9B3DR,0B8BmCA,0BACE,mBAAA,IAAA,eAAA,IADF,uDlCtBA,0BAAA,OAZA,wBAAA,EkCkCA,sDlClCA,wBAAA,OAYA,0BAAA,EkCsBA,kDAeM,WAAA,EAfN,4DAmBM,iBAAA,IACA,kBAAA,EApBN,mEAuBQ,YAAA,KACA,kBAAA,KAcZ,kBlCnHI,cAAA,EkCmHJ,mCAII,aAAA,EAAA,EAAA,IAJJ,8CAOM,oBAAA,ECzIJ,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,2BACE,MAAA,QACA,iBAAA,QxCWF,wDAAA,wDwCPM,MAAA,QACA,iBAAA,QAPN,yDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,sBACE,MAAA,QACA,iBAAA,QxCWF,mDAAA,mDwCPM,MAAA,QACA,iBAAA,QAPN,oDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,wBACE,MAAA,QACA,iBAAA,QxCWF,qDAAA,qDwCPM,MAAA,QACA,iBAAA,QAPN,sDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,uBACE,MAAA,QACA,iBAAA,QxCWF,oDAAA,oDwCPM,MAAA,QACA,iBAAA,QAPN,qDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,sBACE,MAAA,QACA,iBAAA,QxCWF,mDAAA,mDwCPM,MAAA,QACA,iBAAA,QAPN,oDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QChBR,OACE,MAAA,M3CmLI,UAAA,O2CjLJ,YAAA,IACA,YAAA,EACA,MAAA,KACA,YAAA,EAAA,IAAA,EAAA,KACA,QAAA,GzCKA,ayCDE,MAAA,KACA,gBAAA,KzCIF,2CAAA,2CyCCI,QAAA,IAWN,aACE,QAAA,EACA,iBAAA,YACA,OAAA,EAMF,iBACE,eAAA,KCtCF,OAGE,wBAAA,MAAA,WAAA,MACA,UAAA,M5CgLI,UAAA,Q4C7KJ,iBAAA,sBACA,gBAAA,YACA,OAAA,IAAA,MAAA,eACA,WAAA,EAAA,OAAA,OAAA,eACA,QAAA,ErCOE,cAAA,OqClBJ,wBAeI,cAAA,OAfJ,eAmBI,QAAA,EAnBJ,YAuBI,QAAA,MACA,QAAA,EAxBJ,YA4BI,QAAA,KAIJ,cACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,QAAA,OAAA,OACA,MAAA,QACA,iBAAA,sBACA,gBAAA,YACA,cAAA,IAAA,MAAA,gBrCZE,uBAAA,mBACA,wBAAA,mBqCeJ,YACE,QAAA,OCtCF,YAEE,SAAA,OAFF,mBAKI,WAAA,OACA,WAAA,KAKJ,OACE,SAAA,MACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,OAAA,KACA,SAAA,OAGA,QAAA,EAOF,cACE,SAAA,SACA,MAAA,KACA,OAAA,MAEA,eAAA,KAGA,0B7B3BI,WAAA,kBAAA,IAAA,SAAA,WAAA,UAAA,IAAA,SAAA,WAAA,UAAA,IAAA,QAAA,CAAA,kBAAA,IAAA,S6B6BF,kBAAA,mBAAA,UAAA,mB7BzBE,uC6BuBJ,0B7BtBM,WAAA,M6B0BN,0BACE,kBAAA,KAAA,UAAA,KAIF,kCACE,kBAAA,YAAA,UAAA,YAIJ,yBACE,QAAA,YAAA,QAAA,KACA,WAAA,kBAFF,wCAKI,WAAA,mBACA,SAAA,O9Cm1LJ,uC8Cz1LA,uCAWI,kBAAA,EAAA,YAAA,EAXJ,qCAeI,WAAA,KAIJ,uBACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,WAAA,kBAHF,+BAOI,QAAA,MACA,OAAA,mBACA,OAAA,oBAAA,OAAA,iBAAA,OAAA,YACA,QAAA,GAVJ,+CAeI,mBAAA,OAAA,eAAA,OACA,cAAA,OAAA,gBAAA,OACA,OAAA,KAjBJ,8DAoBM,WAAA,KApBN,uDAwBM,QAAA,KAMN,eACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,MAAA,KAGA,eAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,etClGE,cAAA,MsCsGF,QAAA,EAIF,gBACE,SAAA,MACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,MAAA,MACA,OAAA,MACA,iBAAA,KAPF,qBAUW,QAAA,EAVX,qBAWW,QAAA,GAKX,cACE,QAAA,YAAA,QAAA,KACA,eAAA,MAAA,YAAA,WACA,cAAA,QAAA,gBAAA,cACA,QAAA,KAAA,KACA,cAAA,IAAA,MAAA,QtCtHE,uBAAA,kBACA,wBAAA,kBsCgHJ,qBASI,QAAA,KAAA,KAEA,OAAA,MAAA,MAAA,MAAA,KAKJ,aACE,cAAA,EACA,YAAA,IAKF,YACE,SAAA,SAGA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,QAAA,KAIF,cACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,IAAA,gBAAA,SACA,QAAA,OACA,WAAA,IAAA,MAAA,QtCzIE,2BAAA,kBACA,0BAAA,kBsCkIJ,gBAaI,OAAA,OAKJ,yBACE,SAAA,SACA,IAAA,QACA,MAAA,KACA,OAAA,KACA,SAAA,OlCvIE,yBkCzBJ,cAuKI,UAAA,MACA,OAAA,QAAA,KAlJJ,yBAsJI,WAAA,oBAtJJ,wCAyJM,WAAA,qBAtIN,uBA2II,WAAA,oBA3IJ,+BA8IM,OAAA,qBACA,OAAA,oBAAA,OAAA,iBAAA,OAAA,YAQJ,UAAY,UAAA,OlCvKV,yBkC2KF,U9C00LA,U8Cx0LE,UAAA,OlC7KA,0BkCkLF,UAAY,UAAA,QC7Od,SACE,SAAA,SACA,QAAA,KACA,QAAA,MACA,OAAA,ECJA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,YAAA,OACA,aAAA,OACA,WAAA,K/CqKI,UAAA,Q8CzKJ,UAAA,WACA,QAAA,EAXF,cAaW,QAAA,GAbX,gBAgBI,SAAA,SACA,QAAA,MACA,MAAA,MACA,OAAA,MAnBJ,wBAsBM,SAAA,SACA,QAAA,GACA,aAAA,YACA,aAAA,MAKN,mCAAA,gBACE,QAAA,MAAA,EADF,0CAAA,uBAII,OAAA,EAJJ,kDAAA,+BAOM,IAAA,EACA,aAAA,MAAA,MAAA,EACA,iBAAA,KAKN,qCAAA,kBACE,QAAA,EAAA,MADF,4CAAA,yBAII,KAAA,EACA,MAAA,MACA,OAAA,MANJ,oDAAA,iCASM,MAAA,EACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,KAKN,sCAAA,mBACE,QAAA,MAAA,EADF,6CAAA,0BAII,IAAA,EAJJ,qDAAA,kCAOM,OAAA,EACA,aAAA,EAAA,MAAA,MACA,oBAAA,KAKN,oCAAA,iBACE,QAAA,EAAA,MADF,2CAAA,wBAII,MAAA,EACA,MAAA,MACA,OAAA,MANJ,mDAAA,gCASM,KAAA,EACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,KAqBN,eACE,UAAA,MACA,QAAA,OAAA,MACA,MAAA,KACA,WAAA,OACA,iBAAA,KvC9FE,cAAA,OyClBJ,SACE,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,MACA,UAAA,MDLA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,YAAA,OACA,aAAA,OACA,WAAA,K/CqKI,UAAA,QgDxKJ,UAAA,WACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,ezCGE,cAAA,MyClBJ,gBAoBI,SAAA,SACA,QAAA,MACA,MAAA,KACA,OAAA,MACA,OAAA,EAAA,MAxBJ,uBAAA,wBA4BM,SAAA,SACA,QAAA,MACA,QAAA,GACA,aAAA,YACA,aAAA,MAKN,mCAAA,gBACE,cAAA,MADF,0CAAA,uBAII,OAAA,mBAJJ,kDAAA,+BAOM,OAAA,EACA,aAAA,MAAA,MAAA,EACA,iBAAA,gBATN,iDAAA,8BAaM,OAAA,IACA,aAAA,MAAA,MAAA,EACA,iBAAA,KAKN,qCAAA,kBACE,YAAA,MADF,4CAAA,yBAII,KAAA,mBACA,MAAA,MACA,OAAA,KACA,OAAA,MAAA,EAPJ,oDAAA,iCAUM,KAAA,EACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,gBAZN,mDAAA,gCAgBM,KAAA,IACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,KAKN,sCAAA,mBACE,WAAA,MADF,6CAAA,0BAII,IAAA,mBAJJ,qDAAA,kCAOM,IAAA,EACA,aAAA,EAAA,MAAA,MAAA,MACA,oBAAA,gBATN,oDAAA,iCAaM,IAAA,IACA,aAAA,EAAA,MAAA,MAAA,MACA,oBAAA,KAfN,8DAAA,2CAqBI,SAAA,SACA,IAAA,EACA,KAAA,IACA,QAAA,MACA,MAAA,KACA,YAAA,OACA,QAAA,GACA,cAAA,IAAA,MAAA,QAIJ,oCAAA,iBACE,aAAA,MADF,2CAAA,wBAII,MAAA,mBACA,MAAA,MACA,OAAA,KACA,OAAA,MAAA,EAPJ,mDAAA,gCAUM,MAAA,EACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,gBAZN,kDAAA,+BAgBM,MAAA,IACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,KAsBN,gBACE,QAAA,MAAA,OACA,cAAA,EhD0BI,UAAA,KgDvBJ,iBAAA,QACA,cAAA,IAAA,MAAA,QzCnIE,uBAAA,kBACA,wBAAA,kByC4HJ,sBAUI,QAAA,KAIJ,cACE,QAAA,MAAA,OACA,MAAA,QC3JF,UACE,SAAA,SAGF,wBACE,iBAAA,MAAA,aAAA,MAGF,gBACE,SAAA,SACA,MAAA,KACA,SAAA,OCvBA,uBACE,QAAA,MACA,MAAA,KACA,QAAA,GDwBJ,eACE,SAAA,SACA,QAAA,KACA,MAAA,KACA,MAAA,KACA,aAAA,MACA,4BAAA,OAAA,oBAAA,OjClBI,WAAA,kBAAA,IAAA,YAAA,WAAA,UAAA,IAAA,YAAA,WAAA,UAAA,IAAA,WAAA,CAAA,kBAAA,IAAA,YAIA,uCiCQN,ejCPQ,WAAA,MjBg2MR,oBACA,oBkDh1MA,sBAGE,QAAA,MlDk1MF,4BkD/0MA,6CAEE,kBAAA,iBAAA,UAAA,iBlDm1MF,2BkDh1MA,8CAEE,kBAAA,kBAAA,UAAA,kBAQF,8BAEI,QAAA,EACA,oBAAA,QACA,kBAAA,KAAA,UAAA,KlD+0MJ,sDACA,uDkDp1MA,qCAUI,QAAA,EACA,QAAA,EAXJ,0ClD01MA,2CkD10MI,QAAA,EACA,QAAA,EjC5DE,WAAA,QAAA,GAAA,IAIA,uCiCuCN,0ClDk2ME,2CiBx4MM,WAAA,MjB84MR,uBkD70MA,uBAEE,SAAA,SACA,IAAA,EACA,OAAA,EACA,QAAA,EAEA,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,IACA,QAAA,EACA,MAAA,KACA,WAAA,OACA,WAAA,IACA,OAAA,EACA,QAAA,GjCtFI,WAAA,QAAA,KAAA,KAIA,uCjBs6MJ,uBkDp2MF,uBjCjEQ,WAAA,MjB46MR,6BADA,6BGh7ME,6BAAA,6B+C2FE,MAAA,KACA,gBAAA,KACA,QAAA,EACA,QAAA,GAGJ,uBACE,KAAA,EAKF,uBACE,MAAA,ElDy1MF,4BkDl1MA,4BAEE,QAAA,aACA,MAAA,KACA,OAAA,KACA,WAAA,GAAA,CAAA,KAAA,KAAA,UAEF,4BACE,iBAAA,qMAEF,4BACE,iBAAA,sMASF,qBACE,SAAA,SACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,GACA,QAAA,YAAA,QAAA,KACA,cAAA,OAAA,gBAAA,OACA,aAAA,EAEA,aAAA,IACA,YAAA,IACA,WAAA,KAZF,wBAeI,WAAA,YACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,OAAA,IACA,aAAA,IACA,YAAA,IACA,YAAA,OACA,OAAA,QACA,iBAAA,KACA,gBAAA,YAEA,WAAA,KAAA,MAAA,YACA,cAAA,KAAA,MAAA,YACA,QAAA,GjC/JE,WAAA,QAAA,IAAA,KAIA,uCiC+HN,wBjC9HQ,WAAA,MiC8HR,6BAiCI,QAAA,EASJ,kBACE,SAAA,SACA,MAAA,IACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,YAAA,KACA,eAAA,KACA,MAAA,KACA,WAAA,OElMF,kCACE,GAAK,kBAAA,eAAA,UAAA,gBADP,0BACE,GAAK,kBAAA,eAAA,UAAA,gBAGP,gBACE,QAAA,aACA,MAAA,KACA,OAAA,KACA,eAAA,QACA,OAAA,MAAA,MAAA,aACA,mBAAA,YAEA,cAAA,IACA,kBAAA,KAAA,OAAA,SAAA,eAAA,UAAA,KAAA,OAAA,SAAA,eAGF,mBACE,MAAA,KACA,OAAA,KACA,aAAA,KAOF,gCACE,GACE,kBAAA,SAAA,UAAA,SAEF,IACE,QAAA,EACA,kBAAA,KAAA,UAAA,MANJ,wBACE,GACE,kBAAA,SAAA,UAAA,SAEF,IACE,QAAA,EACA,kBAAA,KAAA,UAAA,MAIJ,cACE,QAAA,aACA,MAAA,KACA,OAAA,KACA,eAAA,QACA,iBAAA,aAEA,cAAA,IACA,QAAA,EACA,kBAAA,KAAA,OAAA,SAAA,aAAA,UAAA,KAAA,OAAA,SAAA,aAGF,iBACE,MAAA,KACA,OAAA,KAIA,uCACE,gBpDwiNF,coDtiNI,2BAAA,KAAA,mBAAA,MC3DN,gBAAqB,eAAA,mBACrB,WAAqB,eAAA,cACrB,cAAqB,eAAA,iBACrB,cAAqB,eAAA,iBACrB,mBAAqB,eAAA,sBACrB,gBAAqB,eAAA,mBCFnB,YACE,iBAAA,kBnDUF,mBAAA,mBHunNF,wBADA,wBsD3nNM,iBAAA,kBANJ,cACE,iBAAA,kBnDUF,qBAAA,qBHioNF,0BADA,0BsDroNM,iBAAA,kBANJ,YACE,iBAAA,kBnDUF,mBAAA,mBH2oNF,wBADA,wBsD/oNM,iBAAA,kBANJ,SACE,iBAAA,kBnDUF,gBAAA,gBHqpNF,qBADA,qBsDzpNM,iBAAA,kBANJ,YACE,iBAAA,kBnDUF,mBAAA,mBH+pNF,wBADA,wBsDnqNM,iBAAA,kBANJ,WACE,iBAAA,kBnDUF,kBAAA,kBHyqNF,uBADA,uBsD7qNM,iBAAA,kBANJ,UACE,iBAAA,kBnDUF,iBAAA,iBHmrNF,sBADA,sBsDvrNM,iBAAA,kBANJ,SACE,iBAAA,kBnDUF,gBAAA,gBH6rNF,qBADA,qBsDjsNM,iBAAA,kBCCN,UACE,iBAAA,eAGF,gBACE,iBAAA,sBCXF,QAAkB,OAAA,IAAA,MAAA,kBAClB,YAAkB,WAAA,IAAA,MAAA,kBAClB,cAAkB,aAAA,IAAA,MAAA,kBAClB,eAAkB,cAAA,IAAA,MAAA,kBAClB,aAAkB,YAAA,IAAA,MAAA,kBAElB,UAAmB,OAAA,YACnB,cAAmB,WAAA,YACnB,gBAAmB,aAAA,YACnB,iBAAmB,cAAA,YACnB,eAAmB,YAAA,YAGjB,gBACE,aAAA,kBADF,kBACE,aAAA,kBADF,gBACE,aAAA,kBADF,aACE,aAAA,kBADF,gBACE,aAAA,kBADF,eACE,aAAA,kBADF,cACE,aAAA,kBADF,aACE,aAAA,kBAIJ,cACE,aAAA,eAOF,YACE,cAAA,gBAGF,SACE,cAAA,iBAGF,aACE,uBAAA,iBACA,wBAAA,iBAGF,eACE,wBAAA,iBACA,2BAAA,iBAGF,gBACE,2BAAA,iBACA,0BAAA,iBAGF,cACE,uBAAA,iBACA,0BAAA,iBAGF,YACE,cAAA,gBAGF,gBACE,cAAA,cAGF,cACE,cAAA,gBAGF,WACE,cAAA,YLxEA,iBACE,QAAA,MACA,MAAA,KACA,QAAA,GMOE,QAAwB,QAAA,eAAxB,UAAwB,QAAA,iBAAxB,gBAAwB,QAAA,uBAAxB,SAAwB,QAAA,gBAAxB,SAAwB,QAAA,gBAAxB,aAAwB,QAAA,oBAAxB,cAAwB,QAAA,qBAAxB,QAAwB,QAAA,sBAAA,QAAA,eAAxB,eAAwB,QAAA,6BAAA,QAAA,sB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,0B6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uBAU9B,aAEI,cAAqB,QAAA,eAArB,gBAAqB,QAAA,iBAArB,sBAAqB,QAAA,uBAArB,eAAqB,QAAA,gBAArB,eAAqB,QAAA,gBAArB,mBAAqB,QAAA,oBAArB,oBAAqB,QAAA,qBAArB,cAAqB,QAAA,sBAAA,QAAA,eAArB,qBAAqB,QAAA,6BAAA,QAAA,uBCrBzB,kBACE,SAAA,SACA,QAAA,MACA,MAAA,KACA,QAAA,EACA,SAAA,OALF,0BAQI,QAAA,MACA,QAAA,GATJ,yC1D0iOA,wBADA,yBAEA,yBACA,wB0D3hOI,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,KACA,OAAA,KACA,OAAA,EAQF,gCAEI,YAAA,WAFJ,gCAEI,YAAA,OAFJ,+BAEI,YAAA,IAFJ,+BAEI,YAAA,KCzBF,UAAgC,mBAAA,cAAA,eAAA,cAChC,aAAgC,mBAAA,iBAAA,eAAA,iBAChC,kBAAgC,mBAAA,sBAAA,eAAA,sBAChC,qBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,WAA8B,cAAA,eAAA,UAAA,eAC9B,aAA8B,cAAA,iBAAA,UAAA,iBAC9B,mBAA8B,cAAA,uBAAA,UAAA,uBAC9B,WAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,aAA8B,kBAAA,YAAA,UAAA,YAC9B,aAA8B,kBAAA,YAAA,UAAA,YAC9B,eAA8B,kBAAA,YAAA,YAAA,YAC9B,eAA8B,kBAAA,YAAA,YAAA,YAE9B,uBAAoC,cAAA,gBAAA,gBAAA,qBACpC,qBAAoC,cAAA,cAAA,gBAAA,mBACpC,wBAAoC,cAAA,iBAAA,gBAAA,iBACpC,yBAAoC,cAAA,kBAAA,gBAAA,wBACpC,wBAAoC,cAAA,qBAAA,gBAAA,uBAEpC,mBAAiC,eAAA,gBAAA,YAAA,qBACjC,iBAAiC,eAAA,cAAA,YAAA,mBACjC,oBAAiC,eAAA,iBAAA,YAAA,iBACjC,sBAAiC,eAAA,mBAAA,YAAA,mBACjC,qBAAiC,eAAA,kBAAA,YAAA,kBAEjC,qBAAkC,mBAAA,gBAAA,cAAA,qBAClC,mBAAkC,mBAAA,cAAA,cAAA,mBAClC,sBAAkC,mBAAA,iBAAA,cAAA,iBAClC,uBAAkC,mBAAA,kBAAA,cAAA,wBAClC,sBAAkC,mBAAA,qBAAA,cAAA,uBAClC,uBAAkC,mBAAA,kBAAA,cAAA,kBAElC,iBAAgC,oBAAA,eAAA,WAAA,eAChC,kBAAgC,oBAAA,gBAAA,WAAA,qBAChC,gBAAgC,oBAAA,cAAA,WAAA,mBAChC,mBAAgC,oBAAA,iBAAA,WAAA,iBAChC,qBAAgC,oBAAA,mBAAA,WAAA,mBAChC,oBAAgC,oBAAA,kBAAA,WAAA,kB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,0B+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mBC1ChC,YAAwB,MAAA,eACxB,aAAwB,MAAA,gBACxB,YAAwB,MAAA,ehDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,0BgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBCL1B,iBAAyB,oBAAA,cAAA,iBAAA,cAAA,YAAA,cAAzB,kBAAyB,oBAAA,eAAA,iBAAA,eAAA,gBAAA,eAAA,YAAA,eAAzB,kBAAyB,oBAAA,eAAA,iBAAA,eAAA,gBAAA,eAAA,YAAA,eCAzB,eAAsB,SAAA,eAAtB,iBAAsB,SAAA,iBCCtB,iBAAyB,SAAA,iBAAzB,mBAAyB,SAAA,mBAAzB,mBAAyB,SAAA,mBAAzB,gBAAyB,SAAA,gBAAzB,iBAAyB,SAAA,yBAAA,SAAA,iBAK3B,WACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,KAGF,cACE,SAAA,MACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KAI4B,2DAD9B,YAEI,SAAA,eAAA,SAAA,OACA,IAAA,EACA,QAAA,MCzBJ,SCEE,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EACA,OAAA,KACA,SAAA,OACA,KAAA,cACA,YAAA,OACA,OAAA,EAUA,0BAAA,yBAEE,SAAA,OACA,MAAA,KACA,OAAA,KACA,SAAA,QACA,KAAA,KACA,YAAA,OC7BJ,WAAa,WAAA,EAAA,QAAA,OAAA,2BACb,QAAU,WAAA,EAAA,MAAA,KAAA,0BACV,WAAa,WAAA,EAAA,KAAA,KAAA,2BACb,aAAe,WAAA,eCCX,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,OAAuB,MAAA,eAAvB,QAAuB,MAAA,eAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,OAAuB,OAAA,eAAvB,QAAuB,OAAA,eAI3B,QAAU,UAAA,eACV,QAAU,WAAA,eAIV,YAAc,UAAA,gBACd,YAAc,WAAA,gBAEd,QAAU,MAAA,gBACV,QAAU,OAAA,gBCTF,KAAgC,OAAA,YAChC,MpEmgQR,MoEjgQU,WAAA,YAEF,MpEogQR,MoElgQU,aAAA,YAEF,MpEqgQR,MoEngQU,cAAA,YAEF,MpEsgQR,MoEpgQU,YAAA,YAfF,KAAgC,OAAA,iBAChC,MpE2hQR,MoEzhQU,WAAA,iBAEF,MpE4hQR,MoE1hQU,aAAA,iBAEF,MpE6hQR,MoE3hQU,cAAA,iBAEF,MpE8hQR,MoE5hQU,YAAA,iBAfF,KAAgC,OAAA,gBAChC,MpEmjQR,MoEjjQU,WAAA,gBAEF,MpEojQR,MoEljQU,aAAA,gBAEF,MpEqjQR,MoEnjQU,cAAA,gBAEF,MpEsjQR,MoEpjQU,YAAA,gBAfF,KAAgC,OAAA,eAChC,MpE2kQR,MoEzkQU,WAAA,eAEF,MpE4kQR,MoE1kQU,aAAA,eAEF,MpE6kQR,MoE3kQU,cAAA,eAEF,MpE8kQR,MoE5kQU,YAAA,eAfF,KAAgC,OAAA,iBAChC,MpEmmQR,MoEjmQU,WAAA,iBAEF,MpEomQR,MoElmQU,aAAA,iBAEF,MpEqmQR,MoEnmQU,cAAA,iBAEF,MpEsmQR,MoEpmQU,YAAA,iBAfF,KAAgC,OAAA,eAChC,MpE2nQR,MoEznQU,WAAA,eAEF,MpE4nQR,MoE1nQU,aAAA,eAEF,MpE6nQR,MoE3nQU,cAAA,eAEF,MpE8nQR,MoE5nQU,YAAA,eAfF,KAAgC,QAAA,YAChC,MpEmpQR,MoEjpQU,YAAA,YAEF,MpEopQR,MoElpQU,cAAA,YAEF,MpEqpQR,MoEnpQU,eAAA,YAEF,MpEspQR,MoEppQU,aAAA,YAfF,KAAgC,QAAA,iBAChC,MpE2qQR,MoEzqQU,YAAA,iBAEF,MpE4qQR,MoE1qQU,cAAA,iBAEF,MpE6qQR,MoE3qQU,eAAA,iBAEF,MpE8qQR,MoE5qQU,aAAA,iBAfF,KAAgC,QAAA,gBAChC,MpEmsQR,MoEjsQU,YAAA,gBAEF,MpEosQR,MoElsQU,cAAA,gBAEF,MpEqsQR,MoEnsQU,eAAA,gBAEF,MpEssQR,MoEpsQU,aAAA,gBAfF,KAAgC,QAAA,eAChC,MpE2tQR,MoEztQU,YAAA,eAEF,MpE4tQR,MoE1tQU,cAAA,eAEF,MpE6tQR,MoE3tQU,eAAA,eAEF,MpE8tQR,MoE5tQU,aAAA,eAfF,KAAgC,QAAA,iBAChC,MpEmvQR,MoEjvQU,YAAA,iBAEF,MpEovQR,MoElvQU,cAAA,iBAEF,MpEqvQR,MoEnvQU,eAAA,iBAEF,MpEsvQR,MoEpvQU,aAAA,iBAfF,KAAgC,QAAA,eAChC,MpE2wQR,MoEzwQU,YAAA,eAEF,MpE4wQR,MoE1wQU,cAAA,eAEF,MpE6wQR,MoE3wQU,eAAA,eAEF,MpE8wQR,MoE5wQU,aAAA,eAQF,MAAwB,OAAA,kBACxB,OpE4wQR,OoE1wQU,WAAA,kBAEF,OpE6wQR,OoE3wQU,aAAA,kBAEF,OpE8wQR,OoE5wQU,cAAA,kBAEF,OpE+wQR,OoE7wQU,YAAA,kBAfF,MAAwB,OAAA,iBACxB,OpEoyQR,OoElyQU,WAAA,iBAEF,OpEqyQR,OoEnyQU,aAAA,iBAEF,OpEsyQR,OoEpyQU,cAAA,iBAEF,OpEuyQR,OoEryQU,YAAA,iBAfF,MAAwB,OAAA,gBACxB,OpE4zQR,OoE1zQU,WAAA,gBAEF,OpE6zQR,OoE3zQU,aAAA,gBAEF,OpE8zQR,OoE5zQU,cAAA,gBAEF,OpE+zQR,OoE7zQU,YAAA,gBAfF,MAAwB,OAAA,kBACxB,OpEo1QR,OoEl1QU,WAAA,kBAEF,OpEq1QR,OoEn1QU,aAAA,kBAEF,OpEs1QR,OoEp1QU,cAAA,kBAEF,OpEu1QR,OoEr1QU,YAAA,kBAfF,MAAwB,OAAA,gBACxB,OpE42QR,OoE12QU,WAAA,gBAEF,OpE62QR,OoE32QU,aAAA,gBAEF,OpE82QR,OoE52QU,cAAA,gBAEF,OpE+2QR,OoE72QU,YAAA,gBAMN,QAAmB,OAAA,eACnB,SpE+2QJ,SoE72QM,WAAA,eAEF,SpEg3QJ,SoE92QM,aAAA,eAEF,SpEi3QJ,SoE/2QM,cAAA,eAEF,SpEk3QJ,SoEh3QM,YAAA,exDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpEm7QN,SoEj7QQ,WAAA,YAEF,SpEm7QN,SoEj7QQ,aAAA,YAEF,SpEm7QN,SoEj7QQ,cAAA,YAEF,SpEm7QN,SoEj7QQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEs8QN,SoEp8QQ,WAAA,iBAEF,SpEs8QN,SoEp8QQ,aAAA,iBAEF,SpEs8QN,SoEp8QQ,cAAA,iBAEF,SpEs8QN,SoEp8QQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpEy9QN,SoEv9QQ,WAAA,gBAEF,SpEy9QN,SoEv9QQ,aAAA,gBAEF,SpEy9QN,SoEv9QQ,cAAA,gBAEF,SpEy9QN,SoEv9QQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpE4+QN,SoE1+QQ,WAAA,eAEF,SpE4+QN,SoE1+QQ,aAAA,eAEF,SpE4+QN,SoE1+QQ,cAAA,eAEF,SpE4+QN,SoE1+QQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpE+/QN,SoE7/QQ,WAAA,iBAEF,SpE+/QN,SoE7/QQ,aAAA,iBAEF,SpE+/QN,SoE7/QQ,cAAA,iBAEF,SpE+/QN,SoE7/QQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpEkhRN,SoEhhRQ,WAAA,eAEF,SpEkhRN,SoEhhRQ,aAAA,eAEF,SpEkhRN,SoEhhRQ,cAAA,eAEF,SpEkhRN,SoEhhRQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEqiRN,SoEniRQ,YAAA,YAEF,SpEqiRN,SoEniRQ,cAAA,YAEF,SpEqiRN,SoEniRQ,eAAA,YAEF,SpEqiRN,SoEniRQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpEwjRN,SoEtjRQ,YAAA,iBAEF,SpEwjRN,SoEtjRQ,cAAA,iBAEF,SpEwjRN,SoEtjRQ,eAAA,iBAEF,SpEwjRN,SoEtjRQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpE2kRN,SoEzkRQ,YAAA,gBAEF,SpE2kRN,SoEzkRQ,cAAA,gBAEF,SpE2kRN,SoEzkRQ,eAAA,gBAEF,SpE2kRN,SoEzkRQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpE8lRN,SoE5lRQ,YAAA,eAEF,SpE8lRN,SoE5lRQ,cAAA,eAEF,SpE8lRN,SoE5lRQ,eAAA,eAEF,SpE8lRN,SoE5lRQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpEinRN,SoE/mRQ,YAAA,iBAEF,SpEinRN,SoE/mRQ,cAAA,iBAEF,SpEinRN,SoE/mRQ,eAAA,iBAEF,SpEinRN,SoE/mRQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEooRN,SoEloRQ,YAAA,eAEF,SpEooRN,SoEloRQ,cAAA,eAEF,SpEooRN,SoEloRQ,eAAA,eAEF,SpEooRN,SoEloRQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpEgoRN,UoE9nRQ,WAAA,kBAEF,UpEgoRN,UoE9nRQ,aAAA,kBAEF,UpEgoRN,UoE9nRQ,cAAA,kBAEF,UpEgoRN,UoE9nRQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpEmpRN,UoEjpRQ,WAAA,iBAEF,UpEmpRN,UoEjpRQ,aAAA,iBAEF,UpEmpRN,UoEjpRQ,cAAA,iBAEF,UpEmpRN,UoEjpRQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEsqRN,UoEpqRQ,WAAA,gBAEF,UpEsqRN,UoEpqRQ,aAAA,gBAEF,UpEsqRN,UoEpqRQ,cAAA,gBAEF,UpEsqRN,UoEpqRQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpEyrRN,UoEvrRQ,WAAA,kBAEF,UpEyrRN,UoEvrRQ,aAAA,kBAEF,UpEyrRN,UoEvrRQ,cAAA,kBAEF,UpEyrRN,UoEvrRQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpE4sRN,UoE1sRQ,WAAA,gBAEF,UpE4sRN,UoE1sRQ,aAAA,gBAEF,UpE4sRN,UoE1sRQ,cAAA,gBAEF,UpE4sRN,UoE1sRQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpE0sRF,YoExsRI,WAAA,eAEF,YpE0sRF,YoExsRI,aAAA,eAEF,YpE0sRF,YoExsRI,cAAA,eAEF,YpE0sRF,YoExsRI,YAAA,gBxDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpE4wRN,SoE1wRQ,WAAA,YAEF,SpE4wRN,SoE1wRQ,aAAA,YAEF,SpE4wRN,SoE1wRQ,cAAA,YAEF,SpE4wRN,SoE1wRQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpE+xRN,SoE7xRQ,WAAA,iBAEF,SpE+xRN,SoE7xRQ,aAAA,iBAEF,SpE+xRN,SoE7xRQ,cAAA,iBAEF,SpE+xRN,SoE7xRQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpEkzRN,SoEhzRQ,WAAA,gBAEF,SpEkzRN,SoEhzRQ,aAAA,gBAEF,SpEkzRN,SoEhzRQ,cAAA,gBAEF,SpEkzRN,SoEhzRQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpEq0RN,SoEn0RQ,WAAA,eAEF,SpEq0RN,SoEn0RQ,aAAA,eAEF,SpEq0RN,SoEn0RQ,cAAA,eAEF,SpEq0RN,SoEn0RQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpEw1RN,SoEt1RQ,WAAA,iBAEF,SpEw1RN,SoEt1RQ,aAAA,iBAEF,SpEw1RN,SoEt1RQ,cAAA,iBAEF,SpEw1RN,SoEt1RQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpE22RN,SoEz2RQ,WAAA,eAEF,SpE22RN,SoEz2RQ,aAAA,eAEF,SpE22RN,SoEz2RQ,cAAA,eAEF,SpE22RN,SoEz2RQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpE83RN,SoE53RQ,YAAA,YAEF,SpE83RN,SoE53RQ,cAAA,YAEF,SpE83RN,SoE53RQ,eAAA,YAEF,SpE83RN,SoE53RQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpEi5RN,SoE/4RQ,YAAA,iBAEF,SpEi5RN,SoE/4RQ,cAAA,iBAEF,SpEi5RN,SoE/4RQ,eAAA,iBAEF,SpEi5RN,SoE/4RQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpEo6RN,SoEl6RQ,YAAA,gBAEF,SpEo6RN,SoEl6RQ,cAAA,gBAEF,SpEo6RN,SoEl6RQ,eAAA,gBAEF,SpEo6RN,SoEl6RQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpEu7RN,SoEr7RQ,YAAA,eAEF,SpEu7RN,SoEr7RQ,cAAA,eAEF,SpEu7RN,SoEr7RQ,eAAA,eAEF,SpEu7RN,SoEr7RQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpE08RN,SoEx8RQ,YAAA,iBAEF,SpE08RN,SoEx8RQ,cAAA,iBAEF,SpE08RN,SoEx8RQ,eAAA,iBAEF,SpE08RN,SoEx8RQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpE69RN,SoE39RQ,YAAA,eAEF,SpE69RN,SoE39RQ,cAAA,eAEF,SpE69RN,SoE39RQ,eAAA,eAEF,SpE69RN,SoE39RQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpEy9RN,UoEv9RQ,WAAA,kBAEF,UpEy9RN,UoEv9RQ,aAAA,kBAEF,UpEy9RN,UoEv9RQ,cAAA,kBAEF,UpEy9RN,UoEv9RQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpE4+RN,UoE1+RQ,WAAA,iBAEF,UpE4+RN,UoE1+RQ,aAAA,iBAEF,UpE4+RN,UoE1+RQ,cAAA,iBAEF,UpE4+RN,UoE1+RQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpE+/RN,UoE7/RQ,WAAA,gBAEF,UpE+/RN,UoE7/RQ,aAAA,gBAEF,UpE+/RN,UoE7/RQ,cAAA,gBAEF,UpE+/RN,UoE7/RQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpEkhSN,UoEhhSQ,WAAA,kBAEF,UpEkhSN,UoEhhSQ,aAAA,kBAEF,UpEkhSN,UoEhhSQ,cAAA,kBAEF,UpEkhSN,UoEhhSQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpEqiSN,UoEniSQ,WAAA,gBAEF,UpEqiSN,UoEniSQ,aAAA,gBAEF,UpEqiSN,UoEniSQ,cAAA,gBAEF,UpEqiSN,UoEniSQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpEmiSF,YoEjiSI,WAAA,eAEF,YpEmiSF,YoEjiSI,aAAA,eAEF,YpEmiSF,YoEjiSI,cAAA,eAEF,YpEmiSF,YoEjiSI,YAAA,gBxDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpEqmSN,SoEnmSQ,WAAA,YAEF,SpEqmSN,SoEnmSQ,aAAA,YAEF,SpEqmSN,SoEnmSQ,cAAA,YAEF,SpEqmSN,SoEnmSQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEwnSN,SoEtnSQ,WAAA,iBAEF,SpEwnSN,SoEtnSQ,aAAA,iBAEF,SpEwnSN,SoEtnSQ,cAAA,iBAEF,SpEwnSN,SoEtnSQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpE2oSN,SoEzoSQ,WAAA,gBAEF,SpE2oSN,SoEzoSQ,aAAA,gBAEF,SpE2oSN,SoEzoSQ,cAAA,gBAEF,SpE2oSN,SoEzoSQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpE8pSN,SoE5pSQ,WAAA,eAEF,SpE8pSN,SoE5pSQ,aAAA,eAEF,SpE8pSN,SoE5pSQ,cAAA,eAEF,SpE8pSN,SoE5pSQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpEirSN,SoE/qSQ,WAAA,iBAEF,SpEirSN,SoE/qSQ,aAAA,iBAEF,SpEirSN,SoE/qSQ,cAAA,iBAEF,SpEirSN,SoE/qSQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpEosSN,SoElsSQ,WAAA,eAEF,SpEosSN,SoElsSQ,aAAA,eAEF,SpEosSN,SoElsSQ,cAAA,eAEF,SpEosSN,SoElsSQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEutSN,SoErtSQ,YAAA,YAEF,SpEutSN,SoErtSQ,cAAA,YAEF,SpEutSN,SoErtSQ,eAAA,YAEF,SpEutSN,SoErtSQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpE0uSN,SoExuSQ,YAAA,iBAEF,SpE0uSN,SoExuSQ,cAAA,iBAEF,SpE0uSN,SoExuSQ,eAAA,iBAEF,SpE0uSN,SoExuSQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpE6vSN,SoE3vSQ,YAAA,gBAEF,SpE6vSN,SoE3vSQ,cAAA,gBAEF,SpE6vSN,SoE3vSQ,eAAA,gBAEF,SpE6vSN,SoE3vSQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpEgxSN,SoE9wSQ,YAAA,eAEF,SpEgxSN,SoE9wSQ,cAAA,eAEF,SpEgxSN,SoE9wSQ,eAAA,eAEF,SpEgxSN,SoE9wSQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpEmySN,SoEjySQ,YAAA,iBAEF,SpEmySN,SoEjySQ,cAAA,iBAEF,SpEmySN,SoEjySQ,eAAA,iBAEF,SpEmySN,SoEjySQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEszSN,SoEpzSQ,YAAA,eAEF,SpEszSN,SoEpzSQ,cAAA,eAEF,SpEszSN,SoEpzSQ,eAAA,eAEF,SpEszSN,SoEpzSQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpEkzSN,UoEhzSQ,WAAA,kBAEF,UpEkzSN,UoEhzSQ,aAAA,kBAEF,UpEkzSN,UoEhzSQ,cAAA,kBAEF,UpEkzSN,UoEhzSQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpEq0SN,UoEn0SQ,WAAA,iBAEF,UpEq0SN,UoEn0SQ,aAAA,iBAEF,UpEq0SN,UoEn0SQ,cAAA,iBAEF,UpEq0SN,UoEn0SQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEw1SN,UoEt1SQ,WAAA,gBAEF,UpEw1SN,UoEt1SQ,aAAA,gBAEF,UpEw1SN,UoEt1SQ,cAAA,gBAEF,UpEw1SN,UoEt1SQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpE22SN,UoEz2SQ,WAAA,kBAEF,UpE22SN,UoEz2SQ,aAAA,kBAEF,UpE22SN,UoEz2SQ,cAAA,kBAEF,UpE22SN,UoEz2SQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpE83SN,UoE53SQ,WAAA,gBAEF,UpE83SN,UoE53SQ,aAAA,gBAEF,UpE83SN,UoE53SQ,cAAA,gBAEF,UpE83SN,UoE53SQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpE43SF,YoE13SI,WAAA,eAEF,YpE43SF,YoE13SI,aAAA,eAEF,YpE43SF,YoE13SI,cAAA,eAEF,YpE43SF,YoE13SI,YAAA,gBxDTF,0BwDlDI,QAAgC,OAAA,YAChC,SpE87SN,SoE57SQ,WAAA,YAEF,SpE87SN,SoE57SQ,aAAA,YAEF,SpE87SN,SoE57SQ,cAAA,YAEF,SpE87SN,SoE57SQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEi9SN,SoE/8SQ,WAAA,iBAEF,SpEi9SN,SoE/8SQ,aAAA,iBAEF,SpEi9SN,SoE/8SQ,cAAA,iBAEF,SpEi9SN,SoE/8SQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpEo+SN,SoEl+SQ,WAAA,gBAEF,SpEo+SN,SoEl+SQ,aAAA,gBAEF,SpEo+SN,SoEl+SQ,cAAA,gBAEF,SpEo+SN,SoEl+SQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpEu/SN,SoEr/SQ,WAAA,eAEF,SpEu/SN,SoEr/SQ,aAAA,eAEF,SpEu/SN,SoEr/SQ,cAAA,eAEF,SpEu/SN,SoEr/SQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpE0gTN,SoExgTQ,WAAA,iBAEF,SpE0gTN,SoExgTQ,aAAA,iBAEF,SpE0gTN,SoExgTQ,cAAA,iBAEF,SpE0gTN,SoExgTQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpE6hTN,SoE3hTQ,WAAA,eAEF,SpE6hTN,SoE3hTQ,aAAA,eAEF,SpE6hTN,SoE3hTQ,cAAA,eAEF,SpE6hTN,SoE3hTQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEgjTN,SoE9iTQ,YAAA,YAEF,SpEgjTN,SoE9iTQ,cAAA,YAEF,SpEgjTN,SoE9iTQ,eAAA,YAEF,SpEgjTN,SoE9iTQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpEmkTN,SoEjkTQ,YAAA,iBAEF,SpEmkTN,SoEjkTQ,cAAA,iBAEF,SpEmkTN,SoEjkTQ,eAAA,iBAEF,SpEmkTN,SoEjkTQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpEslTN,SoEplTQ,YAAA,gBAEF,SpEslTN,SoEplTQ,cAAA,gBAEF,SpEslTN,SoEplTQ,eAAA,gBAEF,SpEslTN,SoEplTQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpEymTN,SoEvmTQ,YAAA,eAEF,SpEymTN,SoEvmTQ,cAAA,eAEF,SpEymTN,SoEvmTQ,eAAA,eAEF,SpEymTN,SoEvmTQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpE4nTN,SoE1nTQ,YAAA,iBAEF,SpE4nTN,SoE1nTQ,cAAA,iBAEF,SpE4nTN,SoE1nTQ,eAAA,iBAEF,SpE4nTN,SoE1nTQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpE+oTN,SoE7oTQ,YAAA,eAEF,SpE+oTN,SoE7oTQ,cAAA,eAEF,SpE+oTN,SoE7oTQ,eAAA,eAEF,SpE+oTN,SoE7oTQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpE2oTN,UoEzoTQ,WAAA,kBAEF,UpE2oTN,UoEzoTQ,aAAA,kBAEF,UpE2oTN,UoEzoTQ,cAAA,kBAEF,UpE2oTN,UoEzoTQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpE8pTN,UoE5pTQ,WAAA,iBAEF,UpE8pTN,UoE5pTQ,aAAA,iBAEF,UpE8pTN,UoE5pTQ,cAAA,iBAEF,UpE8pTN,UoE5pTQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEirTN,UoE/qTQ,WAAA,gBAEF,UpEirTN,UoE/qTQ,aAAA,gBAEF,UpEirTN,UoE/qTQ,cAAA,gBAEF,UpEirTN,UoE/qTQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpEosTN,UoElsTQ,WAAA,kBAEF,UpEosTN,UoElsTQ,aAAA,kBAEF,UpEosTN,UoElsTQ,cAAA,kBAEF,UpEosTN,UoElsTQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpEutTN,UoErtTQ,WAAA,gBAEF,UpEutTN,UoErtTQ,aAAA,gBAEF,UpEutTN,UoErtTQ,cAAA,gBAEF,UpEutTN,UoErtTQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpEqtTF,YoEntTI,WAAA,eAEF,YpEqtTF,YoEntTI,aAAA,eAEF,YpEqtTF,YoEntTI,cAAA,eAEF,YpEqtTF,YoEntTI,YAAA,gBCjEN,uBAEI,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,EAEA,eAAA,KACA,QAAA,GAEA,iBAAA,cCVJ,gBAAkB,YAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,oBAIlB,cAAiB,WAAA,kBACjB,WAAiB,YAAA,iBACjB,aAAiB,YAAA,iBACjB,eCTE,SAAA,OACA,cAAA,SACA,YAAA,ODeE,WAAwB,WAAA,eACxB,YAAwB,WAAA,gBACxB,aAAwB,WAAA,iB1DqCxB,yB0DvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kB1DqCxB,yB0DvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kB1DqCxB,yB0DvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kB1DqCxB,0B0DvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBAM5B,gBAAmB,eAAA,oBACnB,gBAAmB,eAAA,oBACnB,iBAAmB,eAAA,qBAInB,mBAAuB,YAAA,cACvB,qBAAuB,YAAA,kBACvB,oBAAuB,YAAA,cACvB,kBAAuB,YAAA,cACvB,oBAAuB,YAAA,iBACvB,aAAuB,WAAA,iBAIvB,YAAc,MAAA,eEvCZ,cACE,MAAA,kBrEUF,qBAAA,qBqELM,MAAA,kBANN,gBACE,MAAA,kBrEUF,uBAAA,uBqELM,MAAA,kBANN,cACE,MAAA,kBrEUF,qBAAA,qBqELM,MAAA,kBANN,WACE,MAAA,kBrEUF,kBAAA,kBqELM,MAAA,kBANN,cACE,MAAA,kBrEUF,qBAAA,qBqELM,MAAA,kBANN,aACE,MAAA,kBrEUF,oBAAA,oBqELM,MAAA,kBANN,YACE,MAAA,kBrEUF,mBAAA,mBqELM,MAAA,kBANN,WACE,MAAA,kBrEUF,kBAAA,kBqELM,MAAA,kBFuCR,WAAa,MAAA,kBACb,YAAc,MAAA,kBAEd,eAAiB,MAAA,yBACjB,eAAiB,MAAA,+BAIjB,WGvDE,KAAA,CAAA,CAAA,EAAA,EACA,MAAA,YACA,YAAA,KACA,iBAAA,YACA,OAAA,EHuDF,sBAAwB,gBAAA,eAExB,YACE,WAAA,qBACA,UAAA,qBAKF,YAAc,MAAA,kBIjEd,SACE,WAAA,kBAGF,WACE,WAAA,iBCAA,a5EOF,ECigUE,QADA,S2EjgUI,YAAA,eAEA,WAAA,eAGF,YAEI,gBAAA,UASJ,mBACE,QAAA,KAAA,YAAA,I5E8LN,I4E/KM,YAAA,mB3Eg/TJ,W2E9+TE,IAEE,OAAA,IAAA,MAAA,QACA,kBAAA,M3Eg/TJ,I2E7+TE,GAEE,kBAAA,M3E++TJ,GACA,G2E7+TE,EAGE,QAAA,EACA,OAAA,EAGF,G3E2+TF,G2Ez+TI,iBAAA,MAQF,MACE,KAAA,G5EnCN,K4EsCM,UAAA,gBAEF,WACE,UAAA,gB7CrEN,Q6C0EM,QAAA,KxCtFN,OwCyFM,OAAA,IAAA,MAAA,K7D1FN,O6D8FM,gBAAA,mBADF,U3Eq+TF,U2Eh+TM,iBAAA,e3Eo+TN,mBc9hUF,mB6DiEQ,OAAA,IAAA,MAAA,kB7DoBR,Y6DfM,MAAA,Q3Ei+TJ,wBAFA,ee5kUA,ef6kUA,qB2E19TM,aAAA,Q7DTR,sB6DcM,MAAA,QACA,aAAA","sourcesContent":["/*!\n * Bootstrap v4.6.2 (https://getbootstrap.com/)\n * Copyright 2011-2022 The Bootstrap Authors\n * Copyright 2011-2022 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"root\";\n@import \"reboot\";\n@import \"type\";\n@import \"images\";\n@import \"code\";\n@import \"grid\";\n@import \"tables\";\n@import \"forms\";\n@import \"buttons\";\n@import \"transitions\";\n@import \"dropdown\";\n@import \"button-group\";\n@import \"input-group\";\n@import \"custom-forms\";\n@import \"nav\";\n@import \"navbar\";\n@import \"card\";\n@import \"breadcrumb\";\n@import \"pagination\";\n@import \"badge\";\n@import \"jumbotron\";\n@import \"alert\";\n@import \"progress\";\n@import \"media\";\n@import \"list-group\";\n@import \"close\";\n@import \"toasts\";\n@import \"modal\";\n@import \"tooltip\";\n@import \"popover\";\n@import \"carousel\";\n@import \"spinners\";\n@import \"utilities\";\n@import \"print\";\n",":root {\n // Custom variable values only support SassScript inside `#{}`.\n @each $color, $value in $colors {\n --#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$color}: #{$value};\n }\n\n @each $bp, $value in $grid-breakpoints {\n --breakpoint-#{$bp}: #{$value};\n }\n\n // Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --font-family-sans-serif: #{inspect($font-family-sans-serif)};\n --font-family-monospace: #{inspect($font-family-monospace)};\n}\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -webkit-tap-highlight-color: rgba($black, 0); // 5\n}\n\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\n// TODO: remove in v5\n// stylelint-disable-next-line selector-list-comma-newline-after\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use\n// the `inherit` value on things like `` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n @include font-size($font-size-base);\n font-weight: $font-weight-base;\n line-height: $line-height-base;\n color: $body-color;\n text-align: left; // 3\n background-color: $body-bg; // 2\n}\n\n// Future-proof rule: in browsers that support :focus-visible, suppress the focus outline\n// on elements that programmatically receive focus but wouldn't normally show a visible\n// focus outline. In general, this would mean that the outline is only applied if the\n// interaction that led to the element receiving programmatic focus was a keyboard interaction,\n// or the browser has somehow determined that the user is primarily a keyboard user and/or\n// wants focus outlines to always be presented.\n//\n// See https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible\n// and https://developer.paciellogroup.com/blog/2018/03/focus-visible-and-backwards-compatibility/\n[tabindex=\"-1\"]:focus:not(:focus-visible) {\n outline: 0 !important;\n}\n\n\n// Content grouping\n//\n// 1. Add the correct box sizing in Firefox.\n// 2. Show the overflow in Edge and IE.\n\nhr {\n box-sizing: content-box; // 1\n height: 0; // 1\n overflow: visible; // 2\n}\n\n\n//\n// Typography\n//\n\n// Remove top margins from headings\n//\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n// stylelint-disable-next-line selector-list-comma-newline-after\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: $headings-margin-bottom;\n}\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Remove the bottom border in Firefox 39-.\n// 5. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-original-title] { // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n border-bottom: 0; // 4\n text-decoration-skip-ink: none; // 5\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // Undo browser default\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: $font-weight-bolder; // Add the correct font weight in Chrome, Edge, and Safari\n}\n\nsmall {\n @include font-size(80%); // Add the correct font size in all browsers\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n position: relative;\n @include font-size(75%);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n//\n// Links\n//\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n background-color: transparent; // Remove the gray background on active links in IE 10.\n\n @include hover() {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n color: inherit;\n text-decoration: none;\n\n @include hover() {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n//\n// Code\n//\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-monospace;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\npre {\n // Remove browser default top margin\n margin-top: 0;\n // Reset browser default of `1em` to use `rem`s\n margin-bottom: 1rem;\n // Don't allow content to break outside\n overflow: auto;\n // Disable auto-hiding scrollbar in IE & legacy Edge to avoid overlap,\n // making it impossible to interact with the content\n -ms-overflow-style: scrollbar;\n}\n\n\n//\n// Figures\n//\n\nfigure {\n // Apply a consistent margin strategy (matches our type styles).\n margin: 0 0 1rem;\n}\n\n\n//\n// Images and content\n//\n\nimg {\n vertical-align: middle;\n border-style: none; // Remove the border on images inside links in IE 10-.\n}\n\nsvg {\n // Workaround for the SVG overflow bug in IE10/11 is still required.\n // See https://github.com/twbs/bootstrap/issues/26878\n overflow: hidden;\n vertical-align: middle;\n}\n\n\n//\n// Tables\n//\n\ntable {\n border-collapse: collapse; // Prevent double borders\n}\n\ncaption {\n padding-top: $table-cell-padding;\n padding-bottom: $table-cell-padding;\n color: $table-caption-color;\n text-align: left;\n caption-side: bottom;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\n\n//\n// Forms\n//\n\nlabel {\n // Allow labels to use `margin` for spacing.\n display: inline-block;\n margin-bottom: $label-margin-bottom;\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n//\n// Details at https://github.com/twbs/bootstrap/issues/24093\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // Remove the margin in Firefox and Safari\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible; // Show the overflow in Edge\n}\n\nbutton,\nselect {\n text-transform: none; // Remove the inheritance of text transform in Firefox\n}\n\n// Set the cursor for non-` - -

- - - - - -
- -
-
- - - - -
- -
- -
-

2020

-

an archive of posts from this year

-
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 2020 | Andrew M. Zhang

2020

an archive of posts from this year

\ No newline at end of file diff --git a/blog/2020/osc-52-patch-for-vte-0425/index.html b/blog/2020/osc-52-patch-for-vte-0425/index.html index 35a9c5c..14727a3 100644 --- a/blog/2020/osc-52-patch-for-vte-0425/index.html +++ b/blog/2020/osc-52-patch-for-vte-0425/index.html @@ -1,379 +1,28 @@ - - + Mosh + Tmux + Copy Paste | Andrew M. Zhang

Mosh + Tmux + Copy Paste

OUTDATED

This guide is outdated. I’m keeping this up for my own records. The updated guide to setting this up will be placed

The overarching goal is to set up what I believe to be the ideal remote development terminal setup; mosh into remote -> tmux + ability to copy paste to local machine.

Background

To achieve the stated goal, we implement the OSC 52 escape command within the default terminal provided by the Ubuntu OS 16.04 (gnome-terminal) so I could copy and paste to the system clipboard through terminal escapes, ie printf "\033]52;c;$(printf "%s" "test" | base64)\a" should copy “test” into the local OS clipboard.

This particular version of vte was chosen due to the fact that its the default version of libvte for ubuntu 16.04, which is what I use. This patch won’t work for more modern versions of vte as the code has changed significantly.

Unsolved problems

Since the goal is for personal use on tmux, this OSC 52 patch does not cover all use cases for OSC 52. In fact this patch only supports the c; option (it assumes all OSC 52 escapes are trying to reach the clipboard). osc 52 documentation

Git Patch

patch code

git clone https://github.com/andrewmzhang/vte.git

To Install w/o Overriding Default libvte Install

# Dependencies
 
-  
-  
-    
-    
-
-    
-    
-    
-    
-    Mosh + Tmux + Copy Paste | Andrew M. Zhang
-    
-    
-    
-
-
-    
-    
-    
-
-    
-    
-
-    
-    
-    
-    
-
-    
-    
-
-    
-
-    
-    
-    
-    
-    
-    
-
-    
-    
-    
-
-    
-    
-    
-
-  
-
-  
-  
-
-    
-    
- - - - - - -
- -
-
-
- - - -
- - - -
- -
-

Mosh + Tmux + Copy Paste

- - -
- -
- -
-

OUTDATED

- -

This guide is outdated. I’m keeping this up for my own records. The updated guide to setting this up will be placed

- - -

The overarching goal is to set up what I believe to be the ideal remote development terminal setup; mosh into remote -> tmux + ability to copy paste to local machine.

- -

Background

- -

To achieve the stated goal, we implement the OSC 52 escape command within the default terminal provided by the Ubuntu OS 16.04 (gnome-terminal) so I could copy and paste to the system clipboard through terminal escapes, ie printf "\033]52;c;$(printf "%s" "test" | base64)\a" should copy “test” into the local OS clipboard.

- -

This particular version of vte was chosen due to the fact that its the default version of libvte for ubuntu 16.04, which is what I use. This patch won’t work for more modern versions of vte as the code has changed significantly.

- -

Unsolved problems

- -

Since the goal is for personal use on tmux, this OSC 52 patch does not cover all use cases for OSC 52. In fact this patch only supports the c; option (it assumes all OSC 52 escapes are trying to reach the clipboard). osc 52 documentation

- -

Git Patch

- -

patch code

- -

git clone https://github.com/andrewmzhang/vte.git

- -

To Install w/o Overriding Default libvte Install

- -
# Dependencies
 sudo apt-get install gtk-doc-tools gobject-introspection valac libvala-dev libgnutls-dev libgirepository1.0-dev gperf
 
-
 # Will install to /opt/vte
+
 ./autogen.sh --prefix=/opt/vte
 make
-sudo make install
+sudo make install

Setting Up gnome-terminal

Initially I tried to devise a way to have 2 different gnome-terminal executables, one that would launch with the doctored libvte library and the other untouched, since I don’t have functionality to turn off OSC 52 escapes once implemented. Unfortunately it seems that gnome-terminal uses the system global name “org.gnome.Terminal” to communicate through the dbus. I don’t know how dbus works, so I didn’t attempt to manipulate it.

When gnome-terminal launches, it actually communicates w/ gnome-terminal-server (or launches it) and gnome-terminal exits (see post on this: gnome-terminal-server-explained ). So we actually need to get gnome-terminal-server to use our doctored lib.

gnome-terminal/gnome-terminal-server version 3.18.3 on the defaul Ubuntu install seems to be a bit different from what sits at the gnome gitlab repository. Instead of trying to install whatever patches Ubuntu utilizes, I opted to relink the gnome-terminal-server executable to point to our doctored lib.

# Will show you what libvte links to
 
-

Setting Up gnome-terminal

+ldd /usr/lib/gnome-terminal/gnome-terminal-server | grep "vte" -

Initially I tried to devise a way to have 2 different gnome-terminal executables, one that would launch with the doctored libvte library and the other untouched, since I don’t have functionality to turn off OSC 52 escapes once implemented. Unfortunately it seems that gnome-terminal uses the system global name “org.gnome.Terminal” to communicate through the dbus. I don’t know how dbus works, so I didn’t attempt to manipulate it.

- -

When gnome-terminal launches, it actually communicates w/ gnome-terminal-server (or launches it) and gnome-terminal exits (see post on this: gnome-terminal-server-explained ). So we actually need to get gnome-terminal-server to use our doctored lib.

- -

gnome-terminal/gnome-terminal-server version 3.18.3 on the defaul Ubuntu install seems to be a bit different from what sits at the gnome gitlab repository. Instead of trying to install whatever patches Ubuntu utilizes, I opted to relink the gnome-terminal-server executable to point to our doctored lib.

- -
# Will show you what libvte links to
-ldd /usr/lib/gnome-terminal/gnome-terminal-server | grep "vte" 
 # outputs: libvte-2.91.so.0 => /usr/lib/x86_64-linux-gnu/libvte-2.91.so.0
 
 # Backup gnome-terminal-server
+
 sudo cp /usr/lib/gnome-terminal/gnome-terminal-server /usr/lib/gnome-terminal/gnome-terminal-server.bak
 
 # Relink the library; Run the patchelf on a non libvte based emulator (eg xterm)
-sudo apt install -y patchelf
-sudo patchelf --replace-needed libvte-2.91.so.0 /opt/vte/lib/libvte-2.91.so.0 /usr/lib/gnome-terminal/gnome-terminal-server
- -

Fixing the colours

- -

The colours might have changed (for me libvte put up a white background w/ black text). To fix this open gnome-terminal->profile preferences->colors

- -

Change the text color to: #FEF8D9 -Change the background color to: #300A24 -Bold color to: [x] Same as text color

- -

Setting Up tmux and mosh

- -

First, we need to tell tmux to copy via OSC 52. To do this we need to set the clipboard.

-

Tmux supports OSC 52 but does not pass the “c;” option, according to yudai’s post. However we can force it to pass the “c;” option. Mosh is capable of catching the OSC 52 option c (the default mosh only accepts the “c;” option). Thus adding these lines to the tmux.conf should allow us to copy into local clipboard. I think if you install this mosh pr it supports the other OSC 52 options.

- -

Note: This only works for more recent version of tmux.

+sudo apt install -y patchelf +sudo patchelf --replace-needed libvte-2.91.so.0 /opt/vte/lib/libvte-2.91.so.0 /usr/lib/gnome-terminal/gnome-terminal-server

Fixing the colours

The colours might have changed (for me libvte put up a white background w/ black text). To fix this open gnome-terminal->profile preferences->colors

Change the text color to: #FEF8D9 Change the background color to: #300A24 Bold color to: [x] Same as text color

Setting Up tmux and mosh

First, we need to tell tmux to copy via OSC 52. To do this we need to set the clipboard.

Tmux supports OSC 52 but does not pass the “c;” option, according to yudai’s post. However we can force it to pass the “c;” option. Mosh is capable of catching the OSC 52 option c (the default mosh only accepts the “c;” option). Thus adding these lines to the tmux.conf should allow us to copy into local clipboard. I think if you install this mosh pr it supports the other OSC 52 options.

Note: This only works for more recent version of tmux.

# sets tmux to use OSC 52 escape
 
-
# sets tmux to use OSC 52 escape
 set -g set-clipboard on
 
 # Forces tmux to use the "c;" option
-set -ag terminal-overrides "vte*:XT:Ms=\\E]52;c;%p2%s\\7,xterm*:XT:Ms=\\E]52;c;%p2%s\\7"
- -

Contributions

-

Big thanks to Kevin Zheng for providing most of the code :)

- -
-
- - - - -
-
-
-
    - - -

    Enjoy Reading This Article?

    -

    Here are some more articles you might like to read next:

    - - -
  • - Running step-ca in docker w/ Yubikey -
  • - - - -
  • - Reverse Proxies With Custom ACME -
  • - - - -
  • - Custom TLD Over Tailscale -
  • - - - -
  • - Notes on Arduino GPS Library -
  • - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +set -ag terminal-overrides "vte*:XT:Ms=\\E]52;c;%p2%s\\7,xterm*:XT:Ms=\\E]52;c;%p2%s\\7"

    Contributions

    Big thanks to Kevin Zheng for providing most of the code :)




      Enjoy Reading This Article?

      Here are some more articles you might like to read next:

    • Custom TLD Over Tailscale
    • Running step-ca in docker w/ Yubikey
    • Notes on Arduino GPS Library
    • Reverse Proxies With Custom ACME
    • \ No newline at end of file diff --git a/blog/2021/arduino-gps-notes/index.html b/blog/2021/arduino-gps-notes/index.html index bb623ed..b06c367 100644 --- a/blog/2021/arduino-gps-notes/index.html +++ b/blog/2021/arduino-gps-notes/index.html @@ -1,411 +1 @@ - - - - - - - - - - - - - Notes on Arduino GPS Library | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - - - - -
      - -
      -
      -
      - - - -
      - - - -
      - -
      -

      Notes on Arduino GPS Library

      - - -
      - -
      - -
      -

      Note: I splurged on a better quality (though way more expensive) shields from sparkfun. Thus this post will probably remain unupdated.

      - -

      Intro

      - -

      I bought DFRobot SIM 808 shield. Cheap shield. However, the library provided by DFRobot is not great. Here are my notes and possible solutions and a low quality fork.

      - -

      On Terminology:

      -
        -
      • Board refers to the arduino. I used an Arduino Uno Rev3.
      • -
      • Shield refers to the DFRobot Shield.
      • -
      - -

      My Fork

      -
        -
      1. andrewmzhang arduino-sim808 fork
      2. -
      - -

      I present my fork of the library, along with an updated version of the sample usage. The best way to use this is to un-stack the shield from the arduino and connect the power lines via male-to-male jumpers. Power pins, pin 12, pin 13 on the board should connect to analogous pins on the shield. Remap pins 2 and 3 from the arduino to pins 0 and 1 on the shield. I explain my motivation for this design below

      - -

      DFRobot SIM808 Library and Resources

      - -
        -
      1. DFRobot SIM808 Github Repo
      2. -
      3. DFRobot SIM808 Wiki Docs
      4. -
      - -

      Pros

      - -

      The documentation has tool called a Serial Debugger. Super useful. You can issue direct AT (which I understand is some kind of protocol sent over Serial) commands to the shield. There’s a typo in the GPS Orientation command. It should say AT + CGNS PWR = 1.

      - -

      Cons

      - -

      There are a few issues with this shield. The first issue is that the module communicates with the arduino board through the default TX RX serial ports; pins 0 and 1 are the Arduino Uno. This is a problem because those pins are also connected to the USB Serial line which means:

      - -
        -
      1. You cannot upload sketches without powering down the shield.
      2. -
      3. All communication sent to the shield will also show up in USB Serial Monitor.
      4. -
      5. Any prints done on arduino will show up on the USB Serial Monitor and will be sent to the shield.
      6. -
      7. This means debugging is nuts; say you want to print out what the Sim808 library buffer is receiving from the shield and print it w/ Serial.println. This will cause a feedback loop since the library buffer will catch it again. This makes the shield a pain to debug.
      8. -
      - -

      The Library is also not particularly well written. A lot of features are missing, such as trying to get the number of satellites in view. And the design of the library is questionable; IIRC the getGPRMS code read 1 char from the serial stream, adds it toa global buffer, checks to see if the global buffer has accumulated to a valid GPRMS (it ignores all other NMEA streams types), and fails if it doesn’t. This means you need to wrap calls to getGPS in a while loop since getGPS will fail a lot…

      - -

      NOTE: I might need to double check the above. I kinda forgot how the lib actually works and I don’t wanna check at 2:26 AM… I will verify/fix this section ASAP…

      - -

      blemasle arduino-sim808 library

      - -
        -
      1. blemasle library
      2. -
      - -

      This library appears to be written for the Adafruit FONA? Not sure.

      - -

      Pros

      - -

      This library has super good logic, also really clean code, fully featured. Some bugs/idiosyncrasies but I’m not using the right board so eh…

      - -

      Cons

      - -

      It doesn’t work on the DFRobot shield very well. Also no comments so its a pain to figure out how it works.

      - -

      There is also a bug!

      - -

      Fixes

      - -

      I present my fixes on the arduino-sim808 library for the DFRobot shield.

      - -

      Hardware

      - -

      Serial communication with the SIM808

      - -

      The solution here is to un-stack the shield and then just use male-to-male jumpers to connect over the power pins. Pins 13 and 12, and connect pins 0,1 on the shield to 2,3 on the board respectively. Then we will use software serial to communicate with the shield, and use the default 0, 1 pins to print Serial messages as per usual. This prevents the Serial prints and board buffer printouts to get feedback looped or whatever.

      - -

      Power On

      - -

      The shield comes with a boot switch. The documentation on the DFRWiki (link here) states that we can press the switch for 1s to power on and 3s to power off. It also states that the switch is also tied to pin D12. Do programatically hit the switch, write high to D12 for X seconds. We can use this trigger the SIM808 power on/off.

      - -

      Reset Pin

      - -

      Although there are traces on the board leading from the SIM808 SIM RESET pin on the SIM808 chip, I can’t figure out where they lead to. The Leonardo version of this shield has some jumpers to tap into that trace, but no on the arduino shield. Thus we leave this alone.

      - -

      Status Pin

      - -

      Again, there are no jumpers to access this on the arduino version of the shield.

      - -

      Software

      - -

      We use the Software Serial to 2,3 to communicate with the shield.

      - -

      I’m not sure when RDY gets sent. When I had the shield serial connected to board serial default (0,1), I never got the RDY response from the shield and setting the baud rate into non-volatile memory (AT?? command) never held across reboot. You only get the RDY if the baud is set according to the docs. Thus in the default library with the default serial comms, the sim808 gets stuck on init waiting on RDY

      - -

      Another issue is that if the GPS fix fails (not enough satellites to perform trilateration), you cannot get any data from NMEA streams that are available; current time, number of GPS in view, etc. I have fixed this (insert github line link here)

      - - -
      -
      - - - - -
      -
      -
      -
        - - -

        Enjoy Reading This Article?

        -

        Here are some more articles you might like to read next:

        - - -
      • - Running step-ca in docker w/ Yubikey -
      • - - - -
      • - Reverse Proxies With Custom ACME -
      • - - - -
      • - Custom TLD Over Tailscale -
      • - - - -
      • - Mosh + Tmux + Copy Paste -
      • - -
        - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Notes on Arduino GPS Library | Andrew M. Zhang

        Notes on Arduino GPS Library

        Note: I splurged on a better quality (though way more expensive) shields from sparkfun. Thus this post will probably remain unupdated.

        Intro

        I bought DFRobot SIM 808 shield. Cheap shield. However, the library provided by DFRobot is not great. Here are my notes and possible solutions and a low quality fork.

        On Terminology:

        • Board refers to the arduino. I used an Arduino Uno Rev3.
        • Shield refers to the DFRobot Shield.

        My Fork

        1. andrewmzhang arduino-sim808 fork

        I present my fork of the library, along with an updated version of the sample usage. The best way to use this is to un-stack the shield from the arduino and connect the power lines via male-to-male jumpers. Power pins, pin 12, pin 13 on the board should connect to analogous pins on the shield. Remap pins 2 and 3 from the arduino to pins 0 and 1 on the shield. I explain my motivation for this design below

        DFRobot SIM808 Library and Resources

        1. DFRobot SIM808 Github Repo
        2. DFRobot SIM808 Wiki Docs

        Pros

        The documentation has tool called a Serial Debugger. Super useful. You can issue direct AT (which I understand is some kind of protocol sent over Serial) commands to the shield. There’s a typo in the GPS Orientation command. It should say AT + CGNS PWR = 1.

        Cons

        There are a few issues with this shield. The first issue is that the module communicates with the arduino board through the default TX RX serial ports; pins 0 and 1 are the Arduino Uno. This is a problem because those pins are also connected to the USB Serial line which means:

        1. You cannot upload sketches without powering down the shield.
        2. All communication sent to the shield will also show up in USB Serial Monitor.
        3. Any prints done on arduino will show up on the USB Serial Monitor and will be sent to the shield.
        4. This means debugging is nuts; say you want to print out what the Sim808 library buffer is receiving from the shield and print it w/ Serial.println. This will cause a feedback loop since the library buffer will catch it again. This makes the shield a pain to debug.

        The Library is also not particularly well written. A lot of features are missing, such as trying to get the number of satellites in view. And the design of the library is questionable; IIRC the getGPRMS code read 1 char from the serial stream, adds it toa global buffer, checks to see if the global buffer has accumulated to a valid GPRMS (it ignores all other NMEA streams types), and fails if it doesn’t. This means you need to wrap calls to getGPS in a while loop since getGPS will fail a lot…

        NOTE: I might need to double check the above. I kinda forgot how the lib actually works and I don’t wanna check at 2:26 AM… I will verify/fix this section ASAP…

        blemasle arduino-sim808 library

        1. blemasle library

        This library appears to be written for the Adafruit FONA? Not sure.

        Pros

        This library has super good logic, also really clean code, fully featured. Some bugs/idiosyncrasies but I’m not using the right board so eh…

        Cons

        It doesn’t work on the DFRobot shield very well. Also no comments so its a pain to figure out how it works.

        There is also a bug!

        Fixes

        I present my fixes on the arduino-sim808 library for the DFRobot shield.

        Hardware

        Serial communication with the SIM808

        The solution here is to un-stack the shield and then just use male-to-male jumpers to connect over the power pins. Pins 13 and 12, and connect pins 0,1 on the shield to 2,3 on the board respectively. Then we will use software serial to communicate with the shield, and use the default 0, 1 pins to print Serial messages as per usual. This prevents the Serial prints and board buffer printouts to get feedback looped or whatever.

        Power On

        The shield comes with a boot switch. The documentation on the DFRWiki (link here) states that we can press the switch for 1s to power on and 3s to power off. It also states that the switch is also tied to pin D12. Do programatically hit the switch, write high to D12 for X seconds. We can use this trigger the SIM808 power on/off.

        Reset Pin

        Although there are traces on the board leading from the SIM808 SIM RESET pin on the SIM808 chip, I can’t figure out where they lead to. The Leonardo version of this shield has some jumpers to tap into that trace, but no on the arduino shield. Thus we leave this alone.

        Status Pin

        Again, there are no jumpers to access this on the arduino version of the shield.

        Software

        We use the Software Serial to 2,3 to communicate with the shield.

        I’m not sure when RDY gets sent. When I had the shield serial connected to board serial default (0,1), I never got the RDY response from the shield and setting the baud rate into non-volatile memory (AT?? command) never held across reboot. You only get the RDY if the baud is set according to the docs. Thus in the default library with the default serial comms, the sim808 gets stuck on init waiting on RDY

        Another issue is that if the GPS fix fails (not enough satellites to perform trilateration), you cannot get any data from NMEA streams that are available; current time, number of GPS in view, etc. I have fixed this (insert github line link here)




          Enjoy Reading This Article?

          Here are some more articles you might like to read next:

        • Custom TLD Over Tailscale
        • Running step-ca in docker w/ Yubikey
        • Reverse Proxies With Custom ACME
        • Mosh + Tmux + Copy Paste
        • \ No newline at end of file diff --git a/blog/2021/index.html b/blog/2021/index.html index 4a13b31..02cc000 100644 --- a/blog/2021/index.html +++ b/blog/2021/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - 2021 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          - - - - - - -
          - -
          -
          -
          - - - -
          - -
          - -
          -

          2021

          -

          an archive of posts from this year

          -
          - - - -
          - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 2021 | Andrew M. Zhang

          2021

          an archive of posts from this year

          \ No newline at end of file diff --git a/blog/2023/custom-tld/index.html b/blog/2023/custom-tld/index.html index ae144ec..c3bed49 100644 --- a/blog/2023/custom-tld/index.html +++ b/blog/2023/custom-tld/index.html @@ -1,356 +1,26 @@ - - - - - - - - - - - - - Custom TLD Over Tailscale | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          - - - - - - -
          - -
          -
          -
          - - - -
          - - - -
          - -
          -

          Custom TLD Over Tailscale

          - - -
          - -
          - -
          -

          Note: It’s like 2am and I was too sleepy to edit this, so I fed it through chatGPT and called it a day. I think it -made some minor mistakes and poor word choice. I’ll fix it tomorrow or something…

          - -

          Intro

          - -

          Tailscale is a Wireguard-based VPN software that I rely on for secure and remote access across my devices. I appreciate -its remarkably minimal setup process - simply installing Tailscale on a device grants it access to the VPN, with the -software taking care of the rest. However, one inconvenience I encountered was the built-in DNS’s limitation of -resolving device hostnames without a TLD. For instance, if I add a machine with the hostname machineA, I can access -webpages hosted on it via https://machineA, but unfortunately, Tailscale DNS does not support setting the domain to -something like https://machineA.ctld. This page documents my solution to implementing a private TLD over a Tailscale -network.

          - -

          I am committed to using TLS because I value the green lock symbol and the assurance it provides. It is crucial for my -setup to appear legitimate; otherwise, people may doubt the credibility of AndyWebServices El El Sí as a legitimate -company. This credibility is essential for attracting investors and achieving a valuation of 100 trillion.

          - -

          To clarify. These are the requirements:

          - -
            -
          • Any and only devices connected by my Tailscale network should be able to access the custom tld network
          • -
          • I intend to use a custom TLD format, such as hostname.ctld. For the purpose of this guide, I will use .ctld as the -TLD.
          • -
          • HTTPS functionality
          • -
          - -

          Resolving a custom TLD over Tailscale

          - -

          Resolving custom TLD

          - -

          Tailscale facilitates secure connections between devices within the Tailscale network. Each device on the Tailscale -network is assigned a static Tailscale IP (100.xx.yy.zz) along with a non-TLD domain. The resolution of this non-TLD -domain is handled by a local DNS resolver that is included with the Tailscale installation.

          - -

          To incorporate a custom TLD into this setup, the first step is to set up a dedicated DNS server to resolve *.ctld -domains. I recommend following the setup outlined below:

          - -
            -
          1. Obtain a Raspberry Pi device. -
              -
            1. If you intend to replicate my network setup, install and configure Ubuntu on the Raspberry Pi.
            2. -
            -
          2. -
          3. Connect the Raspberry Pi to the Tailscale (TS) network. For the sake of this guide, let’s assume it is assigned the -TS IP address 100.100.100.101.
          4. -
          5. Install and set up dnsmasq on the Raspberry Pi.
          6. -
          7. Edit the /etc/hosts file on the Raspberry Pi to manually define the DNS entries. -
              -
            1. In case you are using the default Ubuntu installation, you may need to modify the cloud-init template. Please -refer to the comments in your /etc/hosts file for guidance.
            2. -
            3. The entries in the /etc/hosts file should resemble the following format:
            4. -
            -
          8. -
          - -
          # /etc/hosts
          +        Custom TLD Over Tailscale | Andrew M. Zhang                  

          Custom TLD Over Tailscale

          Note: It’s like 2am and I was too sleepy to edit this, so I fed it through chatGPT and called it a day. I think it made some minor mistakes and poor word choice. I’ll fix it tomorrow or something…

          Intro

          Tailscale is a Wireguard-based VPN software that I rely on for secure and remote access across my devices. I appreciate its remarkably minimal setup process - simply installing Tailscale on a device grants it access to the VPN, with the software taking care of the rest. However, one inconvenience I encountered was the built-in DNS’s limitation of resolving device hostnames without a TLD. For instance, if I add a machine with the hostname machineA, I can access webpages hosted on it via https://machineA, but unfortunately, Tailscale DNS does not support setting the domain to something like https://machineA.ctld. This page documents my solution to implementing a private TLD over a Tailscale network.

          I am committed to using TLS because I value the green lock symbol and the assurance it provides. It is crucial for my setup to appear legitimate; otherwise, people may doubt the credibility of AndyWebServices El El Sí as a legitimate company. This credibility is essential for attracting investors and achieving a valuation of 100 trillion.

          To clarify. These are the requirements:

          • Any and only devices connected by my Tailscale network should be able to access the custom tld network
          • I intend to use a custom TLD format, such as hostname.ctld. For the purpose of this guide, I will use .ctld as the TLD.
          • HTTPS functionality

          Resolving a custom TLD over Tailscale

          Resolving custom TLD

          Tailscale facilitates secure connections between devices within the Tailscale network. Each device on the Tailscale network is assigned a static Tailscale IP (100.xx.yy.zz) along with a non-TLD domain. The resolution of this non-TLD domain is handled by a local DNS resolver that is included with the Tailscale installation.

          To incorporate a custom TLD into this setup, the first step is to set up a dedicated DNS server to resolve *.ctld domains. I recommend following the setup outlined below:

          1. Obtain a Raspberry Pi device.
            1. If you intend to replicate my network setup, install and configure Ubuntu on the Raspberry Pi.
          2. Connect the Raspberry Pi to the Tailscale (TS) network. For the sake of this guide, let’s assume it is assigned the TS IP address 100.100.100.101.
          3. Install and set up dnsmasq on the Raspberry Pi.
          4. Edit the /etc/hosts file on the Raspberry Pi to manually define the DNS entries.
            1. In case you are using the default Ubuntu installation, you may need to modify the cloud-init template. Please refer to the comments in your /etc/hosts file for guidance.
            2. The entries in the /etc/hosts file should resemble the following format:
          # /etc/hosts
           # tailscale_IP hostname
           myMachineA.ctld 100.100.100.123
          -
          - -

          You only need to perform this setup once since the Tailscale IP is static. Keep in mind that these IPs are only -accessible when connected to the VPN. While it is advisable to configure dnsmasq on your Tailscale network interface, -setting it up on 0.0.0.0 is unlikely to pose a security risk.

          - -

          SplitDNS

          - -

          We must ensure the proper utilization of the DNS server by devices connected to the Tailscale network. To achieve -this, we will proceed with configuring SplitDNS within the Tailscale Admin Console. Our primary objective is to -establish the resolution of *.ctld to the Tailscale IP address assigned to the DNS server, -specifically 100.100.100.101.

          - -

          By implementing this approach, any device that joins the Tailscale Network will seamlessly attempt to utilize the DNS -resolver of the Raspberry Pi (rpi) running dnsmasq, but solely for domains associated with our custom top-level domain ( -ctld). This strategy ensures optimal efficiency, as domain resolutions for standard domains like google.com continue -to -be handled by the local DNS, while requests for *.ctld domains are routed through the Tailscale network’s DNS server, -which may incur a higher latency if our rpi is not nearby.

          - -

          TLS Certificates ( The Green Stuff )

          - -

          To enable the use of HTTPS without encountering any browser warnings, obtaining TLS certificates is essential. If you -are already familiar with TLS and its intricacies, you may skip the remaining portion of this subsection. However, if -you require a more detailed explanation, there are numerous comprehensive resources available online.

          - -

          TLS, which stands for Transport Layer Security, is a crucial component of Private Key Infrastructure (PKI) -framework. When a client and server aim to establish a secure communication channel, the client must be aware of the -server’s public key. While the DNS server provides the IP address of machineA.ctld, it does not verify the legitimacy -of the server’s public key. TLS ensures that the key has not been tampered with or maliciously -altered during transit over the network. While communications between Tailscale (TS) devices are considered secure, the -broader internet cannot make such assumptions. Therefore, without the server’s public key, secure communication becomes -impossible. This is where TLS certificates come into play.

          - -

          A TLS certificate is an attestation signed by a trusted entity known as a Certificate Authority (CA). It asserts that a -specific public key belongs to machineA.ctld. Understanding the three levels of TLS certificates is -important. First, the root certificate is a self-signed certificate that contains the public key of the CA. This root -certificate must be installed on all machines requiring TLS functionality for our custom TLD. The private key used to -sign the root certificate is typically kept offline in cold storage, as recovery from a compromised root key is -impossible, -eg you can’t sign a revocation if your private key cannot be trusted.

          - -

          The intermediate certificate is signed by the root certificate and is responsible for signing leaf certificates. Unlike -the root certificate, the private key of the intermediate certificate is usually kept online since it is required to -sign leaf certificates. If an intermediate certificate becomes compromised or expires, the root private key can be -brought out of cold storage to issue a revocation.

          - -

          The leaf or end certificate, which is presented by machineA.ctld, serves as proof that its public key is legitimate. -The -intermediate certificate has the authority to revoke leaf certificates if machineA.ctld exhibits malicious behavior.

          - -

          TLS certificates can be generated by the CA and securely transferred to the server using methods like scp. This approach -is particularly useful for devices where running ACME (Automated Certificate Management Environment) properly is not -feasible. Or if the CA cannot establish bi-directional communication with the machine for some reason. ACME provides an -automated mechanism for generating certificate signing requests and validating the domain ownership to the CA.

          - -

          By understanding these concepts, we can effectively utilize TLS certificates to establish secure and trusted -communication channels, ensuring the green lock symbol and seamless HTTPS functionality in our browsers.

          - -

          ACME

          - -

          If you have previous experience with Let’s Encrypt or certbot, then you are likely familiar with the ACME (Automated -Certificate Management Environment) protocol. ACME is a collection of protocols that servers can employ to demonstrate -their ownership of domain names to Certificate Authorities (CAs) when requesting certificates. The primary purpose of a -certificate is to certify that machineA.ctld is indeed the owner of a specific public key.

          - -

          ACME offers two verification methods, with the less commonly used method being DNS certification. In this approach, the -client server contacts the ACME server and claims ownership of machineA.ctld. The client server provides a -Certificate Signing Request (CSR) to the ACME server for signing. The ACME server then requests the client server to add -a specific string to the TXT section of the DNS record. If the server genuinely owns machineA.ctld and its authoritative -nameserver supports an API for managing domain records, the server can perform the required operation and have it -verified by the ACME server. However, as we are utilizing dnsmasq as our DNS server, the specific steps for performing -this operation are not within my expertise.

          - -

          It is worth noting that the DNS certification method is less common compared to the alternative method, which involves -proving ownership through HTTP-based challenges. This method requires the server to respond to a challenge by placing a -designated file at a specified location on the web server. The ACME server then attempts to access the file to validate -ownership. This approach is generally more straightforward to implement and is not dependent on what API your DNS -provider happens to supply.

          - -

          Step CA

          - -

          To proceed with setting up an ACME server on a Raspberry Pi, we can follow the guide provided -at https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/. Although the guide incorporates using a -YubiKey for loading keys, it is not necessary for our purposes. However, adhering to proper security practices is always -recommended, and if you have access to YubiKeys, it can enhance the overall security of the setup. I get them for free -at work. There is an option to use the infnoise generator dongle, but we will opt because it costs too much and I don’t -get them for free at work. I recommend you use the same Raspberry Pi you’re hosting the ctld DNS off of. Note that the -ACME server will run on port 443, while the DNS server will operate on port 53, ensuring that there won’t be any -conflicts between the two services.

          - -

          During the setup process, remember to modify the domain from tinyca.internal to a domain of your choice with -the .ctld extension, such as ctldca.ctld.

          - -

          Once you have completed this step, you will be able to request TLS certificates for your custom domain, allowing you to -establish secure connections using HTTPS.

          - -

          Install the root cert

          - -

          To ensure that your browser and servers recognize the custom TLD Certificate Authority (CA) and avoid any issues with -certificate verification, install the root certificate into the truststore of your devices. This step -will establish trust in the certificates issued by the custom CA.

          - -

          To verify if the installation was successful, you can open a shell or command prompt and execute the -command curl https://machinea.ctld. If you encounter an error 60, it indicates that the CA is not recognized by your -machine, indicating a problem with the root certificate installation.

          - -

          For convenience and ease of use, it is recommended to store the root certificate in a cloud drive or a similar storage -solution. This way, you can readily access and install it on new devices whenever necessary.

          - -

          Requesting a cert

          - -

          You can refer to the guides provided at https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/ for detailed -instructions on setting up various ACME clients. However, if you’re looking for a straightforward and user-friendly -option, I recommend using acme.sh.

          - -

          Some pitfalls in cert requesting

          - -

          I’ll probably split this off into separate guides when I get the chance.

          - -

          HAProxy

          - -

          Certain reverse proxies, such as HAProxy, will require the leaf private key and certificate in one file. If this -is the case you will need to cat the key and cert together. A reverse proxy may also hog port 80 and 443 which are needed to -do the ACME challenge, in which case you will need to carve out a path to the ACME client.

          - -

          Here is my setup for HAProxy - it’s my octoprint server:

          - -
          # In /etc/haproxy/haproxy.cfg
          +

          You only need to perform this setup once since the Tailscale IP is static. Keep in mind that these IPs are only accessible when connected to the VPN. While it is advisable to configure dnsmasq on your Tailscale network interface, setting it up on 0.0.0.0 is unlikely to pose a security risk.

          SplitDNS

          We must ensure the proper utilization of the DNS server by devices connected to the Tailscale network. To achieve this, we will proceed with configuring SplitDNS within the Tailscale Admin Console. Our primary objective is to establish the resolution of *.ctld to the Tailscale IP address assigned to the DNS server, specifically 100.100.100.101.

          By implementing this approach, any device that joins the Tailscale Network will seamlessly attempt to utilize the DNS resolver of the Raspberry Pi (rpi) running dnsmasq, but solely for domains associated with our custom top-level domain ( ctld). This strategy ensures optimal efficiency, as domain resolutions for standard domains like google.com continue to be handled by the local DNS, while requests for *.ctld domains are routed through the Tailscale network’s DNS server, which may incur a higher latency if our rpi is not nearby.

          TLS Certificates ( The Green Stuff )

          To enable the use of HTTPS without encountering any browser warnings, obtaining TLS certificates is essential. If you are already familiar with TLS and its intricacies, you may skip the remaining portion of this subsection. However, if you require a more detailed explanation, there are numerous comprehensive resources available online.

          TLS, which stands for Transport Layer Security, is a crucial component of Private Key Infrastructure (PKI) framework. When a client and server aim to establish a secure communication channel, the client must be aware of the server’s public key. While the DNS server provides the IP address of machineA.ctld, it does not verify the legitimacy of the server’s public key. TLS ensures that the key has not been tampered with or maliciously altered during transit over the network. While communications between Tailscale (TS) devices are considered secure, the broader internet cannot make such assumptions. Therefore, without the server’s public key, secure communication becomes impossible. This is where TLS certificates come into play.

          A TLS certificate is an attestation signed by a trusted entity known as a Certificate Authority (CA). It asserts that a specific public key belongs to machineA.ctld. Understanding the three levels of TLS certificates is important. First, the root certificate is a self-signed certificate that contains the public key of the CA. This root certificate must be installed on all machines requiring TLS functionality for our custom TLD. The private key used to sign the root certificate is typically kept offline in cold storage, as recovery from a compromised root key is impossible, eg you can’t sign a revocation if your private key cannot be trusted.

          The intermediate certificate is signed by the root certificate and is responsible for signing leaf certificates. Unlike the root certificate, the private key of the intermediate certificate is usually kept online since it is required to sign leaf certificates. If an intermediate certificate becomes compromised or expires, the root private key can be brought out of cold storage to issue a revocation.

          The leaf or end certificate, which is presented by machineA.ctld, serves as proof that its public key is legitimate. The intermediate certificate has the authority to revoke leaf certificates if machineA.ctld exhibits malicious behavior.

          TLS certificates can be generated by the CA and securely transferred to the server using methods like scp. This approach is particularly useful for devices where running ACME (Automated Certificate Management Environment) properly is not feasible. Or if the CA cannot establish bi-directional communication with the machine for some reason. ACME provides an automated mechanism for generating certificate signing requests and validating the domain ownership to the CA.

          By understanding these concepts, we can effectively utilize TLS certificates to establish secure and trusted communication channels, ensuring the green lock symbol and seamless HTTPS functionality in our browsers.

          ACME

          If you have previous experience with Let’s Encrypt or certbot, then you are likely familiar with the ACME (Automated Certificate Management Environment) protocol. ACME is a collection of protocols that servers can employ to demonstrate their ownership of domain names to Certificate Authorities (CAs) when requesting certificates. The primary purpose of a certificate is to certify that machineA.ctld is indeed the owner of a specific public key.

          ACME offers two verification methods, with the less commonly used method being DNS certification. In this approach, the client server contacts the ACME server and claims ownership of machineA.ctld. The client server provides a Certificate Signing Request (CSR) to the ACME server for signing. The ACME server then requests the client server to add a specific string to the TXT section of the DNS record. If the server genuinely owns machineA.ctld and its authoritative nameserver supports an API for managing domain records, the server can perform the required operation and have it verified by the ACME server. However, as we are utilizing dnsmasq as our DNS server, the specific steps for performing this operation are not within my expertise.

          It is worth noting that the DNS certification method is less common compared to the alternative method, which involves proving ownership through HTTP-based challenges. This method requires the server to respond to a challenge by placing a designated file at a specified location on the web server. The ACME server then attempts to access the file to validate ownership. This approach is generally more straightforward to implement and is not dependent on what API your DNS provider happens to supply.

          Step CA

          To proceed with setting up an ACME server on a Raspberry Pi, we can follow the guide provided at https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/. Although the guide incorporates using a YubiKey for loading keys, it is not necessary for our purposes. However, adhering to proper security practices is always recommended, and if you have access to YubiKeys, it can enhance the overall security of the setup. I get them for free at work. There is an option to use the infnoise generator dongle, but we will opt because it costs too much and I don’t get them for free at work. I recommend you use the same Raspberry Pi you’re hosting the ctld DNS off of. Note that the ACME server will run on port 443, while the DNS server will operate on port 53, ensuring that there won’t be any conflicts between the two services.

          During the setup process, remember to modify the domain from tinyca.internal to a domain of your choice with the .ctld extension, such as ctldca.ctld.

          Once you have completed this step, you will be able to request TLS certificates for your custom domain, allowing you to establish secure connections using HTTPS.

          Install the root cert

          To ensure that your browser and servers recognize the custom TLD Certificate Authority (CA) and avoid any issues with certificate verification, install the root certificate into the truststore of your devices. This step will establish trust in the certificates issued by the custom CA.

          To verify if the installation was successful, you can open a shell or command prompt and execute the command curl https://machinea.ctld. If you encounter an error 60, it indicates that the CA is not recognized by your machine, indicating a problem with the root certificate installation.

          For convenience and ease of use, it is recommended to store the root certificate in a cloud drive or a similar storage solution. This way, you can readily access and install it on new devices whenever necessary.

          Requesting a cert

          You can refer to the guides provided at https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/ for detailed instructions on setting up various ACME clients. However, if you’re looking for a straightforward and user-friendly option, I recommend using acme.sh.

          Some pitfalls in cert requesting

          I’ll probably split this off into separate guides when I get the chance.

          HAProxy

          Certain reverse proxies, such as HAProxy, will require the leaf private key and certificate in one file. If this is the case you will need to cat the key and cert together. A reverse proxy may also hog port 80 and 443 which are needed to do the ACME challenge, in which case you will need to carve out a path to the ACME client.

          Here is my setup for HAProxy - it’s my octoprint server:

          # In /etc/haproxy/haproxy.cfg
           frontend public
               bind :::80 v4v6
               # Redirect requests to this path towards the ACME cleint instance on port 8888
               acl letsencrypt-acl path_beg /.well-known/acme-challenge/
               use_backend letsencrypt-backend if letsencrypt-acl
          -    
          +
               # Set the certificate
               bind :::443 v4v6 ssl crt /home/pi/.acme.sh/octoprint.aws.pem
           
           # This is the acme.sh port
           backend letsencrypt-backend
                   server letsencrypt 127.0.0.1:8888
          -
          - -
          # In crontab
          -# Request certs, place them in /some/config/dir. Follow the guide for details on configuring this. 
          -0 * * * * /some/dir/acme.sh --cron --home "/some/config/dir/" --force --httpport 8888 
          +
          # In crontab
          +# Request certs, place them in /some/config/dir. Follow the guide for details on configuring this.
          +0 * * * * /some/dir/acme.sh --cron --home "/some/config/dir/" --force --httpport 8888
           
           # Combine the privKey and the cert. Order matters here
           1 * * * * cat /some/config/dir/machineA.ctld.key /some/config/dir/machineA.ctld.crt > /some/config/dir/machineA.ctld.pem
          -
          - -

          You also need to reload the certificate cause HAProxy is too dumb to pick up that you edited it. Drop this script into -a file, edit your crontab to run it. Also maybe edit out the octoprint stuff:

          - -
          #!/bin/bash
          +

          You also need to reload the certificate cause HAProxy is too dumb to pick up that you edited it. Drop this script into a file, edit your crontab to run it. Also maybe edit out the octoprint stuff:

          #!/bin/bash
           echo========================== SET SSL CERT ==========================echo "$(cat /home/pi/.acme.sh/octoprint.aws.pem)"
           echo -e "set ssl cert /home/pi/.acme.sh/octoprint.aws.pem <<\n$(cat /home/pi/.acme.sh/octoprint.aws.pem)\n" | socat tcp-connect:localhost:9999 -
          @@ -360,211 +30,4 @@ 

          HAProxy

          echo "commit ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 - echo========================== SHOW SSL CERT - after ==========================echo "show ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 - -
          - -

          HomeAssistant

          - -

          This one is a pain in the ass. Haven’t gotten this up and running yet. I’ll write another post to document this.

          - - -
          -
          - - - - -
          -
          -
          -
            - - -

            Enjoy Reading This Article?

            -

            Here are some more articles you might like to read next:

            - - -
          • - Running step-ca in docker w/ Yubikey -
          • - - - -
          • - Reverse Proxies With Custom ACME -
          • - - - -
          • - Notes on Arduino GPS Library -
          • - - - -
          • - Mosh + Tmux + Copy Paste -
          • - -
            - - -
            -
            - - -
            - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

            HomeAssistant

            This one is a pain in the ass. Haven’t gotten this up and running yet. I’ll write another post to document this.




              Enjoy Reading This Article?

              Here are some more articles you might like to read next:

            • Running step-ca in docker w/ Yubikey
            • Reverse Proxies With Custom ACME
            • Notes on Arduino GPS Library
            • Mosh + Tmux + Copy Paste
            • \ No newline at end of file diff --git a/blog/2023/index.html b/blog/2023/index.html index 8eb3c83..45a0f33 100644 --- a/blog/2023/index.html +++ b/blog/2023/index.html @@ -1,284 +1 @@ - - - - - - - - - - - - - 2023 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              - - - - - - -
              - -
              -
              -
              - - - -
              - -
              - -
              -

              2023

              -

              an archive of posts from this year

              -
              - - - -
              - - -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 2023 | Andrew M. Zhang

              2023

              an archive of posts from this year

              \ No newline at end of file diff --git a/blog/2023/reverse-proxies-with-custom-acme/index.html b/blog/2023/reverse-proxies-with-custom-acme/index.html index 6d12eac..8e94724 100644 --- a/blog/2023/reverse-proxies-with-custom-acme/index.html +++ b/blog/2023/reverse-proxies-with-custom-acme/index.html @@ -1,176 +1,4 @@ - - - - - - - - - - - - - Reverse Proxies With Custom ACME | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              - - - - - - -
              - -
              -
              -
              - - - -
              - - - -
              - -
              -

              Reverse Proxies With Custom ACME

              - - -
              - -
              - -
              -

              Intro

              -

              This page assumes that you have some custom ACME server (see previous post) and you want a reverse proxy (eg Nginx, HaProxy) to use it to generate certs automatically.

              - -

              SWAG - docker-swag official -

              - -
                -
              1. Dockerhub image: andywebservices/swag -
              2. -
              - -

              Explanation

              -

              At time of writing, docker-swag main branch does not support custom ACME servers. Fortunately for the dear reader, I have graciously implemented this feature andrewmzhang/docker-swag. It’s probably easier to see how the feature works by looking at the diff. This feature introduces 2 new environment variables. One sets the ACME server and the other sets the CABUNDLE. The CABUNDLE is required so that docker trusts the certificate authority without having to install the certificate to the OS truststore, although I still recommend installing the certificate to your OS truststore.

              - -

              Docker-swag is a complete solution. It’ll renew the certificates once a day and refresh Nginx service to pick up the new certs.

              - -

              HAProxy + ACME.sh - haproxy -

              -

              Issues

              -

              EDIT: This section was updated on 2024-04-17. The previous instructions were out of date

              - -

              HAProxy suffers several issues.

              -
                -
              1. It cannot provision its own SSL certs, ie it cannot do the ACME dance
              2. -
              3. It hogs port 80 and 443, in order for 3rd party acme to work correctly the acme program needs 80 and 443.
              4. -
              5. It demands that the SSL privkey be in the same file as the cert bundle
              6. -
              7. It cannot tell if the SSL cert has changed on disk, thus users need to send commands to get HAProxy to refresh the certs
              8. -
              - -

              Fortunately, acme.sh has some helpers that make this procedure relatively painless

              -
              # Register an account thumbprint. This will produce a thumbprint. Copy that value
              +        Reverse Proxies With Custom ACME | Andrew M. Zhang                  

              Reverse Proxies With Custom ACME

              Intro

              This page assumes that you have some custom ACME server (see previous post) and you want a reverse proxy (eg Nginx, HaProxy) to use it to generate certs automatically.

              SWAG - docker-swag official

              1. Dockerhub image: andywebservices/swag

              Explanation

              At time of writing, docker-swag main branch does not support custom ACME servers. Fortunately for the dear reader, I have graciously implemented this feature andrewmzhang/docker-swag. It’s probably easier to see how the feature works by looking at the diff. This feature introduces 2 new environment variables. One sets the ACME server and the other sets the CABUNDLE. The CABUNDLE is required so that docker trusts the certificate authority without having to install the certificate to the OS truststore, although I still recommend installing the certificate to your OS truststore.

              Docker-swag is a complete solution. It’ll renew the certificates once a day and refresh Nginx service to pick up the new certs.

              HAProxy + ACME.sh - haproxy

              Issues

              EDIT: This section was updated on 2024-04-17. The previous instructions were out of date

              HAProxy suffers several issues.

              1. It cannot provision its own SSL certs, ie it cannot do the ACME dance
              2. It hogs port 80 and 443, in order for 3rd party acme to work correctly the acme program needs 80 and 443.
              3. It demands that the SSL privkey be in the same file as the cert bundle
              4. It cannot tell if the SSL cert has changed on disk, thus users need to send commands to get HAProxy to refresh the certs

              Fortunately, acme.sh has some helpers that make this procedure relatively painless

              # Register an account thumbprint. This will produce a thumbprint. Copy that value
               ./acme.sh --register-account --server https://step-ca.internal/acme/acme/directory -m myemail@example.com
               
               # Edit the following into /etc/haproxy/haproxy.cfg
              @@ -182,220 +10,11 @@ 

              Issues

              frontend public bind :::80 v4v6 bind :::443 v4v6 ssl crt /etc/haproxy/certs/ strict-sni # This allows haproxy to boot without certs, which you wont have initially - # The directive below means when the certificate authority navigates to my.domain.internal/.well-known/acme-challenge/ HAProxy will reply with the account thumbprint + # The directive below means when the certificate authority navigates to my.domain.internal/.well-known/acme-challenge/ HAProxy will reply with the account thumbprint http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_beg '/.well-known/acme-challenge/' } # Do the ACME dance, ACME will write some config files under ~/.acme.sh/mydomain.internal_ecc. Note the deploy-hook and --days 1 ./acme.sh --stateless --issue -d my.domain.internal --server https://step-ca.internal/acme/acme/directory --ca-bundle ~/my_root_ca.crt --deploy --deploy-hook haproxy --days 1 # Remember to update cron ./acme.sh --install-cronjob -
              - -

              Remember to check the .acme.sh config files, namely the Le_RenewalDays value. It defaults to 60 days, but step-ca certs default expires in 1 day, so you’ll need to mess with this value

              - -

              Resources

              -
                -
              1. https://www.haproxy.com/blog/haproxy-and-let-s-encrypt
              2. -
              - -
              -
              - - - - -
              -
              -
              -
                - - -

                Enjoy Reading This Article?

                -

                Here are some more articles you might like to read next:

                - - -
              • - Running step-ca in docker w/ Yubikey -
              • - - - -
              • - Custom TLD Over Tailscale -
              • - - - -
              • - Notes on Arduino GPS Library -
              • - - - -
              • - Mosh + Tmux + Copy Paste -
              • - -
                - - -
                -
                - - -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

                Remember to check the .acme.sh config files, namely the Le_RenewalDays value. It defaults to 60 days, but step-ca certs default expires in 1 day, so you’ll need to mess with this value

                Resources

                1. https://www.haproxy.com/blog/haproxy-and-let-s-encrypt



                  Enjoy Reading This Article?

                  Here are some more articles you might like to read next:

                • Custom TLD Over Tailscale
                • Running step-ca in docker w/ Yubikey
                • Notes on Arduino GPS Library
                • Mosh + Tmux + Copy Paste
                • \ No newline at end of file diff --git a/blog/2023/running-step-ca-in-docker-w-yubikey/index.html b/blog/2023/running-step-ca-in-docker-w-yubikey/index.html index e8e84e1..2a206d2 100644 --- a/blog/2023/running-step-ca-in-docker-w-yubikey/index.html +++ b/blog/2023/running-step-ca-in-docker-w-yubikey/index.html @@ -1,186 +1,4 @@ - - - - - - - - - - - - - Running step-ca in docker w/ Yubikey | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  - - - - - - -
                  - -
                  -
                  -
                  - - - -
                  - - - -
                  - -
                  -

                  Running step-ca in docker w/ Yubikey

                  - - -
                  - -
                  - -
                  -

                  Abstract

                  - -

                  Carl Tashian of Smallstep wrote a blog post regarding Building a Tiny Certificate Authority For Your Homelab. -This guide provides very complete instructions on how to install a step-ca certificate authority on a Raspberry Pi 4 -and how to store the private keys securely on a Yubikey. This post is written assuming familiarity with this guide. -Namely, be familiar with the process of running the step ca init twice, once to setup the private keys off-host (ie usb) -, then again to setup the directory structure. Certs must then be copied from the off-host device to the directory -structure. Private keys on the off-host device are loaded into a Yubikey.

                  - -

                  The only problem is I like using Docker and I generally dislike running stuff on bare metal. Unfortunately, there are -not any clear instructions on how to use the smallstep/step-ca:hsm image with a Raspberry Pi with a Yubikey. My guide -will roughly follow the same steps except using docker.

                  - -

                  NOTE There is currently a bug in step-ca’s dockerfile.hsm. See the final step of the guide for a quick fix.

                  - -

                  Read the following to understand the parts of a PKI https://smallstep.com/blog/everything-pki/

                  - -

                  Requirements

                  -
                    -
                  • Rpi
                  • -
                  • Yubikey
                  • -
                  • USB stick
                  • -
                  - -

                  Setup Rpi

                  - -

                  I tried this using both Ubuntu and Raspbian on Rpi. I think it’ll work on any Rpi OS that supports Docker. Do whatever -you need to do to install Docker.

                  - -

                  Setup Root and Intermediate keys onto USB stick

                  - -

                  The goal is to have the root and intermediate keys on a USB stick, just like in Carl’s guide. Though, I recommend -using a LUKS encrypted USB stick to hold the keys. You can steal the commands for setting that up here: https://github.com/drduh/YubiKey-Guide#backup

                  - -

                  For the remainder of the guide I’ll assume your usb, encrypted or otherwise, is mounted here /mnt/usb/

                  - -
                  # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                  +        Running step-ca in docker w/ Yubikey | Andrew M. Zhang                  

                  Running step-ca in docker w/ Yubikey

                  Abstract

                  Carl Tashian of Smallstep wrote a blog post regarding Building a Tiny Certificate Authority For Your Homelab. This guide provides very complete instructions on how to install a step-ca certificate authority on a Raspberry Pi 4 and how to store the private keys securely on a Yubikey. This post is written assuming familiarity with this guide. Namely, be familiar with the process of running the step ca init twice, once to setup the private keys off-host (ie usb) , then again to setup the directory structure. Certs must then be copied from the off-host device to the directory structure. Private keys on the off-host device are loaded into a Yubikey.

                  The only problem is I like using Docker and I generally dislike running stuff on bare metal. Unfortunately, there are not any clear instructions on how to use the smallstep/step-ca:hsm image with a Raspberry Pi with a Yubikey. My guide will roughly follow the same steps except using docker.

                  NOTE There is currently a bug in step-ca’s dockerfile.hsm. See the final step of the guide for a quick fix.

                  Read the following to understand the parts of a PKI https://smallstep.com/blog/everything-pki/

                  Requirements

                  • Rpi
                  • Yubikey
                  • USB stick

                  Setup Rpi

                  I tried this using both Ubuntu and Raspbian on Rpi. I think it’ll work on any Rpi OS that supports Docker. Do whatever you need to do to install Docker.

                  Setup Root and Intermediate keys onto USB stick

                  The goal is to have the root and intermediate keys on a USB stick, just like in Carl’s guide. Though, I recommend using a LUKS encrypted USB stick to hold the keys. You can steal the commands for setting that up here: https://github.com/drduh/YubiKey-Guide#backup

                  For the remainder of the guide I’ll assume your usb, encrypted or otherwise, is mounted here /mnt/usb/

                  # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                   
                   docker pull smallstep/step-ca:hsm
                   
                  @@ -192,9 +10,9 @@ 

                  Setup Root and Intermed ✔ Deployment Type: Standalone # Select Standalone What would you like to name your new PKI? ✔ (e.g. Smallstep): TinyCA # Give it a name. This will appear in yoru certs -What DNS names or IP addresses will clients use to reach your CA? +What DNS names or IP addresses will clients use to reach your CA? ✔ (e.g. ca.example.com[,10.1.2.3,etc.]): ca.internal,192.168.0.101,10.10.10.10 # You can list a bunch of these. Values can be adjusted layer in /mnt/usb/config/ca.json -What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443) +What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)(e.g. :443 or 127.0.0.1:443): :443 # You probably want :443(e.g. you@smallstep.com): email@example.com # Your email Choose a password for your CA keys and first provisioner. @@ -225,38 +43,7 @@

                  Setup Root and Intermed good or bad at feedback@smallstep.com or join GitHub Discussions https://github.com/smallstep/certificates/discussions and our Discord https://u.step.sm/discord. -

                  - -

                  Optional: Set up name contraints

                  - -

                  Follow the instructions here to setup up name constraints if you’re going to set it up for the root cert. This is probably -good practice. If you don’t use name constraints and your CA is hijacked, then it can issue certs for any domains (ie google.com). -Usually name constraints are set on the intermediate cert but for custom TLDs and internal stuff, constraining the -root cert is acceptable and is the only way to show clients that you’re not going to sign for stuff you don’t own (ie google.com).

                  - -

                  I use an internal TLD. You should set the permitted domains to also include the one you use for emails or else I think -you could get issues. Ie I setup my name constraints to sign .customtld, mydomain.com (I own this), and .mydomain.com

                  - -

                  Load the keys onto the yubikey

                  - -

                  Check the instructions in the Carl Tashian guide for how to import the keys onto the yubikey. You might need to install -yubikey-manager (ie ykman) and pcscd

                  - -

                  https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/#import-the-ca-into-the-yubikey

                  - -

                  Remove pcscd from the bare metal machine. Other cleanup

                  - -

                  Uninstall the yubikey stuff after this step. The pcscd service on the host machine will lock up the yubikey to the -host meaning we can’t pass it to the docker container.

                  - -

                  Unmount the encrypted drive. You don’t need it anymore

                  - -

                  Create a skeleton setup without secret keys

                  - -

                  I’m going to assume that the docker mount for your step-ca server will be under /home/pi/docker/mnt/step

                  - -

                  Run the following. Answer the prompts / set CLI variables the same way you answered them before

                  -
                  # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                  +

                  Optional: Set up name contraints

                  Follow the instructions here to setup up name constraints if you’re going to set it up for the root cert. This is probably good practice. If you don’t use name constraints and your CA is hijacked, then it can issue certs for any domains (ie google.com). Usually name constraints are set on the intermediate cert but for custom TLDs and internal stuff, constraining the root cert is acceptable and is the only way to show clients that you’re not going to sign for stuff you don’t own (ie google.com).

                  I use an internal TLD. You should set the permitted domains to also include the one you use for emails or else I think you could get issues. Ie I setup my name constraints to sign .customtld, mydomain.com (I own this), and .mydomain.com

                  Load the keys onto the yubikey

                  Check the instructions in the Carl Tashian guide for how to import the keys onto the yubikey. You might need to install yubikey-manager (ie ykman) and pcscd

                  https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/#import-the-ca-into-the-yubikey

                  Remove pcscd from the bare metal machine. Other cleanup

                  Uninstall the yubikey stuff after this step. The pcscd service on the host machine will lock up the yubikey to the host meaning we can’t pass it to the docker container.

                  Unmount the encrypted drive. You don’t need it anymore

                  Create a skeleton setup without secret keys

                  I’m going to assume that the docker mount for your step-ca server will be under /home/pi/docker/mnt/step

                  Run the following. Answer the prompts / set CLI variables the same way you answered them before

                  # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                   docker pull smallstep/step-ca:hsm
                   docker run -it -v /home/pi/docker/mnt/step/:/home/step smallstep/step-ca:hsm step ca init --remote-management
                   # Follow the prompt the same way you filled out before
                  @@ -265,10 +52,7 @@ 

                  Create a skeleton setup wit rm -rf /home/pi/docker/mnt/secrets/* cp /mnt/usb/config/* /home/pi/docker/mnt/step/config/ cp /mnt/usb/certs/* /home/pi/docker/mnt/step/certs/ -

                  - -

                  Edit the file in config/ca.json to read something like. Edit values where appropriate

                  -
                  {
                  +

                  Edit the file in config/ca.json to read something like. Edit values where appropriate

                  {
                           "root": "/home/pi/docker/mnt/step/certs/root_ca.crt",
                           "federatedRoots": [],
                           "crt": "/home/pi/docker/mnt/step/certs/intermediate_ca.crt",
                  @@ -279,259 +63,23 @@ 

                  Create a skeleton setup wit }, "address": ":443" // [...] -

                  - -

                  At this point, we’re fully setup to run the cert auth

                  - -

                  Random stuff

                  - -

                  You need a password file. It’s just a thing the docker entrypoint for step-ca expects.

                  - -
                  touch /home/pi/docker/mnt/step/secrets/password
                  -
                  - -

                  Start step-ca and pass Yubikey

                  - -

                  ***I’m hoping that this section becomes fixed in the future. Track the PR here: ***

                  - -

                  Clone the repo github.com/smallstep/certificates.git. Copy docker/Dockerfile.hsm to repo root.

                  - -

                  So there’s a bug as of the writing of this guide 07/25/23. The issue is that the user step in the container doesn’t -have adequate permission to run pcscd service. Thus you’re going to need to include these 3 lines in the Dockerfile

                  -
                  # Change the first line to use golang:bullseye. Otherwise it might not build right on your RPI due to GLibC versioning issues
                  +

                  At this point, we’re fully setup to run the cert auth

                  Random stuff

                  You need a password file. It’s just a thing the docker entrypoint for step-ca expects.

                  touch /home/pi/docker/mnt/step/secrets/password
                  +

                  Start step-ca and pass Yubikey

                  **_I’m hoping that this section becomes fixed in the future. Track the PR here: _**

                  Clone the repo github.com/smallstep/certificates.git. Copy docker/Dockerfile.hsm to repo root.

                  So there’s a bug as of the writing of this guide 07/25/23. The issue is that the user step in the container doesn’t have adequate permission to run pcscd service. Thus you’re going to need to include these 3 lines in the Dockerfile

                  # Change the first line to use golang:bullseye. Otherwise it might not build right on your RPI due to GLibC versioning issues
                   # If we're building on the rpi, this ensures we have the right glibc version.
                   # You may need to adjust as raspbian moves to newer versions
                  -FROM golang:bullseye AS builder  
                  +FROM golang:bullseye AS builder
                   
                   # Insert this after `RUN chown step:step /run/pcscd` but before `USER step`
                   RUN groupadd pcscd          # Create the pcscd group
                   RUN usermod -aG pcscd step  # Adds the user step to pcscd group
                  -
                  - -

                  Then build this image and launch

                  -
                  # Execute the following from repo root
                  +

                  Then build this image and launch

                  # Execute the following from repo root
                   docker build --no-cache -t some-catchy-name:hsm . # build docker image
                   
                   # You can figure out the bus and usb id via `lsusb` command. This does tend to change when you unplug and replug. You can
                  -# maybe use udevadm to set up a symlink. See the Carl Tashian guide for that setup. I think passing the --privileged 
                  +# maybe use udevadm to set up a symlink. See the Carl Tashian guide for that setup. I think passing the --privileged
                   # flag will let the contianer access all devices
                   docker run -d -p 443:443 -v /home/pi/docker/mnt/step:/home/step --device /dev/bus/usb/001/008:/dev/bus/usb/001/008 some-catchy-name:hsm
                  -
                  - -

                  Messing with the udev rules

                  - -

                  The above should work, but if it doesn’t, try running the container as root user with the option -u 0

                  - -

                  I got mine to work with the step user (in the container) by setting these udev rules in the host. I’m not a udev expert -but I think these changes let pcscd work correctly in the container without the -u 0 option.

                  -
                  # IN file /etc/udev/rules.d/75-yubikey.rules
                  +

                  Messing with the udev rules

                  The above should work, but if it doesn’t, try running the container as root user with the option -u 0

                  I got mine to work with the step user (in the container) by setting these udev rules in the host. I’m not a udev expert but I think these changes let pcscd work correctly in the container without the -u 0 option.

                  # IN file /etc/udev/rules.d/75-yubikey.rules
                   ACTION=="add", SUBSYSTEM=="usb", ENV{PRODUCT}=="1050/406/*", TAG+="systemd", SYMLINK+="yubikey", GROUP="pcscd", MODE="0666", RUN+="/bin/chgrp pcscd $root/$parent"
                   ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="1050/406/*", TAG+="systemd"
                  -
                  - -

                  My image

                  - -

                  You can get a copy of my rpi step-ca image via docker pull andywebservices/step-ca:hsm.

                  - - -
                  -
                  - - - - -
                  -
                  -
                  -
                    - - -

                    Enjoy Reading This Article?

                    -

                    Here are some more articles you might like to read next:

                    - - -
                  • - Reverse Proxies With Custom ACME -
                  • - - - -
                  • - Custom TLD Over Tailscale -
                  • - - - -
                  • - Notes on Arduino GPS Library -
                  • - - - -
                  • - Mosh + Tmux + Copy Paste -
                  • - -
                    - - -
                    -
                    - - -
                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

                    My image

                    You can get a copy of my rpi step-ca image via docker pull andywebservices/step-ca:hsm.




                      Enjoy Reading This Article?

                      Here are some more articles you might like to read next:

                    • Custom TLD Over Tailscale
                    • Reverse Proxies With Custom ACME
                    • Mosh + Tmux + Copy Paste
                    • Notes on Arduino GPS Library
                    • \ No newline at end of file diff --git a/blog/category/tech/index.html b/blog/category/tech/index.html index 49a526a..8af1770 100644 --- a/blog/category/tech/index.html +++ b/blog/category/tech/index.html @@ -1,291 +1 @@ - - - - - - - - - - - - - tech | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      tech

                      -

                      an archive of posts in this category

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + tech | Andrew M. Zhang

                      tech

                      an archive of posts in this category

                      \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index 317513b..46c0c5e 100644 --- a/blog/index.html +++ b/blog/index.html @@ -1,527 +1 @@ - - - - - - - - - - - - - AndyTechTips | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - - - - - -
                      -

                      Andy Tech Tips

                      -

                      Random tech stuff with minimal use cases.

                      -
                      - - - -
                      - -
                      - - - - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + blog | Andrew M. Zhang

                      Andy Tech Tips

                      Random tech stuff with minimal use cases.

                      \ No newline at end of file diff --git a/blog/tag/andywebservices/index.html b/blog/tag/andywebservices/index.html index 4bebba8..62bd167 100644 --- a/blog/tag/andywebservices/index.html +++ b/blog/tag/andywebservices/index.html @@ -1,284 +1 @@ - - - - - - - - - - - - - AndyWebServices | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      AndyWebServices

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + AndyWebServices | Andrew M. Zhang

                      AndyWebServices

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/arduino-sim808/index.html b/blog/tag/arduino-sim808/index.html index 1595919..6aa0636 100644 --- a/blog/tag/arduino-sim808/index.html +++ b/blog/tag/arduino-sim808/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - arduino-sim808 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      arduino-sim808

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + arduino-sim808 | Andrew M. Zhang

                      arduino-sim808

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/arduino/index.html b/blog/tag/arduino/index.html index 86a0318..92d8020 100644 --- a/blog/tag/arduino/index.html +++ b/blog/tag/arduino/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - arduino | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      arduino

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + arduino | Andrew M. Zhang

                      arduino

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/authority/index.html b/blog/tag/authority/index.html index 9c01916..353d207 100644 --- a/blog/tag/authority/index.html +++ b/blog/tag/authority/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - Authority | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      Authority

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Authority | Andrew M. Zhang

                      Authority

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/certificate/index.html b/blog/tag/certificate/index.html index 9199ccb..35d5c8f 100644 --- a/blog/tag/certificate/index.html +++ b/blog/tag/certificate/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - Certificate | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      Certificate

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Certificate | Andrew M. Zhang

                      Certificate

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/dfrobot/index.html b/blog/tag/dfrobot/index.html index ef5c053..15bc7c5 100644 --- a/blog/tag/dfrobot/index.html +++ b/blog/tag/dfrobot/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - DFRobot | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      DFRobot

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + DFRobot | Andrew M. Zhang

                      DFRobot

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/gps/index.html b/blog/tag/gps/index.html index d0ca10a..3ec8a08 100644 --- a/blog/tag/gps/index.html +++ b/blog/tag/gps/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - GPS | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      GPS

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + GPS | Andrew M. Zhang

                      GPS

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/network/index.html b/blog/tag/network/index.html index 2aeecbc..955cae1 100644 --- a/blog/tag/network/index.html +++ b/blog/tag/network/index.html @@ -1,277 +1 @@ - - - - - - - - - - - - - network | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      network

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + network | Andrew M. Zhang

                      network

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/sim808/index.html b/blog/tag/sim808/index.html index 8286fca..fc83efd 100644 --- a/blog/tag/sim808/index.html +++ b/blog/tag/sim808/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - SIM808 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      SIM808

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + SIM808 | Andrew M. Zhang

                      SIM808

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/smallstep/index.html b/blog/tag/smallstep/index.html index 4b76778..994550c 100644 --- a/blog/tag/smallstep/index.html +++ b/blog/tag/smallstep/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - smallstep | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      smallstep

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + smallstep | Andrew M. Zhang

                      smallstep

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/ssl/index.html b/blog/tag/ssl/index.html index 0b557e1..4f97e97 100644 --- a/blog/tag/ssl/index.html +++ b/blog/tag/ssl/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - SSL | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      SSL

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + SSL | Andrew M. Zhang

                      SSL

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/step-ca/index.html b/blog/tag/step-ca/index.html index db85f9e..54c8026 100644 --- a/blog/tag/step-ca/index.html +++ b/blog/tag/step-ca/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - step-ca | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      step-ca

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + step-ca | Andrew M. Zhang

                      step-ca

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/tailscale/index.html b/blog/tag/tailscale/index.html index d8b5a95..be44834 100644 --- a/blog/tag/tailscale/index.html +++ b/blog/tag/tailscale/index.html @@ -1,277 +1 @@ - - - - - - - - - - - - - Tailscale | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      Tailscale

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Tailscale | Andrew M. Zhang

                      Tailscale

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/blog/tag/yubikey/index.html b/blog/tag/yubikey/index.html index 6d07025..9ed356d 100644 --- a/blog/tag/yubikey/index.html +++ b/blog/tag/yubikey/index.html @@ -1,270 +1 @@ - - - - - - - - - - - - - Yubikey | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - -
                      - -
                      -

                      Yubikey

                      -

                      an archive of posts with this tag

                      -
                      - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Yubikey | Andrew M. Zhang

                      Yubikey

                      an archive of posts with this tag

                      \ No newline at end of file diff --git a/cv/index.html b/cv/index.html new file mode 100644 index 0000000..b6c159a --- /dev/null +++ b/cv/index.html @@ -0,0 +1 @@ + cv | Andrew M. Zhang

                      cv

                      This is a description of the page. You can modify it in '_pages/cv.md'. You can also change or remove the top pdf download button.

                      Basics

                      Name Albert Einstein
                      Label Scientist
                      Email albert@einstein.de
                      Phone (912) 123-4567
                      Url https://alshedivat.github.io/al-folio/
                      Summary A German-born theoretical physicist, widely ranked among the greatest and most influential scientists of all time

                      Work

                      • 1933.01 - 1955.01
                        Professor of Theoretical Physics
                        Institute for Advanced Study, Princeton University
                        Teaching at Palmer Physical Laboratory (now 302 Frist Campus Center). While not a professor at Princeton, I associated with the physics professors and continued to give lectures on campus.
                        • Relativity

                      Volunteer

                      • 2014.04 - 2015.07

                        Zurich, Switzerland

                        Lead Organizer
                        People's Climate March
                        Lead organizer for the New York City branch of the People's Climate March, the largest climate march in history.
                        • Awarded 'Climate Hero' award by Greenpeace for my efforts organizing the march.
                        • Men of the year 2014 by Time magazine

                      Education

                      • 1905.01 - 1905.01

                        Zurich, Switzerland

                        PhD
                        University of Zurich, Zurich, Switzerland
                        Software Development
                        • Theory of Relativity

                      Awards

                      • 1921.11.01
                        Nobel Prize in Physics
                        Royal Swedish Academy of Sciences
                        The Nobel Prizes are five separate prizes that, according to Alfred Nobel's will of 1895, are awarded to 'those who, during the preceding year, have conferred the greatest benefit to humankind.'

                      Certificates

                      Quantum Teleportation
                      Stanford University 2018-01-01
                      Quantum Communication
                      Stanford University 2018-01-01
                      Quantum Cryptography
                      Stanford University 2018-01-01
                      Quantum Information
                      Stanford University 2018-01-01
                      Quantum Computing
                      Stanford University 2018-01-01
                      Machine Learning
                      Stanford University 2018-01-01

                      Publications

                      • 1916.03.20
                        Die Grundlage der allgemeinen Relativitätstheorie
                        Annalen der Physik
                        The publication of the theory of general relativity made him internationally famous. He was professor of physics at the universities of Zurich (1909–1911) and Prague (1911–1912), before he returned to ETH Zurich (1912–1914).
                      • 1905.06.30
                        Zur Elektrody/namik bewegter Körper
                        Annalen der Physik
                        It concerned an interpretation of the Michelson–Morley experiment and the properties of light and time. Special relativity incorporates the principle that the speed of light is the same for all inertial observers regardless of the state of motion of the source.
                      • 1905.03.18
                        Über einen die Erzeugung und Verwandlung des Lichtes betreffenden heuristischen Gesichtspunkt
                        Annalen der Physik
                        In the second paper, he applied the quantum theory to light to explain the photoelectric effect. In particular, he used the idea of light quanta (photons) to explain experimental results, but stressed the importance of the experimental results. The importance of his work on the photoelectric effect earned him the Nobel Prize in Physics in 1921.

                      Skills

                      Physics
                      Quantum Mechanics
                      Quantum Computing
                      Quantum Information
                      Quantum Cryptography
                      Quantum Communication
                      Quantum Teleportation

                      Languages

                      German
                      Native speaker
                      English
                      Fluent

                      Interests

                      Physics
                      Quantum Mechanics
                      Quantum Computing
                      Quantum Information
                      Quantum Cryptography
                      Quantum Communication
                      Quantum Teleportation

                      References

                      Professor John Doe
                      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam condimentum, diam quis convallis euismod, arcu mi ullamcorper lorem, a vestibulum nunc magna at sem. Sed in risus ac felis varius blandit. D
                      Professor John Doe
                      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam condimentum, diam quis convallis euismod, arcu mi ullamcorper lorem, a vestibulum nunc magna at sem. Sed in risus ac felis varius blandit. D

                      Projects

                      • 2018.01 - 2018.01
                        Quantum Computing
                        Quantum computing is the use of quantum-mechanical phenomena such as superposition and entanglement to perform computation. Computers that perform quantum computations are known as quantum computers.
                        • Quantum Teleportation
                        • Quantum Cryptography
                      \ No newline at end of file diff --git a/feed.xml b/feed.xml index d345cf3..69cc6d6 100644 --- a/feed.xml +++ b/feed.xml @@ -1,41 +1,4 @@ -Jekyll2024-04-28T19:57:26+00:00https://andrewmzhang.com/feed.xmlblankPersonal site of Andrew Zhang -Running step-ca in docker w/ Yubikey2023-07-24T00:00:00+00:002023-07-24T00:00:00+00:00https://andrewmzhang.com/blog/2023/running-step-ca-in-docker-w-yubikeyAbstract - -

                      Carl Tashian of Smallstep wrote a blog post regarding Building a Tiny Certificate Authority For Your Homelab. -This guide provides very complete instructions on how to install a step-ca certificate authority on a Raspberry Pi 4 -and how to store the private keys securely on a Yubikey. This post is written assuming familiarity with this guide. -Namely, be familiar with the process of running the step ca init twice, once to setup the private keys off-host (ie usb) -, then again to setup the directory structure. Certs must then be copied from the off-host device to the directory -structure. Private keys on the off-host device are loaded into a Yubikey.

                      - -

                      The only problem is I like using Docker and I generally dislike running stuff on bare metal. Unfortunately, there are -not any clear instructions on how to use the smallstep/step-ca:hsm image with a Raspberry Pi with a Yubikey. My guide -will roughly follow the same steps except using docker.

                      - -

                      NOTE There is currently a bug in step-ca’s dockerfile.hsm. See the final step of the guide for a quick fix.

                      - -

                      Read the following to understand the parts of a PKI https://smallstep.com/blog/everything-pki/

                      - -

                      Requirements

                      -
                        -
                      • Rpi
                      • -
                      • Yubikey
                      • -
                      • USB stick
                      • -
                      - -

                      Setup Rpi

                      - -

                      I tried this using both Ubuntu and Raspbian on Rpi. I think it’ll work on any Rpi OS that supports Docker. Do whatever -you need to do to install Docker.

                      - -

                      Setup Root and Intermediate keys onto USB stick

                      - -

                      The goal is to have the root and intermediate keys on a USB stick, just like in Carl’s guide. Though, I recommend -using a LUKS encrypted USB stick to hold the keys. You can steal the commands for setting that up here: https://github.com/drduh/YubiKey-Guide#backup

                      - -

                      For the remainder of the guide I’ll assume your usb, encrypted or otherwise, is mounted here /mnt/usb/

                      - -
                      # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                      +Jekyll2024-04-28T21:40:38+00:00https://andrewmzhang.com/feed.xmlblankPersonal site of Andrew Zhang Running step-ca in docker w/ Yubikey2023-07-24T00:00:00+00:002023-07-24T00:00:00+00:00https://andrewmzhang.com/blog/2023/running-step-ca-in-docker-w-yubikeyAbstract 

                      Carl Tashian of Smallstep wrote a blog post regarding Building a Tiny Certificate Authority For Your Homelab. This guide provides very complete instructions on how to install a step-ca certificate authority on a Raspberry Pi 4 and how to store the private keys securely on a Yubikey. This post is written assuming familiarity with this guide. Namely, be familiar with the process of running the step ca init twice, once to setup the private keys off-host (ie usb) , then again to setup the directory structure. Certs must then be copied from the off-host device to the directory structure. Private keys on the off-host device are loaded into a Yubikey.

                      The only problem is I like using Docker and I generally dislike running stuff on bare metal. Unfortunately, there are not any clear instructions on how to use the smallstep/step-ca:hsm image with a Raspberry Pi with a Yubikey. My guide will roughly follow the same steps except using docker.

                      NOTE There is currently a bug in step-ca’s dockerfile.hsm. See the final step of the guide for a quick fix.

                      Read the following to understand the parts of a PKI https://smallstep.com/blog/everything-pki/

                      Requirements

                      • Rpi
                      • Yubikey
                      • USB stick

                      Setup Rpi

                      I tried this using both Ubuntu and Raspbian on Rpi. I think it’ll work on any Rpi OS that supports Docker. Do whatever you need to do to install Docker.

                      Setup Root and Intermediate keys onto USB stick

                      The goal is to have the root and intermediate keys on a USB stick, just like in Carl’s guide. Though, I recommend using a LUKS encrypted USB stick to hold the keys. You can steal the commands for setting that up here: https://github.com/drduh/YubiKey-Guide#backup

                      For the remainder of the guide I’ll assume your usb, encrypted or otherwise, is mounted here /mnt/usb/

                      # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                       
                       docker pull smallstep/step-ca:hsm
                       
                      @@ -47,9 +10,9 @@ there is no ca.json config file; please run step ca init,
                       ✔ Deployment Type: Standalone                                                   # Select Standalone
                       What would you like to name your new PKI?
                       ✔ (e.g. Smallstep): TinyCA                                                      # Give it a name. This will appear in yoru certs
                      -What DNS names or IP addresses will clients use to reach your CA?               
                      +What DNS names or IP addresses will clients use to reach your CA?
                       ✔ (e.g. ca.example.com[,10.1.2.3,etc.]): ca.internal,192.168.0.101,10.10.10.10  # You can list a bunch of these. Values can be adjusted layer in /mnt/usb/config/ca.json
                      -What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)      
                      +What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)(e.g. :443 or 127.0.0.1:443): :443                                            # You probably want :443(e.g. you@smallstep.com): email@example.com                                   # Your email
                       Choose a password for your CA keys and first provisioner.
                      @@ -80,38 +43,7 @@ FEEDBACK 😍 🍻
                         good or bad at feedback@smallstep.com or join GitHub Discussions
                         https://github.com/smallstep/certificates/discussions and our Discord
                         https://u.step.sm/discord.
                      -
                      - -

                      Optional: Set up name contraints

                      - -

                      Follow the instructions here to setup up name constraints if you’re going to set it up for the root cert. This is probably -good practice. If you don’t use name constraints and your CA is hijacked, then it can issue certs for any domains (ie google.com). -Usually name constraints are set on the intermediate cert but for custom TLDs and internal stuff, constraining the -root cert is acceptable and is the only way to show clients that you’re not going to sign for stuff you don’t own (ie google.com).

                      - -

                      I use an internal TLD. You should set the permitted domains to also include the one you use for emails or else I think -you could get issues. Ie I setup my name constraints to sign .customtld, mydomain.com (I own this), and .mydomain.com

                      - -

                      Load the keys onto the yubikey

                      - -

                      Check the instructions in the Carl Tashian guide for how to import the keys onto the yubikey. You might need to install -yubikey-manager (ie ykman) and pcscd

                      - -

                      https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/#import-the-ca-into-the-yubikey

                      - -

                      Remove pcscd from the bare metal machine. Other cleanup

                      - -

                      Uninstall the yubikey stuff after this step. The pcscd service on the host machine will lock up the yubikey to the -host meaning we can’t pass it to the docker container.

                      - -

                      Unmount the encrypted drive. You don’t need it anymore

                      - -

                      Create a skeleton setup without secret keys

                      - -

                      I’m going to assume that the docker mount for your step-ca server will be under /home/pi/docker/mnt/step

                      - -

                      Run the following. Answer the prompts / set CLI variables the same way you answered them before

                      -
                      # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                      +

                      Optional: Set up name contraints

                      Follow the instructions here to setup up name constraints if you’re going to set it up for the root cert. This is probably good practice. If you don’t use name constraints and your CA is hijacked, then it can issue certs for any domains (ie google.com). Usually name constraints are set on the intermediate cert but for custom TLDs and internal stuff, constraining the root cert is acceptable and is the only way to show clients that you’re not going to sign for stuff you don’t own (ie google.com).

                      I use an internal TLD. You should set the permitted domains to also include the one you use for emails or else I think you could get issues. Ie I setup my name constraints to sign .customtld, mydomain.com (I own this), and .mydomain.com

                      Load the keys onto the yubikey

                      Check the instructions in the Carl Tashian guide for how to import the keys onto the yubikey. You might need to install yubikey-manager (ie ykman) and pcscd

                      https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/#import-the-ca-into-the-yubikey

                      Remove pcscd from the bare metal machine. Other cleanup

                      Uninstall the yubikey stuff after this step. The pcscd service on the host machine will lock up the yubikey to the host meaning we can’t pass it to the docker container.

                      Unmount the encrypted drive. You don’t need it anymore

                      Create a skeleton setup without secret keys

                      I’m going to assume that the docker mount for your step-ca server will be under /home/pi/docker/mnt/step

                      Run the following. Answer the prompts / set CLI variables the same way you answered them before

                      # modified from `Manual Installation` here https://hub.docker.com/r/smallstep/step-ca
                       docker pull smallstep/step-ca:hsm
                       docker run -it -v /home/pi/docker/mnt/step/:/home/step smallstep/step-ca:hsm step ca init --remote-management
                       # Follow the prompt the same way you filled out before
                      @@ -120,10 +52,7 @@ docker run -it -v /home/pi/docke
                       rm -rf /home/pi/docker/mnt/secrets/*
                       cp /mnt/usb/config/* /home/pi/docker/mnt/step/config/
                       cp /mnt/usb/certs/* /home/pi/docker/mnt/step/certs/
                      -
                      - -

                      Edit the file in config/ca.json to read something like. Edit values where appropriate

                      -
                      {
                      +

                      Edit the file in config/ca.json to read something like. Edit values where appropriate

                      {
                               "root": "/home/pi/docker/mnt/step/certs/root_ca.crt",
                               "federatedRoots": [],
                               "crt": "/home/pi/docker/mnt/step/certs/intermediate_ca.crt",
                      @@ -134,86 +63,26 @@ docker run -it -v /home/pi/docke
                               },
                               "address": ":443"
                       // [...]
                      -
                      - -

                      At this point, we’re fully setup to run the cert auth

                      - -

                      Random stuff

                      - -

                      You need a password file. It’s just a thing the docker entrypoint for step-ca expects.

                      - -
                      touch /home/pi/docker/mnt/step/secrets/password
                      -
                      - -

                      Start step-ca and pass Yubikey

                      - -

                      ***I’m hoping that this section becomes fixed in the future. Track the PR here: ***

                      - -

                      Clone the repo github.com/smallstep/certificates.git. Copy docker/Dockerfile.hsm to repo root.

                      - -

                      So there’s a bug as of the writing of this guide 07/25/23. The issue is that the user step in the container doesn’t -have adequate permission to run pcscd service. Thus you’re going to need to include these 3 lines in the Dockerfile

                      -
                      # Change the first line to use golang:bullseye. Otherwise it might not build right on your RPI due to GLibC versioning issues
                      +

                      At this point, we’re fully setup to run the cert auth

                      Random stuff

                      You need a password file. It’s just a thing the docker entrypoint for step-ca expects.

                      touch /home/pi/docker/mnt/step/secrets/password
                      +

                      Start step-ca and pass Yubikey

                      **_I’m hoping that this section becomes fixed in the future. Track the PR here: _**

                      Clone the repo github.com/smallstep/certificates.git. Copy docker/Dockerfile.hsm to repo root.

                      So there’s a bug as of the writing of this guide 07/25/23. The issue is that the user step in the container doesn’t have adequate permission to run pcscd service. Thus you’re going to need to include these 3 lines in the Dockerfile

                      # Change the first line to use golang:bullseye. Otherwise it might not build right on your RPI due to GLibC versioning issues
                       # If we're building on the rpi, this ensures we have the right glibc version.
                       # You may need to adjust as raspbian moves to newer versions
                      -FROM golang:bullseye AS builder  
                      +FROM golang:bullseye AS builder
                       
                       # Insert this after `RUN chown step:step /run/pcscd` but before `USER step`
                       RUN groupadd pcscd          # Create the pcscd group
                       RUN usermod -aG pcscd step  # Adds the user step to pcscd group
                      -
                      - -

                      Then build this image and launch

                      -
                      # Execute the following from repo root
                      +

                      Then build this image and launch

                      # Execute the following from repo root
                       docker build --no-cache -t some-catchy-name:hsm . # build docker image
                       
                       # You can figure out the bus and usb id via `lsusb` command. This does tend to change when you unplug and replug. You can
                      -# maybe use udevadm to set up a symlink. See the Carl Tashian guide for that setup. I think passing the --privileged 
                      +# maybe use udevadm to set up a symlink. See the Carl Tashian guide for that setup. I think passing the --privileged
                       # flag will let the contianer access all devices
                       docker run -d -p 443:443 -v /home/pi/docker/mnt/step:/home/step --device /dev/bus/usb/001/008:/dev/bus/usb/001/008 some-catchy-name:hsm
                      -
                      - -

                      Messing with the udev rules

                      - -

                      The above should work, but if it doesn’t, try running the container as root user with the option -u 0

                      - -

                      I got mine to work with the step user (in the container) by setting these udev rules in the host. I’m not a udev expert -but I think these changes let pcscd work correctly in the container without the -u 0 option.

                      -
                      # IN file /etc/udev/rules.d/75-yubikey.rules
                      +

                      Messing with the udev rules

                      The above should work, but if it doesn’t, try running the container as root user with the option -u 0

                      I got mine to work with the step user (in the container) by setting these udev rules in the host. I’m not a udev expert but I think these changes let pcscd work correctly in the container without the -u 0 option.

                      # IN file /etc/udev/rules.d/75-yubikey.rules
                       ACTION=="add", SUBSYSTEM=="usb", ENV{PRODUCT}=="1050/406/*", TAG+="systemd", SYMLINK+="yubikey", GROUP="pcscd", MODE="0666", RUN+="/bin/chgrp pcscd $root/$parent"
                       ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="1050/406/*", TAG+="systemd"
                      -
                      - -

                      My image

                      - -

                      You can get a copy of my rpi step-ca image via docker pull andywebservices/step-ca:hsm.

                      ]]>
                      Andrew M. Zhang
                      Reverse Proxies With Custom ACME2023-05-25T00:00:00+00:002023-05-25T00:00:00+00:00https://andrewmzhang.com/blog/2023/reverse-proxies-with-custom-acmeIntro -

                      This page assumes that you have some custom ACME server (see previous post) and you want a reverse proxy (eg Nginx, HaProxy) to use it to generate certs automatically.

                      - -

                      SWAG - docker-swag official

                      - -
                        -
                      1. Dockerhub image: andywebservices/swag
                      2. -
                      - -

                      Explanation

                      -

                      At time of writing, docker-swag main branch does not support custom ACME servers. Fortunately for the dear reader, I have graciously implemented this feature andrewmzhang/docker-swag. It’s probably easier to see how the feature works by looking at the diff. This feature introduces 2 new environment variables. One sets the ACME server and the other sets the CABUNDLE. The CABUNDLE is required so that docker trusts the certificate authority without having to install the certificate to the OS truststore, although I still recommend installing the certificate to your OS truststore.

                      - -

                      Docker-swag is a complete solution. It’ll renew the certificates once a day and refresh Nginx service to pick up the new certs.

                      - -

                      HAProxy + ACME.sh - haproxy

                      -

                      Issues

                      -

                      EDIT: This section was updated on 2024-04-17. The previous instructions were out of date

                      - -

                      HAProxy suffers several issues.

                      -
                        -
                      1. It cannot provision its own SSL certs, ie it cannot do the ACME dance
                      2. -
                      3. It hogs port 80 and 443, in order for 3rd party acme to work correctly the acme program needs 80 and 443.
                      4. -
                      5. It demands that the SSL privkey be in the same file as the cert bundle
                      6. -
                      7. It cannot tell if the SSL cert has changed on disk, thus users need to send commands to get HAProxy to refresh the certs
                      8. -
                      - -

                      Fortunately, acme.sh has some helpers that make this procedure relatively painless

                      -
                      # Register an account thumbprint. This will produce a thumbprint. Copy that value
                      +

                      My image

                      You can get a copy of my rpi step-ca image via docker pull andywebservices/step-ca:hsm.

                      ]]>
                      Andrew M. Zhang
                      Reverse Proxies With Custom ACME2023-05-25T00:00:00+00:002023-05-25T00:00:00+00:00https://andrewmzhang.com/blog/2023/reverse-proxies-with-custom-acmeIntro

                      This page assumes that you have some custom ACME server (see previous post) and you want a reverse proxy (eg Nginx, HaProxy) to use it to generate certs automatically.

                      SWAG - docker-swag official

                      1. Dockerhub image: andywebservices/swag

                      Explanation

                      At time of writing, docker-swag main branch does not support custom ACME servers. Fortunately for the dear reader, I have graciously implemented this feature andrewmzhang/docker-swag. It’s probably easier to see how the feature works by looking at the diff. This feature introduces 2 new environment variables. One sets the ACME server and the other sets the CABUNDLE. The CABUNDLE is required so that docker trusts the certificate authority without having to install the certificate to the OS truststore, although I still recommend installing the certificate to your OS truststore.

                      Docker-swag is a complete solution. It’ll renew the certificates once a day and refresh Nginx service to pick up the new certs.

                      HAProxy + ACME.sh - haproxy

                      Issues

                      EDIT: This section was updated on 2024-04-17. The previous instructions were out of date

                      HAProxy suffers several issues.

                      1. It cannot provision its own SSL certs, ie it cannot do the ACME dance
                      2. It hogs port 80 and 443, in order for 3rd party acme to work correctly the acme program needs 80 and 443.
                      3. It demands that the SSL privkey be in the same file as the cert bundle
                      4. It cannot tell if the SSL cert has changed on disk, thus users need to send commands to get HAProxy to refresh the certs

                      Fortunately, acme.sh has some helpers that make this procedure relatively painless

                      # Register an account thumbprint. This will produce a thumbprint. Copy that value
                       ./acme.sh --register-account --server https://step-ca.internal/acme/acme/directory -m myemail@example.com
                       
                       # Edit the following into /etc/haproxy/haproxy.cfg
                      @@ -225,233 +94,36 @@ global
                       frontend public
                               bind :::80 v4v6
                               bind :::443 v4v6 ssl crt /etc/haproxy/certs/ strict-sni  # This allows haproxy to boot without certs, which you wont have initially
                      -        # The directive below means when the certificate authority navigates to my.domain.internal/.well-known/acme-challenge/ HAProxy will reply with the account thumbprint 
                      +        # The directive below means when the certificate authority navigates to my.domain.internal/.well-known/acme-challenge/ HAProxy will reply with the account thumbprint
                               http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_beg '/.well-known/acme-challenge/' }
                       
                       # Do the ACME dance, ACME will write some config files under ~/.acme.sh/mydomain.internal_ecc. Note the deploy-hook and --days 1
                       ./acme.sh --stateless --issue -d my.domain.internal --server https://step-ca.internal/acme/acme/directory --ca-bundle ~/my_root_ca.crt --deploy --deploy-hook haproxy --days 1
                       # Remember to update cron
                       ./acme.sh --install-cronjob
                      -
                      - -

                      Remember to check the .acme.sh config files, namely the Le_RenewalDays value. It defaults to 60 days, but step-ca certs default expires in 1 day, so you’ll need to mess with this value

                      - -

                      Resources

                      -
                        -
                      1. https://www.haproxy.com/blog/haproxy-and-let-s-encrypt
                      2. -
                      ]]>
                      Andrew M. Zhang
                      Custom TLD Over Tailscale2023-05-17T00:00:00+00:002023-05-17T00:00:00+00:00https://andrewmzhang.com/blog/2023/custom-tldNote: It’s like 2am and I was too sleepy to edit this, so I fed it through chatGPT and called it a day. I think it -made some minor mistakes and poor word choice. I’ll fix it tomorrow or something…

                      - -

                      Intro

                      - -

                      Tailscale is a Wireguard-based VPN software that I rely on for secure and remote access across my devices. I appreciate -its remarkably minimal setup process - simply installing Tailscale on a device grants it access to the VPN, with the -software taking care of the rest. However, one inconvenience I encountered was the built-in DNS’s limitation of -resolving device hostnames without a TLD. For instance, if I add a machine with the hostname machineA, I can access -webpages hosted on it via https://machineA, but unfortunately, Tailscale DNS does not support setting the domain to -something like https://machineA.ctld. This page documents my solution to implementing a private TLD over a Tailscale -network.

                      - -

                      I am committed to using TLS because I value the green lock symbol and the assurance it provides. It is crucial for my -setup to appear legitimate; otherwise, people may doubt the credibility of AndyWebServices El El Sí as a legitimate -company. This credibility is essential for attracting investors and achieving a valuation of 100 trillion.

                      - -

                      To clarify. These are the requirements:

                      - -
                        -
                      • Any and only devices connected by my Tailscale network should be able to access the custom tld network
                      • -
                      • I intend to use a custom TLD format, such as hostname.ctld. For the purpose of this guide, I will use .ctld as the -TLD.
                      • -
                      • HTTPS functionality
                      • -
                      - -

                      Resolving a custom TLD over Tailscale

                      - -

                      Resolving custom TLD

                      - -

                      Tailscale facilitates secure connections between devices within the Tailscale network. Each device on the Tailscale -network is assigned a static Tailscale IP (100.xx.yy.zz) along with a non-TLD domain. The resolution of this non-TLD -domain is handled by a local DNS resolver that is included with the Tailscale installation.

                      - -

                      To incorporate a custom TLD into this setup, the first step is to set up a dedicated DNS server to resolve *.ctld -domains. I recommend following the setup outlined below:

                      - -
                        -
                      1. Obtain a Raspberry Pi device. -
                          -
                        1. If you intend to replicate my network setup, install and configure Ubuntu on the Raspberry Pi.
                        2. -
                        -
                      2. -
                      3. Connect the Raspberry Pi to the Tailscale (TS) network. For the sake of this guide, let’s assume it is assigned the -TS IP address 100.100.100.101.
                      4. -
                      5. Install and set up dnsmasq on the Raspberry Pi.
                      6. -
                      7. Edit the /etc/hosts file on the Raspberry Pi to manually define the DNS entries. -
                          -
                        1. In case you are using the default Ubuntu installation, you may need to modify the cloud-init template. Please -refer to the comments in your /etc/hosts file for guidance.
                        2. -
                        3. The entries in the /etc/hosts file should resemble the following format:
                        4. -
                        -
                      8. -
                      - -
                      # /etc/hosts
                      +

                      Remember to check the .acme.sh config files, namely the Le_RenewalDays value. It defaults to 60 days, but step-ca certs default expires in 1 day, so you’ll need to mess with this value

                      Resources

                      1. https://www.haproxy.com/blog/haproxy-and-let-s-encrypt
                      ]]>
                      Andrew M. Zhang
                      Custom TLD Over Tailscale2023-05-17T00:00:00+00:002023-05-17T00:00:00+00:00https://andrewmzhang.com/blog/2023/custom-tldNote: It’s like 2am and I was too sleepy to edit this, so I fed it through chatGPT and called it a day. I think it made some minor mistakes and poor word choice. I’ll fix it tomorrow or something…

                      Intro

                      Tailscale is a Wireguard-based VPN software that I rely on for secure and remote access across my devices. I appreciate its remarkably minimal setup process - simply installing Tailscale on a device grants it access to the VPN, with the software taking care of the rest. However, one inconvenience I encountered was the built-in DNS’s limitation of resolving device hostnames without a TLD. For instance, if I add a machine with the hostname machineA, I can access webpages hosted on it via https://machineA, but unfortunately, Tailscale DNS does not support setting the domain to something like https://machineA.ctld. This page documents my solution to implementing a private TLD over a Tailscale network.

                      I am committed to using TLS because I value the green lock symbol and the assurance it provides. It is crucial for my setup to appear legitimate; otherwise, people may doubt the credibility of AndyWebServices El El Sí as a legitimate company. This credibility is essential for attracting investors and achieving a valuation of 100 trillion.

                      To clarify. These are the requirements:

                      • Any and only devices connected by my Tailscale network should be able to access the custom tld network
                      • I intend to use a custom TLD format, such as hostname.ctld. For the purpose of this guide, I will use .ctld as the TLD.
                      • HTTPS functionality

                      Resolving a custom TLD over Tailscale

                      Resolving custom TLD

                      Tailscale facilitates secure connections between devices within the Tailscale network. Each device on the Tailscale network is assigned a static Tailscale IP (100.xx.yy.zz) along with a non-TLD domain. The resolution of this non-TLD domain is handled by a local DNS resolver that is included with the Tailscale installation.

                      To incorporate a custom TLD into this setup, the first step is to set up a dedicated DNS server to resolve *.ctld domains. I recommend following the setup outlined below:

                      1. Obtain a Raspberry Pi device.
                        1. If you intend to replicate my network setup, install and configure Ubuntu on the Raspberry Pi.
                      2. Connect the Raspberry Pi to the Tailscale (TS) network. For the sake of this guide, let’s assume it is assigned the TS IP address 100.100.100.101.
                      3. Install and set up dnsmasq on the Raspberry Pi.
                      4. Edit the /etc/hosts file on the Raspberry Pi to manually define the DNS entries.
                        1. In case you are using the default Ubuntu installation, you may need to modify the cloud-init template. Please refer to the comments in your /etc/hosts file for guidance.
                        2. The entries in the /etc/hosts file should resemble the following format:
                      # /etc/hosts
                       # tailscale_IP hostname
                       myMachineA.ctld 100.100.100.123
                      -
                      - -

                      You only need to perform this setup once since the Tailscale IP is static. Keep in mind that these IPs are only -accessible when connected to the VPN. While it is advisable to configure dnsmasq on your Tailscale network interface, -setting it up on 0.0.0.0 is unlikely to pose a security risk.

                      - -

                      SplitDNS

                      - -

                      We must ensure the proper utilization of the DNS server by devices connected to the Tailscale network. To achieve -this, we will proceed with configuring SplitDNS within the Tailscale Admin Console. Our primary objective is to -establish the resolution of *.ctld to the Tailscale IP address assigned to the DNS server, -specifically 100.100.100.101.

                      - -

                      By implementing this approach, any device that joins the Tailscale Network will seamlessly attempt to utilize the DNS -resolver of the Raspberry Pi (rpi) running dnsmasq, but solely for domains associated with our custom top-level domain ( -ctld). This strategy ensures optimal efficiency, as domain resolutions for standard domains like google.com continue -to -be handled by the local DNS, while requests for *.ctld domains are routed through the Tailscale network’s DNS server, -which may incur a higher latency if our rpi is not nearby.

                      - -

                      TLS Certificates ( The Green Stuff )

                      - -

                      To enable the use of HTTPS without encountering any browser warnings, obtaining TLS certificates is essential. If you -are already familiar with TLS and its intricacies, you may skip the remaining portion of this subsection. However, if -you require a more detailed explanation, there are numerous comprehensive resources available online.

                      - -

                      TLS, which stands for Transport Layer Security, is a crucial component of Private Key Infrastructure (PKI) -framework. When a client and server aim to establish a secure communication channel, the client must be aware of the -server’s public key. While the DNS server provides the IP address of machineA.ctld, it does not verify the legitimacy -of the server’s public key. TLS ensures that the key has not been tampered with or maliciously -altered during transit over the network. While communications between Tailscale (TS) devices are considered secure, the -broader internet cannot make such assumptions. Therefore, without the server’s public key, secure communication becomes -impossible. This is where TLS certificates come into play.

                      - -

                      A TLS certificate is an attestation signed by a trusted entity known as a Certificate Authority (CA). It asserts that a -specific public key belongs to machineA.ctld. Understanding the three levels of TLS certificates is -important. First, the root certificate is a self-signed certificate that contains the public key of the CA. This root -certificate must be installed on all machines requiring TLS functionality for our custom TLD. The private key used to -sign the root certificate is typically kept offline in cold storage, as recovery from a compromised root key is -impossible, -eg you can’t sign a revocation if your private key cannot be trusted.

                      - -

                      The intermediate certificate is signed by the root certificate and is responsible for signing leaf certificates. Unlike -the root certificate, the private key of the intermediate certificate is usually kept online since it is required to -sign leaf certificates. If an intermediate certificate becomes compromised or expires, the root private key can be -brought out of cold storage to issue a revocation.

                      - -

                      The leaf or end certificate, which is presented by machineA.ctld, serves as proof that its public key is legitimate. -The -intermediate certificate has the authority to revoke leaf certificates if machineA.ctld exhibits malicious behavior.

                      - -

                      TLS certificates can be generated by the CA and securely transferred to the server using methods like scp. This approach -is particularly useful for devices where running ACME (Automated Certificate Management Environment) properly is not -feasible. Or if the CA cannot establish bi-directional communication with the machine for some reason. ACME provides an -automated mechanism for generating certificate signing requests and validating the domain ownership to the CA.

                      - -

                      By understanding these concepts, we can effectively utilize TLS certificates to establish secure and trusted -communication channels, ensuring the green lock symbol and seamless HTTPS functionality in our browsers.

                      - -

                      ACME

                      - -

                      If you have previous experience with Let’s Encrypt or certbot, then you are likely familiar with the ACME (Automated -Certificate Management Environment) protocol. ACME is a collection of protocols that servers can employ to demonstrate -their ownership of domain names to Certificate Authorities (CAs) when requesting certificates. The primary purpose of a -certificate is to certify that machineA.ctld is indeed the owner of a specific public key.

                      - -

                      ACME offers two verification methods, with the less commonly used method being DNS certification. In this approach, the -client server contacts the ACME server and claims ownership of machineA.ctld. The client server provides a -Certificate Signing Request (CSR) to the ACME server for signing. The ACME server then requests the client server to add -a specific string to the TXT section of the DNS record. If the server genuinely owns machineA.ctld and its authoritative -nameserver supports an API for managing domain records, the server can perform the required operation and have it -verified by the ACME server. However, as we are utilizing dnsmasq as our DNS server, the specific steps for performing -this operation are not within my expertise.

                      - -

                      It is worth noting that the DNS certification method is less common compared to the alternative method, which involves -proving ownership through HTTP-based challenges. This method requires the server to respond to a challenge by placing a -designated file at a specified location on the web server. The ACME server then attempts to access the file to validate -ownership. This approach is generally more straightforward to implement and is not dependent on what API your DNS -provider happens to supply.

                      - -

                      Step CA

                      - -

                      To proceed with setting up an ACME server on a Raspberry Pi, we can follow the guide provided -at https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/. Although the guide incorporates using a -YubiKey for loading keys, it is not necessary for our purposes. However, adhering to proper security practices is always -recommended, and if you have access to YubiKeys, it can enhance the overall security of the setup. I get them for free -at work. There is an option to use the infnoise generator dongle, but we will opt because it costs too much and I don’t -get them for free at work. I recommend you use the same Raspberry Pi you’re hosting the ctld DNS off of. Note that the -ACME server will run on port 443, while the DNS server will operate on port 53, ensuring that there won’t be any -conflicts between the two services.

                      - -

                      During the setup process, remember to modify the domain from tinyca.internal to a domain of your choice with -the .ctld extension, such as ctldca.ctld.

                      - -

                      Once you have completed this step, you will be able to request TLS certificates for your custom domain, allowing you to -establish secure connections using HTTPS.

                      - -

                      Install the root cert

                      - -

                      To ensure that your browser and servers recognize the custom TLD Certificate Authority (CA) and avoid any issues with -certificate verification, install the root certificate into the truststore of your devices. This step -will establish trust in the certificates issued by the custom CA.

                      - -

                      To verify if the installation was successful, you can open a shell or command prompt and execute the -command curl https://machinea.ctld. If you encounter an error 60, it indicates that the CA is not recognized by your -machine, indicating a problem with the root certificate installation.

                      - -

                      For convenience and ease of use, it is recommended to store the root certificate in a cloud drive or a similar storage -solution. This way, you can readily access and install it on new devices whenever necessary.

                      - -

                      Requesting a cert

                      - -

                      You can refer to the guides provided at https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/ for detailed -instructions on setting up various ACME clients. However, if you’re looking for a straightforward and user-friendly -option, I recommend using acme.sh.

                      - -

                      Some pitfalls in cert requesting

                      - -

                      I’ll probably split this off into separate guides when I get the chance.

                      - -

                      HAProxy

                      - -

                      Certain reverse proxies, such as HAProxy, will require the leaf private key and certificate in one file. If this -is the case you will need to cat the key and cert together. A reverse proxy may also hog port 80 and 443 which are needed to -do the ACME challenge, in which case you will need to carve out a path to the ACME client.

                      - -

                      Here is my setup for HAProxy - it’s my octoprint server:

                      - -
                      # In /etc/haproxy/haproxy.cfg
                      +

                      You only need to perform this setup once since the Tailscale IP is static. Keep in mind that these IPs are only accessible when connected to the VPN. While it is advisable to configure dnsmasq on your Tailscale network interface, setting it up on 0.0.0.0 is unlikely to pose a security risk.

                      SplitDNS

                      We must ensure the proper utilization of the DNS server by devices connected to the Tailscale network. To achieve this, we will proceed with configuring SplitDNS within the Tailscale Admin Console. Our primary objective is to establish the resolution of *.ctld to the Tailscale IP address assigned to the DNS server, specifically 100.100.100.101.

                      By implementing this approach, any device that joins the Tailscale Network will seamlessly attempt to utilize the DNS resolver of the Raspberry Pi (rpi) running dnsmasq, but solely for domains associated with our custom top-level domain ( ctld). This strategy ensures optimal efficiency, as domain resolutions for standard domains like google.com continue to be handled by the local DNS, while requests for *.ctld domains are routed through the Tailscale network’s DNS server, which may incur a higher latency if our rpi is not nearby.

                      TLS Certificates ( The Green Stuff )

                      To enable the use of HTTPS without encountering any browser warnings, obtaining TLS certificates is essential. If you are already familiar with TLS and its intricacies, you may skip the remaining portion of this subsection. However, if you require a more detailed explanation, there are numerous comprehensive resources available online.

                      TLS, which stands for Transport Layer Security, is a crucial component of Private Key Infrastructure (PKI) framework. When a client and server aim to establish a secure communication channel, the client must be aware of the server’s public key. While the DNS server provides the IP address of machineA.ctld, it does not verify the legitimacy of the server’s public key. TLS ensures that the key has not been tampered with or maliciously altered during transit over the network. While communications between Tailscale (TS) devices are considered secure, the broader internet cannot make such assumptions. Therefore, without the server’s public key, secure communication becomes impossible. This is where TLS certificates come into play.

                      A TLS certificate is an attestation signed by a trusted entity known as a Certificate Authority (CA). It asserts that a specific public key belongs to machineA.ctld. Understanding the three levels of TLS certificates is important. First, the root certificate is a self-signed certificate that contains the public key of the CA. This root certificate must be installed on all machines requiring TLS functionality for our custom TLD. The private key used to sign the root certificate is typically kept offline in cold storage, as recovery from a compromised root key is impossible, eg you can’t sign a revocation if your private key cannot be trusted.

                      The intermediate certificate is signed by the root certificate and is responsible for signing leaf certificates. Unlike the root certificate, the private key of the intermediate certificate is usually kept online since it is required to sign leaf certificates. If an intermediate certificate becomes compromised or expires, the root private key can be brought out of cold storage to issue a revocation.

                      The leaf or end certificate, which is presented by machineA.ctld, serves as proof that its public key is legitimate. The intermediate certificate has the authority to revoke leaf certificates if machineA.ctld exhibits malicious behavior.

                      TLS certificates can be generated by the CA and securely transferred to the server using methods like scp. This approach is particularly useful for devices where running ACME (Automated Certificate Management Environment) properly is not feasible. Or if the CA cannot establish bi-directional communication with the machine for some reason. ACME provides an automated mechanism for generating certificate signing requests and validating the domain ownership to the CA.

                      By understanding these concepts, we can effectively utilize TLS certificates to establish secure and trusted communication channels, ensuring the green lock symbol and seamless HTTPS functionality in our browsers.

                      ACME

                      If you have previous experience with Let’s Encrypt or certbot, then you are likely familiar with the ACME (Automated Certificate Management Environment) protocol. ACME is a collection of protocols that servers can employ to demonstrate their ownership of domain names to Certificate Authorities (CAs) when requesting certificates. The primary purpose of a certificate is to certify that machineA.ctld is indeed the owner of a specific public key.

                      ACME offers two verification methods, with the less commonly used method being DNS certification. In this approach, the client server contacts the ACME server and claims ownership of machineA.ctld. The client server provides a Certificate Signing Request (CSR) to the ACME server for signing. The ACME server then requests the client server to add a specific string to the TXT section of the DNS record. If the server genuinely owns machineA.ctld and its authoritative nameserver supports an API for managing domain records, the server can perform the required operation and have it verified by the ACME server. However, as we are utilizing dnsmasq as our DNS server, the specific steps for performing this operation are not within my expertise.

                      It is worth noting that the DNS certification method is less common compared to the alternative method, which involves proving ownership through HTTP-based challenges. This method requires the server to respond to a challenge by placing a designated file at a specified location on the web server. The ACME server then attempts to access the file to validate ownership. This approach is generally more straightforward to implement and is not dependent on what API your DNS provider happens to supply.

                      Step CA

                      To proceed with setting up an ACME server on a Raspberry Pi, we can follow the guide provided at https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/. Although the guide incorporates using a YubiKey for loading keys, it is not necessary for our purposes. However, adhering to proper security practices is always recommended, and if you have access to YubiKeys, it can enhance the overall security of the setup. I get them for free at work. There is an option to use the infnoise generator dongle, but we will opt because it costs too much and I don’t get them for free at work. I recommend you use the same Raspberry Pi you’re hosting the ctld DNS off of. Note that the ACME server will run on port 443, while the DNS server will operate on port 53, ensuring that there won’t be any conflicts between the two services.

                      During the setup process, remember to modify the domain from tinyca.internal to a domain of your choice with the .ctld extension, such as ctldca.ctld.

                      Once you have completed this step, you will be able to request TLS certificates for your custom domain, allowing you to establish secure connections using HTTPS.

                      Install the root cert

                      To ensure that your browser and servers recognize the custom TLD Certificate Authority (CA) and avoid any issues with certificate verification, install the root certificate into the truststore of your devices. This step will establish trust in the certificates issued by the custom CA.

                      To verify if the installation was successful, you can open a shell or command prompt and execute the command curl https://machinea.ctld. If you encounter an error 60, it indicates that the CA is not recognized by your machine, indicating a problem with the root certificate installation.

                      For convenience and ease of use, it is recommended to store the root certificate in a cloud drive or a similar storage solution. This way, you can readily access and install it on new devices whenever necessary.

                      Requesting a cert

                      You can refer to the guides provided at https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/ for detailed instructions on setting up various ACME clients. However, if you’re looking for a straightforward and user-friendly option, I recommend using acme.sh.

                      Some pitfalls in cert requesting

                      I’ll probably split this off into separate guides when I get the chance.

                      HAProxy

                      Certain reverse proxies, such as HAProxy, will require the leaf private key and certificate in one file. If this is the case you will need to cat the key and cert together. A reverse proxy may also hog port 80 and 443 which are needed to do the ACME challenge, in which case you will need to carve out a path to the ACME client.

                      Here is my setup for HAProxy - it’s my octoprint server:

                      # In /etc/haproxy/haproxy.cfg
                       frontend public
                           bind :::80 v4v6
                           # Redirect requests to this path towards the ACME cleint instance on port 8888
                           acl letsencrypt-acl path_beg /.well-known/acme-challenge/
                           use_backend letsencrypt-backend if letsencrypt-acl
                      -    
                      +
                           # Set the certificate
                           bind :::443 v4v6 ssl crt /home/pi/.acme.sh/octoprint.aws.pem
                       
                       # This is the acme.sh port
                       backend letsencrypt-backend
                               server letsencrypt 127.0.0.1:8888
                      -
                      - -
                      # In crontab
                      -# Request certs, place them in /some/config/dir. Follow the guide for details on configuring this. 
                      -0 * * * * /some/dir/acme.sh --cron --home "/some/config/dir/" --force --httpport 8888 
                      +
                      # In crontab
                      +# Request certs, place them in /some/config/dir. Follow the guide for details on configuring this.
                      +0 * * * * /some/dir/acme.sh --cron --home "/some/config/dir/" --force --httpport 8888
                       
                       # Combine the privKey and the cert. Order matters here
                       1 * * * * cat /some/config/dir/machineA.ctld.key /some/config/dir/machineA.ctld.crt > /some/config/dir/machineA.ctld.pem
                      -
                      - -

                      You also need to reload the certificate cause HAProxy is too dumb to pick up that you edited it. Drop this script into -a file, edit your crontab to run it. Also maybe edit out the octoprint stuff:

                      - -
                      #!/bin/bash
                      +

                      You also need to reload the certificate cause HAProxy is too dumb to pick up that you edited it. Drop this script into a file, edit your crontab to run it. Also maybe edit out the octoprint stuff:

                      #!/bin/bash
                       echo========================== SET SSL CERT ==========================echo "$(cat /home/pi/.acme.sh/octoprint.aws.pem)"
                       echo -e "set ssl cert /home/pi/.acme.sh/octoprint.aws.pem <<\n$(cat /home/pi/.acme.sh/octoprint.aws.pem)\n" | socat tcp-connect:localhost:9999 -
                      @@ -461,175 +133,31 @@ a file, edit your crontab to run it. Also maybe edit out the octoprint stuff:

                      echo "commit ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 - echo========================== SHOW SSL CERT - after ==========================echo "show ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 - -
                      - -

                      HomeAssistant

                      - -

                      This one is a pain in the ass. Haven’t gotten this up and running yet. I’ll write another post to document this.

                      ]]>
                      Andrew M. Zhang
                      Notes on Arduino GPS Library2021-06-18T00:00:00+00:002021-06-18T00:00:00+00:00https://andrewmzhang.com/blog/2021/arduino-gps-notesNote: I splurged on a better quality (though way more expensive) shields from sparkfun. Thus this post will probably remain unupdated.

                      - -

                      Intro

                      - -

                      I bought DFRobot SIM 808 shield. Cheap shield. However, the library provided by DFRobot is not great. Here are my notes and possible solutions and a low quality fork.

                      - -

                      On Terminology:

                      -
                        -
                      • Board refers to the arduino. I used an Arduino Uno Rev3.
                      • -
                      • Shield refers to the DFRobot Shield.
                      • -
                      - -

                      My Fork

                      -
                        -
                      1. andrewmzhang arduino-sim808 fork
                      2. -
                      - -

                      I present my fork of the library, along with an updated version of the sample usage. The best way to use this is to un-stack the shield from the arduino and connect the power lines via male-to-male jumpers. Power pins, pin 12, pin 13 on the board should connect to analogous pins on the shield. Remap pins 2 and 3 from the arduino to pins 0 and 1 on the shield. I explain my motivation for this design below

                      - -

                      DFRobot SIM808 Library and Resources

                      - -
                        -
                      1. DFRobot SIM808 Github Repo
                      2. -
                      3. DFRobot SIM808 Wiki Docs
                      4. -
                      - -

                      Pros

                      - -

                      The documentation has tool called a Serial Debugger. Super useful. You can issue direct AT (which I understand is some kind of protocol sent over Serial) commands to the shield. There’s a typo in the GPS Orientation command. It should say AT + CGNS PWR = 1.

                      - -

                      Cons

                      - -

                      There are a few issues with this shield. The first issue is that the module communicates with the arduino board through the default TX RX serial ports; pins 0 and 1 are the Arduino Uno. This is a problem because those pins are also connected to the USB Serial line which means:

                      - -
                        -
                      1. You cannot upload sketches without powering down the shield.
                      2. -
                      3. All communication sent to the shield will also show up in USB Serial Monitor.
                      4. -
                      5. Any prints done on arduino will show up on the USB Serial Monitor and will be sent to the shield.
                      6. -
                      7. This means debugging is nuts; say you want to print out what the Sim808 library buffer is receiving from the shield and print it w/ Serial.println. This will cause a feedback loop since the library buffer will catch it again. This makes the shield a pain to debug.
                      8. -
                      - -

                      The Library is also not particularly well written. A lot of features are missing, such as trying to get the number of satellites in view. And the design of the library is questionable; IIRC the getGPRMS code read 1 char from the serial stream, adds it toa global buffer, checks to see if the global buffer has accumulated to a valid GPRMS (it ignores all other NMEA streams types), and fails if it doesn’t. This means you need to wrap calls to getGPS in a while loop since getGPS will fail a lot…

                      - -

                      NOTE: I might need to double check the above. I kinda forgot how the lib actually works and I don’t wanna check at 2:26 AM… I will verify/fix this section ASAP…

                      - -

                      blemasle arduino-sim808 library

                      - -
                        -
                      1. blemasle library
                      2. -
                      - -

                      This library appears to be written for the Adafruit FONA? Not sure.

                      - -

                      Pros

                      - -

                      This library has super good logic, also really clean code, fully featured. Some bugs/idiosyncrasies but I’m not using the right board so eh…

                      - -

                      Cons

                      - -

                      It doesn’t work on the DFRobot shield very well. Also no comments so its a pain to figure out how it works.

                      - -

                      There is also a bug!

                      - -

                      Fixes

                      +

                      HomeAssistant

                      This one is a pain in the ass. Haven’t gotten this up and running yet. I’ll write another post to document this.

                      ]]>
                      Andrew M. Zhang
                      Notes on Arduino GPS Library2021-06-18T00:00:00+00:002021-06-18T00:00:00+00:00https://andrewmzhang.com/blog/2021/arduino-gps-notesNote: I splurged on a better quality (though way more expensive) shields from sparkfun. Thus this post will probably remain unupdated.

                      Intro

                      I bought DFRobot SIM 808 shield. Cheap shield. However, the library provided by DFRobot is not great. Here are my notes and possible solutions and a low quality fork.

                      On Terminology:

                      • Board refers to the arduino. I used an Arduino Uno Rev3.
                      • Shield refers to the DFRobot Shield.

                      My Fork

                      1. andrewmzhang arduino-sim808 fork

                      I present my fork of the library, along with an updated version of the sample usage. The best way to use this is to un-stack the shield from the arduino and connect the power lines via male-to-male jumpers. Power pins, pin 12, pin 13 on the board should connect to analogous pins on the shield. Remap pins 2 and 3 from the arduino to pins 0 and 1 on the shield. I explain my motivation for this design below

                      DFRobot SIM808 Library and Resources

                      1. DFRobot SIM808 Github Repo
                      2. DFRobot SIM808 Wiki Docs

                      Pros

                      The documentation has tool called a Serial Debugger. Super useful. You can issue direct AT (which I understand is some kind of protocol sent over Serial) commands to the shield. There’s a typo in the GPS Orientation command. It should say AT + CGNS PWR = 1.

                      Cons

                      There are a few issues with this shield. The first issue is that the module communicates with the arduino board through the default TX RX serial ports; pins 0 and 1 are the Arduino Uno. This is a problem because those pins are also connected to the USB Serial line which means:

                      1. You cannot upload sketches without powering down the shield.
                      2. All communication sent to the shield will also show up in USB Serial Monitor.
                      3. Any prints done on arduino will show up on the USB Serial Monitor and will be sent to the shield.
                      4. This means debugging is nuts; say you want to print out what the Sim808 library buffer is receiving from the shield and print it w/ Serial.println. This will cause a feedback loop since the library buffer will catch it again. This makes the shield a pain to debug.

                      The Library is also not particularly well written. A lot of features are missing, such as trying to get the number of satellites in view. And the design of the library is questionable; IIRC the getGPRMS code read 1 char from the serial stream, adds it toa global buffer, checks to see if the global buffer has accumulated to a valid GPRMS (it ignores all other NMEA streams types), and fails if it doesn’t. This means you need to wrap calls to getGPS in a while loop since getGPS will fail a lot…

                      NOTE: I might need to double check the above. I kinda forgot how the lib actually works and I don’t wanna check at 2:26 AM… I will verify/fix this section ASAP…

                      blemasle arduino-sim808 library

                      1. blemasle library

                      This library appears to be written for the Adafruit FONA? Not sure.

                      Pros

                      This library has super good logic, also really clean code, fully featured. Some bugs/idiosyncrasies but I’m not using the right board so eh…

                      Cons

                      It doesn’t work on the DFRobot shield very well. Also no comments so its a pain to figure out how it works.

                      There is also a bug!

                      Fixes

                      I present my fixes on the arduino-sim808 library for the DFRobot shield.

                      Hardware

                      Serial communication with the SIM808

                      The solution here is to un-stack the shield and then just use male-to-male jumpers to connect over the power pins. Pins 13 and 12, and connect pins 0,1 on the shield to 2,3 on the board respectively. Then we will use software serial to communicate with the shield, and use the default 0, 1 pins to print Serial messages as per usual. This prevents the Serial prints and board buffer printouts to get feedback looped or whatever.

                      Power On

                      The shield comes with a boot switch. The documentation on the DFRWiki (link here) states that we can press the switch for 1s to power on and 3s to power off. It also states that the switch is also tied to pin D12. Do programatically hit the switch, write high to D12 for X seconds. We can use this trigger the SIM808 power on/off.

                      Reset Pin

                      Although there are traces on the board leading from the SIM808 SIM RESET pin on the SIM808 chip, I can’t figure out where they lead to. The Leonardo version of this shield has some jumpers to tap into that trace, but no on the arduino shield. Thus we leave this alone.

                      Status Pin

                      Again, there are no jumpers to access this on the arduino version of the shield.

                      Software

                      We use the Software Serial to 2,3 to communicate with the shield.

                      I’m not sure when RDY gets sent. When I had the shield serial connected to board serial default (0,1), I never got the RDY response from the shield and setting the baud rate into non-volatile memory (AT?? command) never held across reboot. You only get the RDY if the baud is set according to the docs. Thus in the default library with the default serial comms, the sim808 gets stuck on init waiting on RDY

                      Another issue is that if the GPS fix fails (not enough satellites to perform trilateration), you cannot get any data from NMEA streams that are available; current time, number of GPS in view, etc. I have fixed this (insert github line link here)

                      ]]>
                      Andrew M. Zhang
                      Mosh + Tmux + Copy Paste2020-02-06T02:01:00+00:002020-02-06T02:01:00+00:00https://andrewmzhang.com/blog/2020/osc-52-patch-for-vte-0425OUTDATED

                      This guide is outdated. I’m keeping this up for my own records. The updated guide to setting this up will be placed

                      The overarching goal is to set up what I believe to be the ideal remote development terminal setup; mosh into remote -> tmux + ability to copy paste to local machine.

                      Background

                      To achieve the stated goal, we implement the OSC 52 escape command within the default terminal provided by the Ubuntu OS 16.04 (gnome-terminal) so I could copy and paste to the system clipboard through terminal escapes, ie printf "\033]52;c;$(printf "%s" "test" | base64)\a" should copy “test” into the local OS clipboard.

                      This particular version of vte was chosen due to the fact that its the default version of libvte for ubuntu 16.04, which is what I use. This patch won’t work for more modern versions of vte as the code has changed significantly.

                      Unsolved problems

                      Since the goal is for personal use on tmux, this OSC 52 patch does not cover all use cases for OSC 52. In fact this patch only supports the c; option (it assumes all OSC 52 escapes are trying to reach the clipboard). osc 52 documentation

                      Git Patch

                      patch code

                      git clone https://github.com/andrewmzhang/vte.git

                      To Install w/o Overriding Default libvte Install

                      # Dependencies
                       
                      -

                      I present my fixes on the arduino-sim808 library for the DFRobot shield.

                      - -

                      Hardware

                      - -

                      Serial communication with the SIM808

                      - -

                      The solution here is to un-stack the shield and then just use male-to-male jumpers to connect over the power pins. Pins 13 and 12, and connect pins 0,1 on the shield to 2,3 on the board respectively. Then we will use software serial to communicate with the shield, and use the default 0, 1 pins to print Serial messages as per usual. This prevents the Serial prints and board buffer printouts to get feedback looped or whatever.

                      - -

                      Power On

                      - -

                      The shield comes with a boot switch. The documentation on the DFRWiki (link here) states that we can press the switch for 1s to power on and 3s to power off. It also states that the switch is also tied to pin D12. Do programatically hit the switch, write high to D12 for X seconds. We can use this trigger the SIM808 power on/off.

                      - -

                      Reset Pin

                      - -

                      Although there are traces on the board leading from the SIM808 SIM RESET pin on the SIM808 chip, I can’t figure out where they lead to. The Leonardo version of this shield has some jumpers to tap into that trace, but no on the arduino shield. Thus we leave this alone.

                      - -

                      Status Pin

                      - -

                      Again, there are no jumpers to access this on the arduino version of the shield.

                      - -

                      Software

                      - -

                      We use the Software Serial to 2,3 to communicate with the shield.

                      - -

                      I’m not sure when RDY gets sent. When I had the shield serial connected to board serial default (0,1), I never got the RDY response from the shield and setting the baud rate into non-volatile memory (AT?? command) never held across reboot. You only get the RDY if the baud is set according to the docs. Thus in the default library with the default serial comms, the sim808 gets stuck on init waiting on RDY

                      - -

                      Another issue is that if the GPS fix fails (not enough satellites to perform trilateration), you cannot get any data from NMEA streams that are available; current time, number of GPS in view, etc. I have fixed this (insert github line link here)

                      ]]>Andrew M. ZhangMosh + Tmux + Copy Paste2020-02-06T02:01:00+00:002020-02-06T02:01:00+00:00https://andrewmzhang.com/blog/2020/osc-52-patch-for-vte-0425OUTDATED - -

                      This guide is outdated. I’m keeping this up for my own records. The updated guide to setting this up will be placed

                      - - -

                      The overarching goal is to set up what I believe to be the ideal remote development terminal setup; mosh into remote -> tmux + ability to copy paste to local machine.

                      - -

                      Background

                      - -

                      To achieve the stated goal, we implement the OSC 52 escape command within the default terminal provided by the Ubuntu OS 16.04 (gnome-terminal) so I could copy and paste to the system clipboard through terminal escapes, ie printf "\033]52;c;$(printf "%s" "test" | base64)\a" should copy “test” into the local OS clipboard.

                      - -

                      This particular version of vte was chosen due to the fact that its the default version of libvte for ubuntu 16.04, which is what I use. This patch won’t work for more modern versions of vte as the code has changed significantly.

                      - -

                      Unsolved problems

                      - -

                      Since the goal is for personal use on tmux, this OSC 52 patch does not cover all use cases for OSC 52. In fact this patch only supports the c; option (it assumes all OSC 52 escapes are trying to reach the clipboard). osc 52 documentation

                      - -

                      Git Patch

                      - -

                      patch code

                      - -

                      git clone https://github.com/andrewmzhang/vte.git

                      - -

                      To Install w/o Overriding Default libvte Install

                      - -
                      # Dependencies
                       sudo apt-get install gtk-doc-tools gobject-introspection valac libvala-dev libgnutls-dev libgirepository1.0-dev gperf
                       
                      -
                       # Will install to /opt/vte
                      +
                       ./autogen.sh --prefix=/opt/vte
                       make
                      -sudo make install
                      - -

                      Setting Up gnome-terminal

                      - -

                      Initially I tried to devise a way to have 2 different gnome-terminal executables, one that would launch with the doctored libvte library and the other untouched, since I don’t have functionality to turn off OSC 52 escapes once implemented. Unfortunately it seems that gnome-terminal uses the system global name “org.gnome.Terminal” to communicate through the dbus. I don’t know how dbus works, so I didn’t attempt to manipulate it.

                      - -

                      When gnome-terminal launches, it actually communicates w/ gnome-terminal-server (or launches it) and gnome-terminal exits (see post on this: gnome-terminal-server-explained ). So we actually need to get gnome-terminal-server to use our doctored lib.

                      +sudo make install

                      Setting Up gnome-terminal

                      Initially I tried to devise a way to have 2 different gnome-terminal executables, one that would launch with the doctored libvte library and the other untouched, since I don’t have functionality to turn off OSC 52 escapes once implemented. Unfortunately it seems that gnome-terminal uses the system global name “org.gnome.Terminal” to communicate through the dbus. I don’t know how dbus works, so I didn’t attempt to manipulate it.

                      When gnome-terminal launches, it actually communicates w/ gnome-terminal-server (or launches it) and gnome-terminal exits (see post on this: gnome-terminal-server-explained ). So we actually need to get gnome-terminal-server to use our doctored lib.

                      gnome-terminal/gnome-terminal-server version 3.18.3 on the defaul Ubuntu install seems to be a bit different from what sits at the gnome gitlab repository. Instead of trying to install whatever patches Ubuntu utilizes, I opted to relink the gnome-terminal-server executable to point to our doctored lib.

                      # Will show you what libvte links to
                       
                      -

                      gnome-terminal/gnome-terminal-server version 3.18.3 on the defaul Ubuntu install seems to be a bit different from what sits at the gnome gitlab repository. Instead of trying to install whatever patches Ubuntu utilizes, I opted to relink the gnome-terminal-server executable to point to our doctored lib.

                      +ldd /usr/lib/gnome-terminal/gnome-terminal-server | grep "vte" -
                      # Will show you what libvte links to
                      -ldd /usr/lib/gnome-terminal/gnome-terminal-server | grep "vte" 
                       # outputs: libvte-2.91.so.0 => /usr/lib/x86_64-linux-gnu/libvte-2.91.so.0
                       
                       # Backup gnome-terminal-server
                      +
                       sudo cp /usr/lib/gnome-terminal/gnome-terminal-server /usr/lib/gnome-terminal/gnome-terminal-server.bak
                       
                       # Relink the library; Run the patchelf on a non libvte based emulator (eg xterm)
                      -sudo apt install -y patchelf
                      -sudo patchelf --replace-needed libvte-2.91.so.0 /opt/vte/lib/libvte-2.91.so.0 /usr/lib/gnome-terminal/gnome-terminal-server
                      - -

                      Fixing the colours

                      - -

                      The colours might have changed (for me libvte put up a white background w/ black text). To fix this open gnome-terminal->profile preferences->colors

                      - -

                      Change the text color to: #FEF8D9 -Change the background color to: #300A24 -Bold color to: [x] Same as text color

                      -

                      Setting Up tmux and mosh

                      - -

                      First, we need to tell tmux to copy via OSC 52. To do this we need to set the clipboard.

                      - -

                      Tmux supports OSC 52 but does not pass the “c;” option, according to yudai’s post. However we can force it to pass the “c;” option. Mosh is capable of catching the OSC 52 option c (the default mosh only accepts the “c;” option). Thus adding these lines to the tmux.conf should allow us to copy into local clipboard. I think if you install this mosh pr it supports the other OSC 52 options.

                      - -

                      Note: This only works for more recent version of tmux.

                      +sudo apt install -y patchelf +sudo patchelf --replace-needed libvte-2.91.so.0 /opt/vte/lib/libvte-2.91.so.0 /usr/lib/gnome-terminal/gnome-terminal-server

                      Fixing the colours

                      The colours might have changed (for me libvte put up a white background w/ black text). To fix this open gnome-terminal->profile preferences->colors

                      Change the text color to: #FEF8D9 Change the background color to: #300A24 Bold color to: [x] Same as text color

                      Setting Up tmux and mosh

                      First, we need to tell tmux to copy via OSC 52. To do this we need to set the clipboard.

                      Tmux supports OSC 52 but does not pass the “c;” option, according to yudai’s post. However we can force it to pass the “c;” option. Mosh is capable of catching the OSC 52 option c (the default mosh only accepts the “c;” option). Thus adding these lines to the tmux.conf should allow us to copy into local clipboard. I think if you install this mosh pr it supports the other OSC 52 options.

                      Note: This only works for more recent version of tmux.

                      # sets tmux to use OSC 52 escape
                       
                      -
                      # sets tmux to use OSC 52 escape
                       set -g set-clipboard on
                       
                       # Forces tmux to use the "c;" option
                      -set -ag terminal-overrides "vte*:XT:Ms=\\E]52;c;%p2%s\\7,xterm*:XT:Ms=\\E]52;c;%p2%s\\7"
                      -

                      Contributions

                      -

                      Big thanks to Kevin Zheng for providing most of the code :)

                      ]]>Andrew M. Zhang + Kevin Zheng \ No newline at end of file +set -ag terminal-overrides "vte*:XT:Ms=\\E]52;c;%p2%s\\7,xterm*:XT:Ms=\\E]52;c;%p2%s\\7"

                      Contributions

                      Big thanks to Kevin Zheng for providing most of the code :)

                      ]]>
                      Andrew M. Zhang + Kevin Zheng
                      \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 7eab61f..5db6f7e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,112 +1 @@ -'use strict'; - -var gulp = require('gulp'); -var gutil = require('gulp-util'); -var rename = require('gulp-rename'); - -var cryptojs = require('crypto-js'); -var marked = require('marked'); -var FileSystem = require('fs'); -var through = require('through2'); -var PluginError = gutil.PluginError; - -/* - START FIREWALL TASKS -*/ -function checkEncryptedLayout(frontMatter, filepath) { - var lines = frontMatter.split('\n'), - linesWithoutLayout = [], - hasEncryptedLayout = false; - - lines.forEach(function(line) { - var layoutTag = 'layout:', - isLayoutIndex = line.indexOf(layoutTag), - isLayout = isLayoutIndex >= 0, - isEncryptedLayout = line.indexOf('encrypted') >= (isLayoutIndex + layoutTag.length); - - if (isLayout) { - // in case of multiple instances of layout - hasEncryptedLayout = isEncryptedLayout ? true : false; - } - }); - - if (!hasEncryptedLayout) { - console.log('[WARNING] ' + filepath + ': protected file not using encrypted layout.'); - } - - // var linesWithLayout = linesWithoutLayout - // .splice(0, 1) - // .concat('layout: encrypted') - // .concat(linesWithoutLayout); - - // var frontMatterWithEncryptedLayout = linesWithLayout.join('\n'); - // return frontMatterWithEncryptedLayout; -} - -function encrypt(password) { - return through.obj(function(file, encoding, callback) { - if (file.isNull() || file.isDirectory()) { - this.push(file); - return callback(); - } - - // No support for streams - if (file.isStream()) { - this.emit('error', new PluginError({ - plugin: 'Encrypt', - message: 'Streams are not supported.' - })); - return callback(); - } - - if (file.isBuffer()) { - var delimiter = '---', - chunks = String(file.contents).split(delimiter), - originalBody = chunks[0], - frontMatter = ''; - - if (chunks.length === 3) { - checkEncryptedLayout(chunks[1], file.path); - frontMatter = chunks[1]; - originalBody = chunks[2]; - } else if (chunks.length > 1) { - this.emit('error', new PluginError({ - plugin: 'Encrypt', - message: file.path + ': protected file has invalid front matter.' - })); - return callback(); - } - - var encryptedBody = cryptojs.AES.encrypt(marked(originalBody), password), - hmac = cryptojs.HmacSHA256(encryptedBody.toString(), cryptojs.SHA256(password).toString()).toString(), - encryptedFrontMatter = 'encrypted: ' + hmac + encryptedBody, - result = [ delimiter, frontMatter, '\n', encryptedFrontMatter, '\n', delimiter ]; - - file.contents = new Buffer(result.join('')); - this.push(file); - return callback(); - } - }); -} - -gulp.task('firewall:encrypt', () => { - return gulp.src('_protected/*.*') - .pipe(encrypt('supernodesecurities')) - .pipe(rename({extname: '.md.priv'})) - .pipe(gulp.dest('_posts')); -}); - -gulp.task('firewall:watch', () => { - gulp.watch('_protected/*.*', gulp.series('firewall:encrypt')); -}); - -gulp.task('firewall', gulp.series('firewall:encrypt', 'firewall:watch',() => {})); - - -/* - END FIREWALL TASKS -*/ - -gulp.task('default', gulp.series('firewall', () => { - // your tasks here -})); +"use strict";function checkEncryptedLayout(e,r){var t=e.split("\n"),i=!1;t.forEach(function(e){var r="layout:",t=e.indexOf(r),n=t>=0,u=e.indexOf("encrypted")>=t+r.length;n&&(i=!!u)}),i||console.log("[WARNING] "+r+": protected file not using encrypted layout.")}function encrypt(e){return through.obj(function(r,t,i){if(r.isNull()||r.isDirectory())return this.push(r),i();if(r.isStream())return this.emit("error",new PluginError({plugin:"Encrypt",message:"Streams are not supported."})),i();if(r.isBuffer()){var n="---",u=String(r.contents).split(n),p=u[0],l="";if(3===u.length)checkEncryptedLayout(u[1],r.path),l=u[1],p=u[2];else if(u.length>1)return this.emit("error",new PluginError({plugin:"Encrypt",message:r.path+": protected file has invalid front matter."})),i();var s=cryptojs.AES.encrypt(marked(p),e),o=[n,l,"\n","encrypted: "+cryptojs.HmacSHA256(s.toString(),cryptojs.SHA256(e).toString()).toString()+s,"\n",n];return r.contents=new Buffer(o.join("")),this.push(r),i()}})}var gulp=require("gulp"),gutil=require("gulp-util"),rename=require("gulp-rename"),cryptojs=require("crypto-js"),marked=require("marked"),FileSystem=require("fs"),through=require("through2"),PluginError=gutil.PluginError;gulp.task("firewall:encrypt",()=>gulp.src("_protected/*.*").pipe(encrypt("supernodesecurities")).pipe(rename({extname:".md.priv"})).pipe(gulp.dest("_posts"))),gulp.task("firewall:watch",()=>{gulp.watch("_protected/*.*",gulp.series("firewall:encrypt"))}),gulp.task("firewall",gulp.series("firewall:encrypt","firewall:watch",()=>{})),gulp.task("default",gulp.series("firewall",()=>{})); \ No newline at end of file diff --git a/index.html b/index.html index 7f8ffe4..bb2bf49 100644 --- a/index.html +++ b/index.html @@ -1,441 +1 @@ - - - - - - - - - - - - - Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - -
                      -
                      -

                      - Andrew M. Zhang -

                      -

                      Working at a Chicago-based Quant Trading Firm. Citadel Securities Quantitative Research Intern (2019 & 2020). RISELab. Former EECS Masters Student - UC Berkeley.

                      -
                      - -
                      -
                      - -
                      - - - - - - - - - - prof_pic.jpg - - - -
                      - -
                      - -
                      -
                      - -
                      -

                      Website under minor construction…

                      - -

                      I don’t really maintain this bio…

                      - -

                      I was a student pursuing an M.Sc in Computer Science at University of California - Berkeley. I was also a researcher in -RISELab where I work under Prof. Randy Katz on serverless machine learning frameworks and serverless computing. I used -to TA for CS189: Machine Learning and CS70: Discrete Math and Probability Theory.

                      - -

                      My most up to date resume is always provided below:

                      - -

                      My Resume

                      - - -
                      - - - - - -

                      latest posts

                      -
                      -
                      - - - - - - - - - - - - - - -
                      Jul 24, 2023 - Running step-ca in docker w/ Yubikey -
                      May 25, 2023 - Reverse Proxies With Custom ACME -
                      May 17, 2023 - Custom TLD Over Tailscale -
                      -
                      -
                      - - - -

                      selected publications

                      -
                      -
                        -
                      1. - -
                        -
                        SoCC
                        - - -
                        - -
                        CENTAUR: A Practical Serverless Framework for End-to-End ML Workflows
                        - -
                        - - - J. Carreira, P. Fonseca, A. Tumanov, A. Zhang, and Prof. Katz
                        - - - - -
                        - Symposium on Cloud Computing,, 2019 -
                        -
                        - -
                        - - - - -
                        - - -
                        - - - -
                        -
                        -
                      2. -
                      3. - -
                        -
                        NeurIPS
                        - - -
                        - -
                        A Case for Serverless Machine Learning
                        - -
                        - - - J. Carreira, P. Fonseca, A. Tumanov, A. Zhang, and Prof. Katz
                        - - - - -
                        - NuerIPS Workshop,, 2018 -
                        -
                        - -
                        - - - - -
                        - - -
                        - - - -
                        -
                        -
                      4. -
                      -
                      - - - - -
                      - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Andrew M. Zhang

                      Andrew M. Zhang

                      Working at a Chicago-based Quant Trading Firm. Citadel Securities Quantitative Research Intern (2019 & 2020). RISELab. Former EECS Masters Student - UC Berkeley.

                      prof_pic.jpg

                      I don’t really maintain this bio…

                      I was a student pursuing an M.Sc in Computer Science at University of California - Berkeley. I was also a researcher in RISELab where I work under Prof. Randy Katz on serverless machine learning frameworks and serverless computing. I used to TA for CS189: Machine Learning and CS70: Discrete Math and Probability Theory.

                      My most up-to-date resume is always provided below:

                      My Resume

                      latest posts

                      selected publications

                      1. SoCC
                        CENTAUR: A Practical Serverless Framework for End-to-End ML Workflows
                        J. Carreira , P. Fonseca , A. Tumanov , A. Zhang , and Prof. Katz
                        Symposium on Cloud Computing,, 2019
                      2. NeurIPS
                        A Case for Serverless Machine Learning
                        J. Carreira , P. Fonseca , A. Tumanov , A. Zhang , and Prof. Katz
                        NuerIPS Workshop,, 2018
                      \ No newline at end of file diff --git a/news/announcement_1/index.html b/news/announcement_1/index.html index 507652d..5f5f006 100644 --- a/news/announcement_1/index.html +++ b/news/announcement_1/index.html @@ -1,268 +1 @@ - - - - - - - - - - - - - Announcement_1 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - - -
                      - -
                      -

                      Announcement_1

                      - - -
                      - -
                      - -
                      -

                      A simple inline announcement.

                      - -
                      -
                      -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Announcement_1 | Andrew M. Zhang

                      Announcement_1

                      A simple inline announcement.

                      \ No newline at end of file diff --git a/news/announcement_2/index.html b/news/announcement_2/index.html index 28f5771..3ed357b 100644 --- a/news/announcement_2/index.html +++ b/news/announcement_2/index.html @@ -1,293 +1 @@ - - - - - - - - - - - - - A long announcement with details | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - - -
                      - -
                      -

                      A long announcement with details

                      - - -
                      - -
                      - -
                      -

                      Announcements and news can be much longer than just quick inline posts. In fact, they can have all the features available for the standard blog posts. See below.

                      - -
                      - -

                      Jean shorts raw denim Vice normcore, art party High Life PBR skateboard stumptown vinyl kitsch. Four loko meh 8-bit, tousled banh mi tilde forage Schlitz dreamcatcher twee 3 wolf moon. Chambray asymmetrical paleo salvia, sartorial umami four loko master cleanse drinking vinegar brunch. Pinterest DIY authentic Schlitz, hoodie Intelligentsia butcher trust fund brunch shabby chic Kickstarter forage flexitarian. Direct trade cold-pressed meggings stumptown plaid, pop-up taxidermy. Hoodie XOXO fingerstache scenester Echo Park. Plaid ugh Wes Anderson, freegan pug selvage fanny pack leggings pickled food truck DIY irony Banksy.

                      - -

                      Hipster list

                      -
                        -
                      • brunch
                      • -
                      • fixie
                      • -
                      • raybans
                      • -
                      • messenger bag
                      • -
                      - -

                      Hoodie Thundercats retro, tote bag 8-bit Godard craft beer gastropub. Truffaut Tumblr taxidermy, raw denim Kickstarter sartorial dreamcatcher. Quinoa chambray slow-carb salvia readymade, bicycle rights 90’s yr typewriter selfies letterpress cardigan vegan.

                      - -
                      - -

                      Pug heirloom High Life vinyl swag, single-origin coffee four dollar toast taxidermy reprehenderit fap distillery master cleanse locavore. Est anim sapiente leggings Brooklyn ea. Thundercats locavore excepteur veniam eiusmod. Raw denim Truffaut Schlitz, migas sapiente Portland VHS twee Bushwick Marfa typewriter retro id keytar.

                      - -
                      -

                      We do not grow absolutely, chronologically. We grow sometimes in one dimension, and not in another, unevenly. We grow partially. We are relative. We are mature in one realm, childish in another. -—Anais Nin

                      -
                      - -

                      Fap aliqua qui, scenester pug Echo Park polaroid irony shabby chic ex cardigan church-key Odd Future accusamus. Blog stumptown sartorial squid, gastropub duis aesthetic Truffaut vero. Pinterest tilde twee, odio mumblecore jean shorts lumbersexual.

                      - -
                      -
                      -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A long announcement with details | Andrew M. Zhang

                      A long announcement with details

                      Announcements and news can be much longer than just quick inline posts. In fact, they can have all the features available for the standard blog posts. See below.


                      Jean shorts raw denim Vice normcore, art party High Life PBR skateboard stumptown vinyl kitsch. Four loko meh 8-bit, tousled banh mi tilde forage Schlitz dreamcatcher twee 3 wolf moon. Chambray asymmetrical paleo salvia, sartorial umami four loko master cleanse drinking vinegar brunch. Pinterest DIY authentic Schlitz, hoodie Intelligentsia butcher trust fund brunch shabby chic Kickstarter forage flexitarian. Direct trade cold-pressed meggings stumptown plaid, pop-up taxidermy. Hoodie XOXO fingerstache scenester Echo Park. Plaid ugh Wes Anderson, freegan pug selvage fanny pack leggings pickled food truck DIY irony Banksy.

                      Hipster list

                      • brunch
                      • fixie
                      • raybans
                      • messenger bag

                      Hoodie Thundercats retro, tote bag 8-bit Godard craft beer gastropub. Truffaut Tumblr taxidermy, raw denim Kickstarter sartorial dreamcatcher. Quinoa chambray slow-carb salvia readymade, bicycle rights 90’s yr typewriter selfies letterpress cardigan vegan.


                      Pug heirloom High Life vinyl swag, single-origin coffee four dollar toast taxidermy reprehenderit fap distillery master cleanse locavore. Est anim sapiente leggings Brooklyn ea. Thundercats locavore excepteur veniam eiusmod. Raw denim Truffaut Schlitz, migas sapiente Portland VHS twee Bushwick Marfa typewriter retro id keytar.

                      We do not grow absolutely, chronologically. We grow sometimes in one dimension, and not in another, unevenly. We grow partially. We are relative. We are mature in one realm, childish in another. —Anais Nin

                      Fap aliqua qui, scenester pug Echo Park polaroid irony shabby chic ex cardigan church-key Odd Future accusamus. Blog stumptown sartorial squid, gastropub duis aesthetic Truffaut vero. Pinterest tilde twee, odio mumblecore jean shorts lumbersexual.

                      \ No newline at end of file diff --git a/news/announcement_3/index.html b/news/announcement_3/index.html index da5c281..1700077 100644 --- a/news/announcement_3/index.html +++ b/news/announcement_3/index.html @@ -1,268 +1 @@ - - - - - - - - - - - - - Announcement_3 | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - - -
                      - -
                      -

                      Announcement_3

                      - - -
                      - -
                      - -
                      -

                      A simple inline announcement with Markdown emoji! :sparkles: :smile:

                      - -
                      -
                      -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Announcement_3 | Andrew M. Zhang

                      Announcement_3

                      A simple inline announcement with Markdown emoji! :sparkles: :smile:

                      \ No newline at end of file diff --git a/news/index.html b/news/index.html index 8d53411..97a231f 100644 --- a/news/index.html +++ b/news/index.html @@ -1,287 +1 @@ - - - - - - - - - - - - - news | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - -
                      - -
                      -

                      news

                      -

                      -
                      - -
                      -
                      -
                      - - - - - - - - - - - - - - -
                      Jan 15, 2016 - A simple inline announcement with Markdown emoji! :sparkles: :smile: - -
                      Nov 7, 2015 - A long announcement with details -
                      Oct 22, 2015 - A simple inline announcement. - -
                      -
                      -
                      - -
                      - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + news | Andrew M. Zhang

                      news

                      \ No newline at end of file diff --git a/people/index.html b/people/index.html new file mode 100644 index 0000000..9f913d7 --- /dev/null +++ b/people/index.html @@ -0,0 +1 @@ + people | Andrew M. Zhang

                      people

                      members of the lab or group


                      prof_pic.jpg

                      555 your office number

                      123 your address street

                      Your City, State 12345

                      Write your biography here. Tell the world about yourself. Link to your favorite subreddit. You can put a picture in, too. The code is already in, just name your picture prof_pic.jpg and put it in the img/ folder.

                      Put your address / P.O. box / other info right below your picture. You can also disable any these elements by editing profile property of the YAML header of your _pages/about.md. Edit _bibliography/papers.bib and Jekyll will render your publications page automatically.

                      Link to your social media connections, too. This theme is set up to use Font Awesome icons and Academicons, like the ones below. Add your Facebook, Twitter, LinkedIn, Google Scholar, or just disable all of them.


                      prof_pic.jpg

                      555 your office number

                      123 your address street

                      Your City, State 12345

                      Write your biography here. Tell the world about yourself. Link to your favorite subreddit. You can put a picture in, too. The code is already in, just name your picture prof_pic.jpg and put it in the img/ folder.

                      Put your address / P.O. box / other info right below your picture. You can also disable any these elements by editing profile property of the YAML header of your _pages/about.md. Edit _bibliography/papers.bib and Jekyll will render your publications page automatically.

                      Link to your social media connections, too. This theme is set up to use Font Awesome icons and Academicons, like the ones below. Add your Facebook, Twitter, LinkedIn, Google Scholar, or just disable all of them.

                      \ No newline at end of file diff --git a/publications/index.html b/publications/index.html index 189c96b..3055f6c 100644 --- a/publications/index.html +++ b/publications/index.html @@ -1,352 +1 @@ - - - - - - - - - - - - - publications | Andrew M. Zhang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      - - - - - - -
                      - -
                      -
                      -
                      - - - -
                      - - -
                      - -
                      -

                      publications

                      -

                      publications by categories in reversed chronological order. generated by jekyll-scholar.

                      -
                      - -
                      -
                      -

                      2019

                      -
                      1. - -
                        -
                        SoCC
                        - - -
                        - -
                        CENTAUR: A Practical Serverless Framework for End-to-End ML Workflows
                        - -
                        - - - J. Carreira, P. Fonseca, A. Tumanov, A. Zhang, and Prof. Katz
                        - - - - -
                        - Symposium on Cloud Computing,, 2019 -
                        -
                        - -
                        - - - - -
                        - - -
                        - - - -
                        -
                        -
                      - -

                      2018

                      -
                      1. - -
                        -
                        NeurIPS
                        - - -
                        - -
                        A Case for Serverless Machine Learning
                        - -
                        - - - J. Carreira, P. Fonseca, A. Tumanov, A. Zhang, and Prof. Katz
                        - - - - -
                        - NuerIPS Workshop,, 2018 -
                        -
                        - -
                        - - - - -
                        - - -
                        - - - -
                        -
                        -
                      - - -
                      - -
                      - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + publications | Andrew M. Zhang

                      publications

                      publications by categories in reversed chronological order. generated by jekyll-scholar.

                      2019

                      1. SoCC
                        CENTAUR: A Practical Serverless Framework for End-to-End ML Workflows
                        J. Carreira , P. Fonseca , A. Tumanov , A. Zhang , and Prof. Katz
                        Symposium on Cloud Computing,, 2019

                      2018

                      1. NeurIPS
                        A Case for Serverless Machine Learning
                        J. Carreira , P. Fonseca , A. Tumanov , A. Zhang , and Prof. Katz
                        NuerIPS Workshop,, 2018
                      \ No newline at end of file diff --git a/repositories/index.html b/repositories/index.html new file mode 100644 index 0000000..6c7b9d1 --- /dev/null +++ b/repositories/index.html @@ -0,0 +1 @@ + repositories | Andrew M. Zhang

                      repositories

                      Edit the `_data/repositories.yml` and change the `github_users` and `github_repos` lists to include your own GitHub profile and repositories.

                      GitHub users

                      GitHub Repositories

                      \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 9d2c5be..72ee06f 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,98 +1 @@ - - - -https://andrewmzhang.com/news/announcement_1/ -2015-10-22T19:59:00+00:00 - - -https://andrewmzhang.com/news/announcement_2/ -2015-11-07T20:11:00+00:00 - - -https://andrewmzhang.com/news/announcement_3/ -2016-01-15T11:59:00+00:00 - - -https://andrewmzhang.com/blog/2020/osc-52-patch-for-vte-0425/ -2020-02-06T02:01:00+00:00 - - -https://andrewmzhang.com/blog/2021/arduino-gps-notes/ -2021-06-18T00:00:00+00:00 - - -https://andrewmzhang.com/blog/2023/custom-tld/ -2023-05-17T00:00:00+00:00 - - -https://andrewmzhang.com/blog/2023/reverse-proxies-with-custom-acme/ -2023-05-25T00:00:00+00:00 - - -https://andrewmzhang.com/blog/2023/running-step-ca-in-docker-w-yubikey/ -2023-07-24T00:00:00+00:00 - - -https://andrewmzhang.com/ - - -https://andrewmzhang.com/news/ - - -https://andrewmzhang.com/publications/ - - -https://andrewmzhang.com/blog/tag/gps/ - - -https://andrewmzhang.com/blog/tag/sim808/ - - -https://andrewmzhang.com/blog/tag/dfrobot/ - - -https://andrewmzhang.com/blog/tag/arduino/ - - -https://andrewmzhang.com/blog/tag/arduino-sim808/ - - -https://andrewmzhang.com/blog/tag/andywebservices/ - - -https://andrewmzhang.com/blog/tag/tailscale/ - - -https://andrewmzhang.com/blog/tag/network/ - - -https://andrewmzhang.com/blog/tag/ssl/ - - -https://andrewmzhang.com/blog/tag/certificate/ - - -https://andrewmzhang.com/blog/tag/authority/ - - -https://andrewmzhang.com/blog/tag/yubikey/ - - -https://andrewmzhang.com/blog/tag/smallstep/ - - -https://andrewmzhang.com/blog/tag/step-ca/ - - -https://andrewmzhang.com/blog/category/tech/ - - -https://andrewmzhang.com/blog/2020/ - - -https://andrewmzhang.com/blog/2021/ - - -https://andrewmzhang.com/blog/2023/ - - + https://andrewmzhang.com/news/announcement_1/ 2015-10-22T19:59:00+00:00 https://andrewmzhang.com/news/announcement_2/ 2015-11-07T20:11:00+00:00 https://andrewmzhang.com/news/announcement_3/ 2016-01-15T11:59:00+00:00 https://andrewmzhang.com/blog/2020/osc-52-patch-for-vte-0425/ 2020-02-06T02:01:00+00:00 https://andrewmzhang.com/blog/2021/arduino-gps-notes/ 2021-06-18T00:00:00+00:00 https://andrewmzhang.com/blog/2023/custom-tld/ 2023-05-17T00:00:00+00:00 https://andrewmzhang.com/blog/2023/reverse-proxies-with-custom-acme/ 2023-05-25T00:00:00+00:00 https://andrewmzhang.com/blog/2023/running-step-ca-in-docker-w-yubikey/ 2023-07-24T00:00:00+00:00 https://andrewmzhang.com/ https://andrewmzhang.com/cv/ https://andrewmzhang.com/_pages/dropdown/ https://andrewmzhang.com/news/ https://andrewmzhang.com/people/ https://andrewmzhang.com/publications/ https://andrewmzhang.com/repositories/ https://andrewmzhang.com/blog/tag/gps/ https://andrewmzhang.com/blog/tag/sim808/ https://andrewmzhang.com/blog/tag/dfrobot/ https://andrewmzhang.com/blog/tag/arduino/ https://andrewmzhang.com/blog/tag/arduino-sim808/ https://andrewmzhang.com/blog/tag/andywebservices/ https://andrewmzhang.com/blog/tag/tailscale/ https://andrewmzhang.com/blog/tag/network/ https://andrewmzhang.com/blog/tag/ssl/ https://andrewmzhang.com/blog/tag/certificate/ https://andrewmzhang.com/blog/tag/authority/ https://andrewmzhang.com/blog/tag/yubikey/ https://andrewmzhang.com/blog/tag/smallstep/ https://andrewmzhang.com/blog/tag/step-ca/ https://andrewmzhang.com/blog/category/tech/ https://andrewmzhang.com/blog/2020/ https://andrewmzhang.com/blog/2021/ https://andrewmzhang.com/blog/2023/ https://andrewmzhang.com/blog/ \ No newline at end of file