├── .prettierrc.toml
├── teaching.md
├── _static
├── share.png
├── images
│ ├── docsets.png
│ ├── maslow.png
│ ├── navigate.png
│ ├── black-panther.jpeg
│ ├── dash-docsets-repo.png
│ ├── hidden-oss-work.png
│ ├── extract-hidden-value.png
│ ├── google-domains-static-ip.png
│ ├── google-domains-dynamic-dns.png
│ ├── google-domains-acme-challenge.png
│ └── google-domains-wildcard-subdomain.png
├── anderson-profile.jpeg
└── custom.css
├── posts.md
├── .gitattributes
├── feed.xml
├── .github
├── dependabot.yml
└── workflows
│ └── ci.yaml
├── talks.md
├── .binder
└── environment.yml
├── posts
├── 2019
│ └── scipy-2019.md
├── 2020
│ ├── sphinx-based-redesign.md
│ ├── maurice-hilleman.md
│ ├── the-sun-and-her-scorch.md
│ ├── chadwick-boseman.md
│ ├── a-knitting-weekend-with-dash.md
│ ├── advent-of-code-day-6.ipynb
│ ├── advent-of-code-day-5.ipynb
│ ├── advent-of-code-day-9.ipynb
│ ├── advent-of-code-day-3.ipynb
│ ├── advent-of-code-day-2.ipynb
│ └── advent-of-code-day-8.ipynb
├── 2021
│ ├── freedom-of-cryptography.md
│ ├── mesdames.md
│ ├── lets-encrypt-wildcard-ssl-certificate-on-centos.md
│ ├── google-dynamic-dns-wildcard-subdomains.md
│ ├── how-to-merge-disk-partitions-on-centos.md
│ ├── dictionary-merge-and-update-operators.ipynb
│ └── function-expressions-in-js.ipynb
├── 2022
│ └── multitude.md
└── drafts
│ └── bayesian-for-hackers
│ └── probability-distributions.ipynb
├── .pre-commit-config.yaml
├── environment.yml
├── Makefile
├── _templates
└── hello.html
├── README.md
├── index.md
├── pyproject.toml
├── config_data
├── teaching.yaml
└── talks.yaml
├── .gitignore
├── data
└── advent-of-code
│ └── 2020
│ ├── day-1-input
│ ├── day-8-input
│ ├── day-3-input
│ ├── day-5-input
│ └── day-9-input
├── about.md
├── talks_gallery.md
├── teaching_gallery.md
└── conf.py
/.prettierrc.toml:
--------------------------------------------------------------------------------
1 | tabWidth = 2
2 | semi = false
3 | singleQuote = true
4 |
--------------------------------------------------------------------------------
/teaching.md:
--------------------------------------------------------------------------------
1 | # Teaching
2 |
3 | ```{include} teaching_gallery.md
4 |
5 | ```
6 |
--------------------------------------------------------------------------------
/_static/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/share.png
--------------------------------------------------------------------------------
/posts.md:
--------------------------------------------------------------------------------
1 | # ✍🏽 Posts
2 |
3 | % This will be replaced by `ablog` so there's nothing here.
4 |
--------------------------------------------------------------------------------
/_static/images/docsets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/docsets.png
--------------------------------------------------------------------------------
/_static/images/maslow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/maslow.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/_static/images/navigate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/navigate.png
--------------------------------------------------------------------------------
/_static/anderson-profile.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/anderson-profile.jpeg
--------------------------------------------------------------------------------
/_static/images/black-panther.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/black-panther.jpeg
--------------------------------------------------------------------------------
/_static/images/dash-docsets-repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/dash-docsets-repo.png
--------------------------------------------------------------------------------
/_static/images/hidden-oss-work.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/hidden-oss-work.png
--------------------------------------------------------------------------------
/_static/images/extract-hidden-value.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/extract-hidden-value.png
--------------------------------------------------------------------------------
/feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://blog.andersonbanihirwe.dev/posts/atom.xml
4 |
5 |
6 |
--------------------------------------------------------------------------------
/_static/images/google-domains-static-ip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/google-domains-static-ip.png
--------------------------------------------------------------------------------
/_static/images/google-domains-dynamic-dns.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/google-domains-dynamic-dns.png
--------------------------------------------------------------------------------
/_static/images/google-domains-acme-challenge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/google-domains-acme-challenge.png
--------------------------------------------------------------------------------
/_static/images/google-domains-wildcard-subdomain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andersy005/blog/main/_static/images/google-domains-wildcard-subdomain.png
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | groups:
8 | actions:
9 | patterns:
10 | - "*"
11 |
--------------------------------------------------------------------------------
/talks.md:
--------------------------------------------------------------------------------
1 | # 🎙 Talks
2 |
3 | I’ve given talks at academic and software conferences.
4 | Some of these are recorded and available online.
5 | Below are a few highlighted talks that I have given recently.
6 |
7 | ```{include} talks_gallery.md
8 |
9 | ```
10 |
--------------------------------------------------------------------------------
/.binder/environment.yml:
--------------------------------------------------------------------------------
1 | name: blog
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - ablog
6 | - jupyterlab
7 | - myst-nb
8 | - pandas
9 | - pydata-sphinx-theme
10 | - python=3.8
11 | - sphinx-panels
12 | - pip
13 | - pip:
14 | - sphinxext-opengraph
15 | - sphinxcontrib-bibtex
16 |
--------------------------------------------------------------------------------
/posts/2020/sphinx-based-redesign.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2020-11-30
4 | tags: news
5 | ---
6 |
7 | # Migrating from `fastpages` to sphinx-based blog
8 |
9 | After a few months on [fastpages](https://fastpages.fast.ai/) hosted on GitHub pages, all the content I have published on my blog is now being built with sphinx hosted on Github pages. This sphinx-based redesign was inspired by [this blog post by Chris Holdgraf](https://predictablynoisy.com/posts/2020/sphinx-blogging/). Thank you 🙏🏽, Chris!
10 |
11 | The Sphinx source for this blog is hosted on Github in this [repo](https://github.com/andersy005/blog).
12 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ci:
2 | autoupdate_schedule: monthly
3 | repos:
4 | - repo: https://github.com/pre-commit/pre-commit-hooks
5 | rev: v5.0.0
6 | hooks:
7 | - id: trailing-whitespace
8 | - id: end-of-file-fixer
9 | - id: check-docstring-first
10 | - id: check-json
11 | - id: check-yaml
12 | - id: double-quote-string-fixer
13 | - id: debug-statements
14 | - id: mixed-line-ending
15 |
16 | - repo: https://github.com/astral-sh/ruff-pre-commit
17 | rev: "v0.7.2"
18 | hooks:
19 | - id: ruff
20 | args: ["--fix"]
21 | - id: ruff-format
22 |
23 | - repo: https://github.com/pre-commit/mirrors-prettier
24 | rev: v4.0.0-alpha.8
25 | hooks:
26 | - id: prettier
27 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: blog
2 | channels:
3 | - conda-forge
4 | - nodefaults
5 | dependencies:
6 | - ablog
7 | - cftime
8 | - colorspacious
9 | - dask
10 | - dask-labextension
11 | - distributed
12 | - hvplot
13 | - ipywidgets
14 | - ipywidgets
15 | - jupyterlab>=3
16 | - matplotlib
17 | - myst-nb>=0.12.0
18 | - netcdf4
19 | - numba
20 | - pip
21 | - pydantic
22 | - pydata-sphinx-theme>=0.4.3
23 | - python=3.9
24 | - scipy
25 | - seaborn
26 | - sphinx
27 | - sphinx-autobuild
28 | - sphinx-comments
29 | - sphinx-panels
30 | - sphinxcontrib-bibtex<2.0.0
31 | - sympy
32 | - watermark
33 | - wrapt
34 | - xarray>=0.18.2
35 | - pooch
36 | - pip:
37 | - ptime
38 | - sphinx-design
39 | - sphinxext-opengraph
40 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | live:
16 | sphinx-autobuild --ignore */.github/* --ignore */tmp/* --ignore */drafts/* "$(SOURCEDIR)" _build/dirhtml/ --port 9999
17 |
18 | .PHONY: help Makefile
19 |
20 | # Catch-all target: route all unknown targets to Sphinx using the new
21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
22 | %: Makefile
23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
24 |
--------------------------------------------------------------------------------
/_templates/hello.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Anderson Banihirwe
7 |
8 | Interactive High Performance Computing | Open Source Science
9 |
10 |
11 |
12 | I contribute to and maintain several libraries within the open source
13 | scientific Python stack, particularly around improving scalability of Python
14 | tools in order to handle terabyte-scale datasets on HPC and cloud platforms.
15 |
16 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://results.pre-commit.ci/latest/github/andersy005/blog/main)
3 |
4 | # [blog.andersonbanihirwe.dev](https://blog.andersonbanihirwe.dev/)
5 |
6 | This repository serves my personal website, technical blog, and a collection of my personal notes. The contents are posted at [blog.andersonbanihirwe.dev](https://blog.andersonbanihirwe.dev/).
7 |
8 | ## License
9 |
10 | This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .
11 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: deploy-site
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | workflow_dispatch:
11 |
12 | jobs:
13 | deploy-site:
14 | runs-on: ubuntu-latest
15 | defaults:
16 | run:
17 | shell: bash -l {0}
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - name: set up conda environment
22 | uses: mamba-org/setup-micromamba@v1
23 | with:
24 | environment-file: environment.yml
25 | init-shell: >-
26 | bash
27 | cache-environment: true
28 | cache-downloads: true
29 | post-cleanup: "all"
30 |
31 | - name: Build
32 | run: |
33 | make dirhtml
34 |
35 | - name: Deploy
36 | if: github.ref == 'refs/heads/main'
37 | uses: peaceiris/actions-gh-pages@v4.0.0
38 | with:
39 | github_token: ${{ secrets.GITHUB_TOKEN }}
40 | publish_dir: ./_build/dirhtml
41 | cname: blog.andersonbanihirwe.dev
42 | enable_jekyll: false
43 |
--------------------------------------------------------------------------------
/index.md:
--------------------------------------------------------------------------------
1 | # Anderson Banihirwe
2 |
3 | Currently, I am working as a software engineer in [Computational & Information Systems Lab (CISL)](https://www2.cisl.ucar.edu/) at the [National Center for Atmospheric Research (NCAR)](https://ncar.ucar.edu/). On the interwebs, I go by [@andersy005](https://github.com/andersy005).
4 |
5 | I’ve been extremely fortunate to work in realms that allow me to cross institutional and geographic boundaries to collaborate on tools and research software. More generally I contribute to and maintain several libraries within the open source scientific Python stack, particularly around improving scalability of Python tools in order to (1) handle large scale datasets on [High Performance Computing](https://en.wikipedia.org/wiki/Supercomputer) and [Cloud Computing](https://en.wikipedia.org/wiki/Cloud_computing) platforms and (2) move the [**open science paradigm**](https://en.wikipedia.org/wiki/Open_science) forward.
6 |
7 | ## Recent Posts
8 |
9 | See the [blog archives](posts) for a more complete list.
10 |
11 | ```{postlist}
12 | :date: "%Y-%m-%d"
13 | :format: "{date} - {title}"
14 | :excerpts:
15 | ```
16 |
17 | ```{toctree}
18 | :maxdepth: 2
19 | :hidden:
20 | posts
21 | about
22 | talks
23 | teaching
24 | 🧾 CV
25 | Video
26 | ```
27 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.ruff]
2 | line-length = 100
3 | target-version = "py312"
4 | extend-include = ["*.ipynb"]
5 |
6 | builtins = ["ellipsis"]
7 | # Exclude a variety of commonly ignored directories.
8 | exclude = [
9 | ".bzr",
10 | ".direnv",
11 | ".eggs",
12 | ".git",
13 | ".git-rewrite",
14 | ".hg",
15 | ".ipynb_checkpoints",
16 | ".mypy_cache",
17 | ".nox",
18 | ".pants.d",
19 | ".pyenv",
20 | ".pytest_cache",
21 | ".pytype",
22 | ".ruff_cache",
23 | ".svn",
24 | ".tox",
25 | ".venv",
26 | ".vscode",
27 | "__pypackages__",
28 | "_build",
29 | "buck-out",
30 | "build",
31 | "dist",
32 | "node_modules",
33 | "site-packages",
34 | "venv",
35 | ".pixi"
36 | ]
37 | per-file-ignores = {}
38 | ignore = [
39 | "E721", # Comparing types instead of isinstance
40 | "E741", # Ambiguous variable names
41 | "E501", # Conflicts with ruff format
42 | ]
43 | select = [
44 | # Pyflakes
45 | "F",
46 | # Pycodestyle
47 | "E",
48 | "W",
49 | # isort
50 | "I",
51 | # Pyupgrade
52 | "UP",
53 | ]
54 |
55 |
56 |
57 | [tool.ruff.lint.mccabe]
58 | max-complexity = 18
59 |
60 | [tool.ruff.lint.isort]
61 | known-first-party = []
62 | combine-as-imports = true
63 |
64 | [tool.ruff.format]
65 | quote-style = "single"
66 | docstring-code-format = true
67 |
68 | [tool.ruff.lint.pydocstyle]
69 | convention = "numpy"
70 |
--------------------------------------------------------------------------------
/posts/2020/maurice-hilleman.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2020-12-16
4 | tags: life, science, people, podcast
5 | ---
6 |
7 | # On Maurice Hilleman
8 |
9 | I spent today's evening listening to [_The Great Vaccinator_](https://www.wnycstudios.org/podcasts/radiolab/articles/great_vaccinator) episode from Radiolab podcast. This episode is about [Maurice Hilleman](https://en.wikipedia.org/wiki/Maurice_Hilleman), an amazing microbiologist who is known today as the father of modern vaccine. Hilleman is credited with having saved more lives than any other scientist because he was responsible for developing more than half of the vaccines (measles, mumps, meningitis, etc...) children receive today.
10 |
11 |
12 |
13 | His life was marked by life-changing losses. He was born in the middle of the 1918 flu pandemic, and his mother and twin sister passed away right after his birth. As a young boy, he survived a couple of traumatic situations (e.g. drowning). He lost his wife from his first marriage to cancer. Amazingly, he stayed a pretty resilient, hard-working person throughout it all. I was enamored by his modesty and humility (which are part of the reason why today most people don't even know who he is). I mean... the guy developed a lot of vaccines but none of his vaccines or discoveries are named after him.
14 |
15 | _This episode was extremely satisfying to listen to and it was a great episode for better understanding our times._
16 |
--------------------------------------------------------------------------------
/posts/2021/freedom-of-cryptography.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2021-02-21
4 | tags: todayilearned, cryptography
5 | ---
6 |
7 | # Freedom of Cryptography
8 |
9 | Today I learned that if you could travel back to the early 1990s with the contents of this [git repository](https://github.com/pyca/cryptography), you would have had to become a licensed arms dealer 😮 —the govt certainly would have denied you an export license— before you could post the source code (or any work that featured the source code) on the internet.
10 |
11 | Publicly sharing the following code snippet would have landed you in prison for arms trafficking because export of cryptography from the United States was regulated at the same level as missiles, tanks, etc...😮.
12 |
13 | ```python
14 | In [1]: from cryptography.fernet import Fernet
15 |
16 | In [2]: key = Fernet.generate_key()
17 |
18 | In [3]: f = Fernet(key)
19 |
20 | In [4]: plain_text = b'Hello Alice'
21 |
22 | In [5]: cipher_text = f.encrypt(plain_text)
23 |
24 | In [6]: cipher_text
25 | Out[6]: b'gAAAAABgMjSru96WoOLHq3ygBw93ZICzyu5aKjYQqw0MQ7G44Ch77-xqCVNmYSbB4j6Kz_Ipol3hyPWx5Ti5rui1SdRc_D7LfA=='
26 |
27 | In [7]: f.decrypt(cipher_text)
28 | Out[7]: b'Hello Alice'
29 | ```
30 |
31 | **Resources with more deailed history of the legal battles for freedom of cryptography**:
32 |
33 | - [Bernstein v. United States](https://en.wikipedia.org/wiki/Bernstein_v._United_States)
34 | - [Crypto: How the Code Rebels Beat the Government Saving Privacy in the Digital Age](https://www.amazon.com/Crypto-Rebels-Government-Privacy-Digital/dp/0140244328)
35 | - [The Case against Regulating
36 | Encryption Technology](https://people.csail.mit.edu/rivest/pubs/Riv98e.pdf)
37 |
--------------------------------------------------------------------------------
/_static/custom.css:
--------------------------------------------------------------------------------
1 | /* Bio area */
2 | div.profile-pic {
3 | margin-top: 1em;
4 | }
5 |
6 | div.profile-pic img {
7 | border-radius: 500px;
8 | width: 80%;
9 | max-width: 190px;
10 | margin: 0 auto;
11 | display: block;
12 | }
13 |
14 | .bio-info {
15 | margin: 1em auto;
16 | max-width: 220px;
17 | }
18 |
19 | .name {
20 | font-size: 1.5em;
21 | }
22 |
23 | .focusareas {
24 | font-size: 0.9em;
25 | font-weight: bold;
26 | }
27 |
28 | .whatido {
29 | margin-top: 1em;
30 | }
31 |
32 | /* Sidebar for blog archive / each post */
33 | ul.ablog-archive {
34 | padding-left: 0px;
35 | }
36 |
37 | .bd-sidebar h2 {
38 | font-size: 1.4em;
39 | }
40 |
41 | .bd-sidebar ul {
42 | padding-left: 0;
43 | list-style-type: none;
44 | }
45 |
46 | .bd-sidebar li {
47 | padding-bottom: 0.5em;
48 | }
49 |
50 | div.bd-sidebar h3,
51 | div.bd-sidebar h2,
52 | div.bd-sidebar ul {
53 | padding-left: 5%;
54 | }
55 |
56 | /* In-page post lists */
57 | ul.postlist {
58 | padding-left: 0;
59 | }
60 |
61 | ul.postlist > li > p:first-child {
62 | font-size: 1.5em;
63 | }
64 |
65 | ul.postlist li + li {
66 | margin-top: 2em;
67 | }
68 |
69 | ul.postlist li > p > a {
70 | font-style: normal;
71 | font-size: 1.3em;
72 | }
73 |
74 | /* Timeline CSS */
75 | div.timeline div.card {
76 | border: 0px;
77 | }
78 |
79 | div.timeline div.left {
80 | text-align: right;
81 | border-right: 1px solid black;
82 | }
83 |
84 | div.timeline div.entry::after {
85 | width: 1em;
86 | height: 1em;
87 | background: white;
88 | border-radius: 50%;
89 | content: "";
90 | top: 1em;
91 | display: block;
92 | position: absolute;
93 | border: 1px black solid;
94 | z-index: 999;
95 | }
96 |
97 | div.timeline div.entry.left::after {
98 | right: -0.5em;
99 | }
100 |
101 | div.timeline div.entry.right::after {
102 | left: -0.5em;
103 | }
104 |
--------------------------------------------------------------------------------
/config_data/teaching.yaml:
--------------------------------------------------------------------------------
1 | - name: NCAR Python Tutorial Seminar Series - Xarray Part 1
2 | video: 'VIDEO '
3 | date: 2021-06-09
4 | repository: https://github.com/andersy005/xarray-tutorial
5 | - name: NCAR Python Tutorial Seminar Series - Xarray Part 2
6 | video: 'VIDEO '
7 | date: 2021-06-23
8 | repository: https://github.com/andersy005/xarray-tutorial
9 | - name: NCAR Python Tutorial Seminar Series - Dask Part 1
10 | video: 'VIDEO '
11 | date: 2021-07-29
12 | repository: https://github.com/andersy005/xarray-tutorial
13 | - name: NCAR Python Tutorial Seminar Series - Dask P2
14 | video: 'VIDEO '
15 | date: 2021-08-11
16 | repository: https://github.com/andersy005/xarray-tutorial
17 | - name: Xarray Tutorial | xarray fundamentals
18 | video: 'VIDEO '
19 | date: 2020-10-06
20 | repository: https://github.com/andersy005/xarray-tutorial
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # PyCharm project settings
98 | .idea/
99 |
100 | # Rope project settings
101 | .ropeproject
102 |
103 | # mkdocs documentation
104 | /site
105 |
106 | # mypy
107 | .mypy_cache/
108 |
109 |
110 | # Sphinx
111 | _build/
112 | .vscode/
113 | pip-wheel-metadata/*
114 | .DS_Store
115 | dask-worker-space/
116 | posts/2020/2020-12-03-advent-of-code-day-3-Copy1.ipynb
117 | .gitignore
118 | posts/2020/2020-12-xx-advent-of-code-day-xx-Copy1.ipynb
119 | .pixi
120 |
--------------------------------------------------------------------------------
/data/advent-of-code/2020/day-1-input:
--------------------------------------------------------------------------------
1 | 1895
2 | 1602
3 | 1592
4 | 1714
5 | 1403
6 | 1766
7 | 1654
8 | 1771
9 | 1957
10 | 1533
11 | 1661
12 | 1761
13 | 1711
14 | 1869
15 | 1541
16 | 1595
17 | 1819
18 | 1735
19 | 1894
20 | 1316
21 | 1777
22 | 1450
23 | 1526
24 | 1888
25 | 1968
26 | 1877
27 | 1972
28 | 1988
29 | 1655
30 | 1369
31 | 1636
32 | 1453
33 | 1969
34 | 1239
35 | 1717
36 | 1444
37 | 1907
38 | 1682
39 | 1358
40 | 1706
41 | 1482
42 | 1852
43 | 1689
44 | 1905
45 | 1262
46 | 1956
47 | 770
48 | 1507
49 | 1314
50 | 1890
51 | 784
52 | 1710
53 | 1418
54 | 597
55 | 1417
56 | 1587
57 | 2003
58 | 1889
59 | 879
60 | 1534
61 | 279
62 | 1302
63 | 1976
64 | 1936
65 | 1590
66 | 1939
67 | 1489
68 | 1966
69 | 1238
70 | 1481
71 | 1412
72 | 1675
73 | 2001
74 | 1543
75 | 1220
76 | 1352
77 | 1536
78 | 1879
79 | 1892
80 | 2006
81 | 1642
82 | 1321
83 | 1600
84 | 1908
85 | 2009
86 | 1784
87 | 1260
88 | 1881
89 | 1897
90 | 1933
91 | 1048
92 | 1851
93 | 2005
94 | 1626
95 | 1441
96 | 1945
97 | 1742
98 | 1734
99 | 1816
100 | 1919
101 | 1802
102 | 1460
103 | 1845
104 | 1914
105 | 1652
106 | 1943
107 | 1521
108 | 1830
109 | 1477
110 | 1866
111 | 1702
112 | 1629
113 | 1932
114 | 1671
115 | 1707
116 | 1577
117 | 1962
118 | 1518
119 | 1989
120 | 1502
121 | 61
122 | 1546
123 | 1264
124 | 1651
125 | 2000
126 | 1443
127 | 1931
128 | 1882
129 | 1583
130 | 1597
131 | 1487
132 | 1255
133 | 1779
134 | 1782
135 | 1540
136 | 1580
137 | 1294
138 | 1691
139 | 1337
140 | 1743
141 | 1632
142 | 1348
143 | 2010
144 | 1794
145 | 1876
146 | 1808
147 | 1647
148 | 422
149 | 1994
150 | 1864
151 | 1996
152 | 1738
153 | 1998
154 | 1749
155 | 1789
156 | 1395
157 | 1997
158 | 1440
159 | 1676
160 | 1527
161 | 1523
162 | 1836
163 | 1366
164 | 1700
165 | 1826
166 | 1426
167 | 1709
168 | 166
169 | 1958
170 | 1909
171 | 1428
172 | 1984
173 | 521
174 | 1760
175 | 156
176 | 1296
177 | 1475
178 | 1566
179 | 1573
180 | 1696
181 | 1471
182 | 1788
183 | 1809
184 | 1942
185 | 1461
186 | 1559
187 | 1699
188 | 1504
189 | 1465
190 | 1658
191 | 1973
192 | 1679
193 | 1376
194 | 1985
195 | 1503
196 | 1517
197 | 1825
198 | 1847
199 | 1528
200 | 1246
201 |
--------------------------------------------------------------------------------
/posts/2020/the-sun-and-her-scorch.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2020-08-02
4 | tags: music
5 | ---
6 |
7 | # Dizzy - The Sun and Her Scorch: You don’t just hear it, you feel it
8 |
9 | Two years ago I stumble upon [indie music](https://en.wikipedia.org/wiki/Independent_music), and have never looked back since then. Today, I love indie music for how true to the soul it is. One of my favorite indie artists is [**Dizzy**](https://www.dizzytheband.com/), a Canadian indie alt-pop four-piece band. Dizzy recently released their new record _The Sun and Her Scorch_. It is so beautiful! My top two songs on this record are:
10 |
11 | - **The Magician**: which is about Katie Munshaw (who is the vocalist of the band) wanting to magically bring a friend who passed away back to real life.
12 |
13 | > You be the bird, I'll be a magician 🎶
14 |
15 | VIDEO
16 |
17 | Personally, this song reminds me of a great college friend of mine who passed away in a tragic accident in 2019. Overall, the song sounds like such an emotional story portrayed beautifully with a little hope.
18 |
19 | - **Roman Candles**: which is about the spiraling anxiety and fear one feels whenever they think of having made the wrong career choice.
20 |
21 | > “The song is about being nervous and scared that I've made the wrong decision in pursuing music as a career. I feel like I'm being left behind in a way. I think it's hard for people to understand music as a career when you're not famous. If you're not Dua Lipa, people are worried about you. They don't realise that it is a career option. It can be hard to relate to people, especially when I'm not going to work every morning. Christmas dinners are usually pretty awkward. 'Oh, you're still doing music, eh?' 'Yes, grandpa!'” -- Katie Munshaw, [Apple Music](https://music.apple.com/nz/album/the-sun-and-her-scorch/1508164390)
22 |
23 | VIDEO
24 |
25 | On a personal note, I’ve been extremely lucky to (1) have a fulfilling job that I enjoy (2) to work in realms that allow me to cross institutional and geographic boundaries to collaborate on tools and research software. I'm so thankful for the opportunity to help with moving science forward.
26 |
27 | _In [a year (2020)](https://en.wikipedia.org/wiki/2020) that in the future may be known as “the year we shall not speak of”, Music has been a great source of solace...._
28 |
29 | Here's the full album on spotify. Enjoy 😊
30 |
31 |
32 |
--------------------------------------------------------------------------------
/posts/2020/chadwick-boseman.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2020-08-28
4 | tags: life, people
5 | ---
6 |
7 | # Chadwick Boseman: Rest Easy King T’Challa. Wakanda 🙅🏾♂️ forever
8 |
9 | Chadwick Boseman:
10 |
11 | - **Thank you for teaching and showing us how to serve others, while quietly understanding their pain.**
12 |
13 |
14 |
15 | - **Thank you for being the light to so many people, sharing your beautiful spirit and talent with the world! We will miss you so .... ✊🏾 ❤️ 🙅🏾♂️ forever and ever ...**
16 |
17 | VIDEO
18 |
19 | - **Throughout it all you found the courage and the will to persevere while uplifting those around you. You didn't just play a hero, you were truly one!**
20 |
21 |
22 |
23 |
24 |
25 | Repose en paix, Chadwick Boseman. Tu nous manques déjà...
26 |
27 | 
28 |
29 | > “He who has gone, so we but cherish his memory, abides with us, more potent, nay, more present than the living man.” — Antoine de Saint-Exupery
30 |
--------------------------------------------------------------------------------
/about.md:
--------------------------------------------------------------------------------
1 | # About me
2 |
3 | I work as a software engineer in the [Computational & Information Systems Lab (CISL)](https://www2.cisl.ucar.edu/) at the [National Center for Atmospheric Research (NCAR)](https://ncar.ucar.edu/).
4 |
5 | ## Software
6 |
7 | As part of my work at the National Center for Atmospheric Research, I am a core contributor to many projects in the PyData ecosystem. A complete record of projects that I have contributed to is available on my [{fa}`github,style=fab` GitHub page](https://github.com/andersy005).
8 |
9 | ## Publications
10 |
11 | For a list of publications in which I've been involved,
12 | check out [my ORCID page](https://orcid.org/0000-0001-6583-571X) or [my Google Scholar page](https://scholar.google.com/citations?user=vrlgltgAAAAJ&hl=en&oi=ao).
13 |
14 | ## Academic and Work timeline
15 |
16 | Below is a timeline of what I've been up to over the past several years.
17 |
18 | ```{panels}
19 | :container: timeline
20 | :column: col-6 p-0
21 | :card:
22 |
23 | ---
24 | :column: +entry left
25 |
26 | **Sept 2020**: Promoted to Software Engineer ||
27 | ^^^
28 |
29 | I continued leading the intake-ESM project. In addition, I joined the [Jupyter Meets Earth](https://pangeo-data.github.io/jupyter-earth/) project as a contributor. During this time, I helped with the development of the following projects:
30 | - [jupyter-forward](https://jupyter-forward.readthedocs.io/), a Jupyter Lab port forwarding utility that simplifies running jupyter on remote resources.
31 |
32 | ---
33 | :column: +right
34 | ---
35 | :column: +left
36 |
37 | ---
38 | :column: +entry right
39 |
40 | **Oct 2018**: Joined NCAR as Software Engineer |
41 | ^^^
42 |
43 | After my work at Quansight, I joined NCAR as a fulltime Software Engineer I focusing my work around developing Python tools for climate data analysis. Here are a few of the main things I did during this time:
44 |
45 | - Lead the [intake-ESM](https://intake-esm.readthedocs.io/en/latest/) project, a Python data cataloguing package for exploring and ingesting earth system model data sets.
46 | - Contributed to the core software stack powering the [Pangeo Project](https://pangeo.io/). Some of the projects I contributed to include:
47 | - [xarray](https://xarray.pydata.org/en/stable/)
48 | - [dask](https://docs.dask.org/en/latest/)
49 | - [distributed](https://distributed.dask.org/en/latest/)
50 | - [dask-mpi](https://mpi.dask.org/en/latest/)
51 | - [dask-jobqueue](https://jobqueue.dask.org/en/latest/)
52 |
53 | ---
54 | :column: +entry left
55 |
56 | **June 2018**: Joined Quansight
57 | ^^^
58 |
59 | After graduating I joined [Quansight](https://www.quansight.com/) as a software developer intern. At Quansight, I developed [xndframes](https://github.com/xnd-project/xndframes), an experimental Pandas extension array backed by xnd. In addition to xndframes, I worked on [cuDF](https://github.com/rapidsai/cudf) a GPU dataframe library.
60 |
61 | ---
62 | :column: +right
63 | ---
64 | :column: +left
65 | ---
66 | :column: +entry right
67 |
68 | **May 2018**: Graduated from UA-Little Rock
69 | ^^^
70 |
71 | Graduated from [University of Arkansas at Little Rock](http://ualr.edu/systemsengineering/) with a B.S. in Systems Engineering.
72 | ```
73 |
--------------------------------------------------------------------------------
/posts/2021/mesdames.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2021-03-13
4 | tags: music
5 | ---
6 |
7 | # « Mesdames » - Parce que l’avenir appartient à celles qu’on aime trop 🎶
8 |
9 | Ça fait des années que je n’ai pas parlé français ou que j’ai écrit en français.
10 | Mon excuse numéro un, c'est que je réside dans un pays anglophone. Et à cause de ça, je n’ai pas l’occasion d’utiliser (parler, écrir) la langue régulièrement. Pourtant, j'ai plein d'occasions de savourer:
11 |
12 | - des programmes diffusés à la télé ([Quotidien avec Yann Barthès](https://www.tf1.fr/tmc/quotidien-avec-yann-barthes) est mon numéro un préféré 🤩).
13 | - beaucoup de chansons (merci Spotify, Youtube :))
14 |
15 | Ce blog post est ma première tentative de blogger en français. Je vais essayer d'écrire en français chaque fois que l' occasion se présentera. Dans ce blog post, je veux parler du nouvel album de [Grand Corps Malade](https://en.wikipedia.org/wiki/Grand_Corps_Malade) baptisé **["Mesdames"]()**. Je viens d'ecouter à l'intégralité de cet album. L'album est formidable et il est avant tout un hommage aux femmes. Voici mes morceaux préférés:
16 |
17 | - **Une sœur**: _Il y a peu de monde qui te permette de donner au mot famille un vrai sens_ ... 🎶
18 |
19 | VIDEO
20 |
21 | - **Mesdames**: _Vous êtes infiniment plus subtiles, plus élégantes et plus classes_ ...🎶
22 |
23 | VIDEO
24 |
25 | - **Enfants du désordre**: _La violence est une rancœur qu'on a laissé grandir
26 | Une colère prisonnière qui ne veut plus partir_ ... 🎶
27 |
28 | VIDEO
29 |
30 | - **Mais je t'aime**: _Ces flammes nous ont rendus fous
31 | On a oublié qu'au final, le feu ça brûle.... Pourquoi lorsque l'amour est fort il nous rend vulnérables et fragiles_...🎶
32 |
33 | VIDEO
34 |
35 | **Cet album est un vrai chef-d'œuvre! Musique, voix, textes, etc... tout est magnifique!** Pour les amoureux de la musique, voici l'album complet sur Spotify. Enjoy 😊...
36 |
37 |
38 |
39 | ## Bonus
40 |
41 | - Pour une dose de bonne humeur, voici **"Mais j'te tej"**, une parodie trop drôle de **"Mais je t'aime"**. Je me suis bien marré 😂😂😂
42 |
43 | VIDEO
44 |
--------------------------------------------------------------------------------
/talks_gallery.md:
--------------------------------------------------------------------------------
1 | ```{panels}
2 | :card: text-center
3 |
4 | [Community Earth System Model Large Ensemble (CESM LENS) Datasets on AWS](https://talks.andersonbanihirwe.dev/presentations/2022/esip-jan-cesm-lens-aws.html)
5 | ^^^
6 | ...
7 | +++
8 | ESIP January 2022 Meeting | Virtual | 2022-01-19
9 |
10 | ---
11 |
12 | [The Current State of Deploying Dask on HPC systems](https://talks.andersonbanihirwe.dev/deploying-dask-on-hpc-dask-summit-2021.html)
13 | ^^^
14 | VIDEO
15 | +++
16 | Dask Summit 2021 | Virtual | 2021-05-20
17 |
18 | ---
19 |
20 | [Pangeo Use Case: Analyzing Initialized Climate Prediction System Datasets with climpred](https://talks.andersonbanihirwe.dev/climpred-cdpw-2020.html)
21 | ^^^
22 | ...
23 | +++
24 | NOAA’s 45th Climate Diagnostics & Prediction Workshop | Virtual | 2020-10-20
25 |
26 | ---
27 |
28 | [Zarr: chunked, compressed, multidimensional arrays](https://talks.andersonbanihirwe.dev/zarr-cloud-native-geospatial-2020.html)
29 | ^^^
30 | VIDEO
31 | +++
32 | Cloud Native Geospatial Outreach Day 2020 | Virtual | 2020-09-08
33 |
34 | ---
35 |
36 | [Intake-ESM – Making It Easier To Consume Climate and Weather Data](https://talks.andersonbanihirwe.dev/intake-esm-esip-2020.html)
37 | ^^^
38 | VIDEO
39 | +++
40 | ESIP Summer Meeting 2020 | Virtual | 2020-07-23
41 |
42 | ---
43 |
44 | [Dask and Pangeo](https://speakerdeck.com/andersy005/dask-and-pangeo-a-community-platform-for-big-data-geoscience)
45 | ^^^
46 | ...
47 | +++
48 | Dask Developer Summit 2020 | Washington, District of Columbia, U.S. | 2020-02-26
49 |
50 | ---
51 |
52 | [Turning HPC Systems into Interactive Data Analysis Platforms using Jupyter and Dask](https://talks.andersonbanihirwe.dev/dask-jupyter-scipy-2019.html)
53 | ^^^
54 | VIDEO
55 | +++
56 | SciPy Conference 2019 | Austin, Texas, U.S. | 2019-07-12
57 |
58 | ---
59 |
60 | [PySpark for "Big" Atmospheric Data Analysis](https://opensky.ucar.edu/islandora/object/conference%3A3443/datastream/PDF/view)
61 | ^^^
62 |
63 | +++
64 | Eighth Symposium on Advances in Modeling and Analysis Using Python. American Meteorological Society | Austin, Texas, U.S. | 2018-01-08
65 |
66 | ---
67 |
68 | [PySpark for "Big" Atmospheric and Oceanic Data Analysis](...)
69 | ^^^
70 | VIDEO
71 | +++
72 | 2017 NCAR/CISL SIParCS Internship | Boulder, Colorado, U.S. | 2017-08-23
73 |
74 | ```
75 |
--------------------------------------------------------------------------------
/posts/2021/lets-encrypt-wildcard-ssl-certificate-on-centos.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2021-02-27
4 | tags: todayilearned, dns, domains, letsencrypt
5 | ---
6 |
7 | # How to Generate Wildcard SSL Certificate using Let’s Encrypt/Certbot on CentOS
8 |
9 | Today I wanted to generate a wildcard SSL certificate for a service I was working on. Luckily, Let's Encrypt's ACME v2 production endpoint makes it so easy to generate wilcard certificates (for more details on this feature, see [this post](https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578)). Below are the steps I used to generate a wildcard certificate.
10 |
11 | :::{note}
12 | This article describes the process for Centos 7/8 but can also be used for other Linux distros (with small changes in step 1). Also, `{subdomain}` and `{domain}` are placeholders. Remember to replace them with your own values. For instance, `{subdomain}`-> `mycloud`, and `{domain}` -> `example.com`
13 | :::
14 |
15 | ## Step 1 — Installing the Certbot Let’s Encrypt Client
16 |
17 | ```bash
18 | $ sudo dfn install epel-release
19 | $ sudo dfn install certbot
20 | ```
21 |
22 | :::{note}
23 |
24 | This step assumes that you are using CentOS 7/8.
25 |
26 | :::
27 |
28 | ## Step 2 — Obtaining a Wildcard Certificate
29 |
30 | ```bash
31 | $ sudo certbot certonly -d *.{subdomain}.{domain} \
32 | > --manual \
33 | > --preferred-challenges dns \
34 | > --server https://acme-v02.api.letsencrypt.org/directory
35 | ```
36 |
37 | The certbot prompts you for some personal information. Once everything is done, certbot provides a DNS TXT record to add to your DNS settings. At this point, head over to your DNS settings ( I was using google domains) and enter your TXT DNS record:
38 |
39 | 
40 |
41 | :::{note}
42 |
43 | `{subdomain}` and `{domain}` are placeholders. Remember to replace them with your own values. For instance, `{subdomain}`-> `mycloud`, and `{domain}` -> `example.com`
44 |
45 | :::
46 |
47 | At this point,
48 |
49 | - Go back to your command line command (which should have been blocking after the DNS TXT record instructions).
50 | - Then Hit `Enter`.
51 |
52 | Cerbot will retrieve your DNS records to verify that the entries are correct. If the verification is successful, you get following output:
53 |
54 | ```console
55 | Before continuing, verify the record is deployed.
56 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
57 | Press Enter to Continue
58 | Waiting for verification...
59 | Cleaning up challenges
60 |
61 | IMPORTANT NOTES:
62 | - Congratulations! Your certificate and chain have been saved at:
63 | /etc/letsencrypt/live/mycloud.example.com/fullchain.pem
64 | Your key file has been saved at:
65 | /etc/letsencrypt/live/mycloud.example.com/privkey.pem
66 | Your certificate will expire on 2021-05-28. To obtain a new or
67 | tweaked version of this certificate in the future, simply run
68 | certbot again. To non-interactively renew *all* of your
69 | certificates, run "certbot renew"
70 | - If you like Certbot, please consider supporting our work by:
71 |
72 | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
73 | Donating to EFF: https://eff.org/donate-le
74 | ```
75 |
76 | ## Step 3 — Testing the Certificate and SSL Configuration
77 |
78 | At this point, you can ensure that Certbot created your SSL certificate correctly by using the [SSL Server Test](https://www.ssllabs.com/ssltest/) from the cloud security company Qualys.
79 |
80 | Open your browser, and point it to the following link, replacing `mycloud.example.com` with your domain:
81 |
82 | ```console
83 | https://www.ssllabs.com/ssltest/analyze.html?d=mycloud.example.com
84 | ```
85 |
86 | Voilà 🎉🎉🎉🎉!
87 |
--------------------------------------------------------------------------------
/posts/2021/google-dynamic-dns-wildcard-subdomains.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2021-01-09
4 | tags: todayilearned, dns, domains
5 | ---
6 |
7 | # How to set up a wildcard subdomain on Google Domains
8 |
9 | Today, I was working with [dokku](https://github.com/dokku/dokku/), and I found myself in need of a wildcard subdomain. A [wildcard DNS record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) is a record that will match requests for non-existent subdomains. For instance, if you set a wildcard DNS record to `*.example.com`, and a user requests `random.example.com` or `foo.example.com`, etc.. the requests will be forwarded to whichever server `*.example.com` points to.
10 |
11 | For my use case, I wanted to host multiple applications on a single server, and wanted to map each app to a subdomain such as `app1-name.dokku.example.com`, `app2-name.dokku.example.com`, etc. To achieve this, I needed to set up a wildcard DNS record for `*.dokku.example.com`.
12 |
13 | Currently, I happen to own a domain on [Google Domains](https://domains.google/). Below are the steps I followed to set up the `*.dokku.example.com` wildcard DNS record.
14 |
15 | :::{note}
16 | I'm using `example.com` as a dummy domain for demonstration purposes.
17 | :::
18 |
19 | ## Server/VM with a dynamic IP address
20 |
21 | For a server with a dynamic IP address, we need to create a dynamic DNS record and a CNAME record in our DNS settings.
22 |
23 | ### Step 1: Create a Dynamic DNS record in Synthetic Records
24 |
25 | Create a synthetic record for **dokku.example.com** instead of **\*.dokku.example.com**:
26 |
27 | 
28 |
29 | ### Step 2: Create a CNAME record of the subdomain
30 |
31 | Create a CNAME record of the subdomain **\*dokku.example.com** and point it to the synthetic records subdomain **dokku.example.com**:
32 |
33 | 
34 |
35 | ### Step 3: Set up ddclient on your server
36 |
37 | First, make sure [`ddclient`](https://github.com/ddclient/ddclient) is installed on your server and the `ddclient` service is up and running.
38 |
39 | Second,
40 |
41 | ```bash
42 | $ sudo nano /etc/ddclient.conf
43 | ```
44 |
45 | And edit these lines using the credentials from the created Google Domains dynamic DNS record:
46 |
47 | ```bash
48 | ##
49 | ## Google Domains (www.google.com/domains)
50 | ##
51 | # protocol=googledomains,
52 | # login=my-auto-generated-username,
53 | # password=my-auto-generated-password
54 | # my.domain.tld, otherhost.domain.tld
55 | ```
56 |
57 | - Example:
58 |
59 | ```bash
60 | daemon=3600 # Check every 1 hour
61 | ssl=yes
62 | use=web, web=checkip.dyndns.com/, web-skip='IP Address'
63 | protocol=googledomains
64 | login=xxzzzxxxxxxzzzzzz
65 | password=xxzzzzxxxxzzzzz
66 | dokku.example.com
67 | ```
68 |
69 | Verify that the `ddclient` is working by trying:
70 |
71 | ```bash
72 | sudo ddclient -daemon=0 -debug -verbose -noquiet
73 | ```
74 |
75 | ### Step 4: Verify that our changes have taken effect
76 |
77 | We can verify our changes on a UNIX machine by trying one or more of the following commands:
78 |
79 | - `host dokku.example.com`
80 | - `dig dokku.example.com`
81 | - `nslookup dokku.example.com`
82 |
83 | Once we have a confirmation that our top level subdomain works, we should be able to query any other name under `dokku.example.com` and get back an IP address of our server. Try:
84 |
85 | - `host myapp.dokku.example.com`
86 | - `dig +short '*.dokku.example.com'`
87 |
88 | Credits: Thank you [StackExchange](https://serverfault.com/questions/670066/google-dynamic-dns-wildcard-subdomains) 🙏🏽!
89 |
90 | ## Server/VM with a static IP address
91 |
92 | For a server/VM with a static IP address, the process is much simpler. Creating an `A record` pointing to the IP address of the server/VM suffices:
93 |
94 | 
95 |
--------------------------------------------------------------------------------
/config_data/talks.yaml:
--------------------------------------------------------------------------------
1 | - title: "Community Earth System Model Large Ensemble (CESM LENS) Datasets on AWS"
2 | slides: https://talks.andersonbanihirwe.dev/presentations/2022/esip-jan-cesm-lens-aws.html
3 | video: ...
4 | conference:
5 | name: ESIP January 2022 Meeting
6 | location: Virtual
7 | date: 2022-01-19
8 |
9 | - title: "The Current State of Deploying Dask on HPC systems"
10 | slides: https://talks.andersonbanihirwe.dev/deploying-dask-on-hpc-dask-summit-2021.html
11 | video: 'VIDEO '
12 | conference:
13 | name: Dask Summit 2021
14 | location: Virtual
15 | date: 2021-05-20
16 |
17 | - title: "Pangeo Use Case: Analyzing Initialized Climate Prediction System Datasets with climpred"
18 | slides: https://talks.andersonbanihirwe.dev/climpred-cdpw-2020.html
19 | video: ...
20 | conference:
21 | name: NOAA’s 45th Climate Diagnostics & Prediction Workshop
22 | location: Virtual
23 | date: 2020-10-20
24 |
25 | - title: "Zarr: chunked, compressed, multidimensional arrays"
26 | slides: https://talks.andersonbanihirwe.dev/zarr-cloud-native-geospatial-2020.html
27 | video: 'VIDEO '
28 | conference:
29 | name: Cloud Native Geospatial Outreach Day 2020
30 | location: Virtual
31 | date: 2020-09-08
32 |
33 | - title: "Intake-ESM – Making It Easier To Consume Climate and Weather Data"
34 | slides: https://talks.andersonbanihirwe.dev/intake-esm-esip-2020.html
35 | video: 'VIDEO '
36 | conference:
37 | name: ESIP Summer Meeting 2020
38 | location: Virtual
39 | date: 2020-07-23
40 |
41 | - title: "Dask and Pangeo"
42 | slides: https://speakerdeck.com/andersy005/dask-and-pangeo-a-community-platform-for-big-data-geoscience
43 | video: ...
44 | conference:
45 | name: Dask Developer Summit 2020
46 | location: Washington, District of Columbia, U.S.
47 | date: 2020-02-26
48 |
49 | - title: "Turning HPC Systems into Interactive Data Analysis Platforms using Jupyter and Dask"
50 | slides: https://talks.andersonbanihirwe.dev/dask-jupyter-scipy-2019.html
51 | video: 'VIDEO '
52 | conference:
53 | name: SciPy Conference 2019
54 | location: Austin, Texas, U.S.
55 | date: 2019-07-12
56 |
57 | - title: 'PySpark for "Big" Atmospheric Data Analysis'
58 | slides: https://opensky.ucar.edu/islandora/object/conference%3A3443/datastream/PDF/view
59 | video: ''
60 | conference:
61 | name: Eighth Symposium on Advances in Modeling and Analysis Using Python. American Meteorological Society
62 | location: Austin, Texas, U.S.
63 | date: 2018-01-08
64 |
65 | - title: 'PySpark for "Big" Atmospheric and Oceanic Data Analysis'
66 | slides: ...
67 | video: 'VIDEO '
68 | conference:
69 | name: 2017 NCAR/CISL SIParCS Internship
70 | location: Boulder, Colorado, U.S.
71 | date: 2017-08-23
72 |
--------------------------------------------------------------------------------
/posts/2020/a-knitting-weekend-with-dash.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2020-01-21
4 | tags: dash, documentation, docset, python
5 | ---
6 |
7 | # A Knitting Weekend with Dash and Python
8 |
9 | For the last few months, I've become a huge fan of the **quiet weekend**, the weekend when no plan is the plan, and you are in no hurry at all. I woke up on Saturday morning, and I decided that this weekend was going to be a quiet one. After watching a late morning football game from the English Premier League -- yup, I refuse to call it soccer 😀 -- I decided to write some code-nothing big, just a few lines of codes to improve my experience with [Dash](https://kapeli.com/dash), a tool that I've been using for a few months.
10 |
11 | Dash is a MacOS application that offers offline documentation for hundreds of programming languages, frameworks and libraries. Dash is awesome for offline programming when using spotty WiFi or on long-haul flights. While it is **free as in beer**, it's one of the programs that are worth paying for.
12 |
13 | ## The Problem
14 |
15 | I've been using Dash for quite some time and have been really satisfied with the preset selection of documentation sets. At some point, I started running into scenarios when I was using libraries/packages whose documentations aren't available for Dash. So, my objective was to generate documentation sets for these libraries myself. I should point out that I mostly work with Python packages, and most Python packages use [sphinx](https://www.sphinx-doc.org/) as their main framework for building documentation. So, my goal was to find a way to easily build documentation sets and integrate them with Dash.
16 |
17 | ## The Solution: Doc2dash and Sphinx To The Rescue
18 |
19 | After few minutes of google searches, I found doc2dash. [doc2dash](https://doc2dash.readthedocs.io/en/stable/) is a great tool for converting HTML documentation to Dash's format. doc2dash takes the output of Sphinx documentation and converts it to a Dash documentation package.
20 |
21 | ### Show Me The Code!
22 |
23 | In Just a few steps, I was able to build a docset for [Zarr](https://zarr.readthedocs.io/en/stable/) using dash2doc:
24 |
25 | - Create new conda environment and install dependencies
26 |
27 | ```bash
28 | $ conda create -n dash-docs -c conda-forge \
29 | doc2dash sphinx-rtd-theme numpydoc sphinx-issues
30 | $ conda activate dash-docs
31 | ```
32 |
33 | - Pull down the project form GitHub and build the documentation
34 |
35 | ```bash
36 | $ git clone https://github.com/zarr-developers/zarr-python.git
37 | $ cd zarr-python
38 | $ python -m pip install -e .
39 | $ cd docs
40 | $ make html
41 | ```
42 |
43 | - Finally, run doc2dash with a few commands
44 |
45 | ```bash
46 | $ doc2dash --name zarr --index-page index.html --enable-js \
47 | --add-to-dash _build/html
48 | ```
49 |
50 | And with that I had a shiny new Zarr docset in Dash:
51 |
52 | 
53 |
54 | Once I was confident that I understood how to do this for one project, I decided to automate this process for a bunch of other projects. By dinner time (on Saturday) I felt like I was on the right track. After a few more hours on Sunday and Monday, I had a [GitHub repository](https://github.com/andersy005/dash-docsets) with continuous integration via CircleCI up and running, and had a dozen docsets generated:
55 |
56 | 
57 |
58 | 
59 |
60 | ## Was It Worth Fifteen or Twenty Hours of My Life?
61 |
62 | **I think so:** I took pleasure in doing something that I knew how to do and in creating something that would fit my needs perfectly.
63 |
64 | Sitting in a chair in front a computer screen while listening to MIX 100 Denver Radio station 😀, I was reminded of the [intriguing parallels between knitting and programming](https://www.nytimes.com/2019/05/17/science/math-physics-knitting-matsumoto.html):
65 |
66 | > "Knitting is Coding, and Yarn is a Programmable material."
67 |
68 | _On quiet weekends like this I write code for fun, and Visual Studio Code & Python are my yarn and needles._
69 |
--------------------------------------------------------------------------------
/teaching_gallery.md:
--------------------------------------------------------------------------------
1 | ``````{grid} 2
2 | :class-container: full-width
3 |
4 | `````{grid-item-card} Xarray Tutorial | xarray fundamentals
5 | :text-align: center
6 | VIDEO
7 | +++
8 |
9 | ````{grid} 2 2 2 2
10 | :margin: 0 0 0 0
11 | :padding: 0 0 0 0
12 | :gutter: 1
13 |
14 | ```{grid-item}
15 | :child-direction: row
16 | :child-align: start
17 | :class: sd-fs-5
18 | {bdg-link-secondary}`repo `
19 | ```
20 |
21 | ```{grid-item}
22 | :child-direction: row
23 | :child-align: end
24 | [](https://github.com/andersy005/xarray-tutorial)
25 | ```
26 |
27 | ````
28 |
29 | `````
30 |
31 | `````{grid-item-card} NCAR Python Tutorial Seminar Series - Xarray Part 1
32 | :text-align: center
33 | VIDEO
34 | +++
35 |
36 | ````{grid} 2 2 2 2
37 | :margin: 0 0 0 0
38 | :padding: 0 0 0 0
39 | :gutter: 1
40 |
41 | ```{grid-item}
42 | :child-direction: row
43 | :child-align: start
44 | :class: sd-fs-5
45 | {bdg-link-secondary}`repo `
46 | ```
47 |
48 | ```{grid-item}
49 | :child-direction: row
50 | :child-align: end
51 | [](https://github.com/andersy005/xarray-tutorial)
52 | ```
53 |
54 | ````
55 |
56 | `````
57 |
58 | `````{grid-item-card} NCAR Python Tutorial Seminar Series - Xarray Part 2
59 | :text-align: center
60 | VIDEO
61 | +++
62 |
63 | ````{grid} 2 2 2 2
64 | :margin: 0 0 0 0
65 | :padding: 0 0 0 0
66 | :gutter: 1
67 |
68 | ```{grid-item}
69 | :child-direction: row
70 | :child-align: start
71 | :class: sd-fs-5
72 | {bdg-link-secondary}`repo `
73 | ```
74 |
75 | ```{grid-item}
76 | :child-direction: row
77 | :child-align: end
78 | [](https://github.com/andersy005/xarray-tutorial)
79 | ```
80 |
81 | ````
82 |
83 | `````
84 |
85 | `````{grid-item-card} NCAR Python Tutorial Seminar Series - Dask Part 1
86 | :text-align: center
87 | VIDEO
88 | +++
89 |
90 | ````{grid} 2 2 2 2
91 | :margin: 0 0 0 0
92 | :padding: 0 0 0 0
93 | :gutter: 1
94 |
95 | ```{grid-item}
96 | :child-direction: row
97 | :child-align: start
98 | :class: sd-fs-5
99 | {bdg-link-secondary}`repo `
100 | ```
101 |
102 | ```{grid-item}
103 | :child-direction: row
104 | :child-align: end
105 | [](https://github.com/andersy005/xarray-tutorial)
106 | ```
107 |
108 | ````
109 |
110 | `````
111 |
112 | `````{grid-item-card} NCAR Python Tutorial Seminar Series - Dask P2
113 | :text-align: center
114 | VIDEO
115 | +++
116 |
117 | ````{grid} 2 2 2 2
118 | :margin: 0 0 0 0
119 | :padding: 0 0 0 0
120 | :gutter: 1
121 |
122 | ```{grid-item}
123 | :child-direction: row
124 | :child-align: start
125 | :class: sd-fs-5
126 | {bdg-link-secondary}`repo `
127 | ```
128 |
129 | ```{grid-item}
130 | :child-direction: row
131 | :child-align: end
132 | [](https://github.com/andersy005/xarray-tutorial)
133 | ```
134 |
135 | ````
136 |
137 | `````
138 |
139 | ``````
140 |
--------------------------------------------------------------------------------
/posts/2021/how-to-merge-disk-partitions-on-centos.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2021-01-07
4 | tags: todayilearned, linux, centos
5 | ---
6 |
7 | # How to merge two or more disk partitions on Centos 7
8 |
9 | I've been working with centos 7 virtual machine provisioned via VMware's vrealize suite. One thing I particulary dislike is how the storage disk gets partitioned into tiny partititions during the VM provisioning:
10 |
11 | ```bash
12 | $ df -h
13 | Filesystem Size Used Avail Use% Mounted on
14 | devtmpfs 1.9G 0 1.9G 0% /dev
15 | tmpfs 1.9G 0 1.9G 0% /dev/shm
16 | tmpfs 1.9G 8.9M 1.9G 1% /run
17 | tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
18 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-root 6.0G 70M 6.0G 2% /
19 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-usr 6.0G 1.5G 4.6G 24% /usr
20 | /dev/sda1 1014M 232M 783M 23% /boot
21 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-data 61G 34M 61G 1% /data
22 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-usr_local 6.0G 33M 6.0G 1% /usr/local
23 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-home 10G 33M 10G 1% /home
24 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-var 6.0G 414M 5.6G 7% /var
25 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-tmp 2.0G 33M 2.0G 2% /tmp
26 | tmpfs 379M 0 379M 0% /run/user/1001
27 | ```
28 |
29 | Notice how `var`, `data`, `home`, `tmp`, `usr`, `usr_local`, and `root` have their own partitions. I prefer to have a few but large disk partitions. So, today I figured out how to merge two or more partitions into the root partition (thank you, @kmpaul for the help and documenting this!).
30 |
31 | ## Step 1 — Make sure you are logged in as root
32 |
33 | ## Step 2 — Backup data from the partitions you want to merge into the root partiton
34 |
35 | ```bash
36 | $ rsync -a /home/ /home-old/
37 | $ rsync -a /tmp/ /tmp-old/
38 | $ rsync -a /var/ /var-old/
39 | ```
40 |
41 | ## Step 3 — Reboot the VM into an emergency mode
42 |
43 | ```bash
44 | $ systemctl emergency
45 | ```
46 |
47 | ## Step 4 — Umount and remove logic volume for each of the partitions
48 |
49 | ```bash
50 | $ umount /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-data
51 | $ umount /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-home
52 | $ umount /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-var
53 | $ umount /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-tmp
54 | ```
55 |
56 | ```bash
57 | $ lvremove /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-data
58 | $ lvremove /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-home
59 | $ lvremove /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-var
60 | $ lvremove /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-tmp
61 | ```
62 |
63 | ## Step 5 — Copy the backed up data
64 |
65 | ```bash
66 | $ rsync -a /home-old/ /home/
67 | $ rsync -a /var-old/ /var/
68 | $ rsync -a /tmp-old/ /tmp/
69 | ```
70 |
71 | ## Step 6 — Edit the `/etc/fstab` file by removing or commenting out the partitions we don't need
72 |
73 | ```bash
74 | $ vi /etc/fstab
75 | ```
76 |
77 | ## Step 7 — Extend the root partition to fill the remaining space
78 |
79 | ```bash
80 | $ lvextend -l +100%FREE -r /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-root
81 | ```
82 |
83 | ## Step 8 — Remove the backups
84 |
85 | ```bash
86 | $ rm -rf /home-old/ /tmp-old/ /var-old/
87 | ```
88 |
89 | ## Step 9 — Reboot the system
90 |
91 | ```bash
92 | $ reboot
93 | ```
94 |
95 | ## Step 10 — Login to the VM as a regular user or root
96 |
97 | Let's check that our `/` root partition size has increased:
98 |
99 | ```bash
100 | $ df -h
101 | Filesystem Size Used Avail Use% Mounted on
102 | devtmpfs 1.9G 0 1.9G 0% /dev
103 | tmpfs 1.9G 0 1.9G 0% /dev/shm
104 | tmpfs 1.9G 8.9M 1.9G 1% /run
105 | tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
106 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-root 85G 474M 85G 1% /
107 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-usr 6.0G 1.5G 4.6G 24% /usr
108 | /dev/sda1 1014M 232M 783M 23% /boot
109 | /dev/mapper/centos_dhcp--zzz--zzz--zzz--zz-usr_local 6.0G 33M 6.0G 1% /usr/local
110 | tmpfs 379M 0 379M 0% /run/user/1001
111 | ```
112 |
113 | Voilà! 🙌
114 |
--------------------------------------------------------------------------------
/posts/2022/multitude.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2022-03-06
4 | tags: music, francais
5 | ---
6 |
7 | # « Multitude de Stromae » - Des morceaux aussi forts sur des sujets si primordials 🎶
8 |
9 | J'ai passé le week-end en ecoutant en boucle l'intégralité du nouvel album de Stromae, intitulé [**"Multitude"**](https://music.youtube.com/playlist?list=OLAK5uy_kDes3UKBSh3zb1ZwRE8r3x6-6bDTM6jzY). L'album est sublime. Les morceaux, les instrumentals sont sensationnels. Les rythmes, les thèmes abordés (la dépression, la solitude, le suicide, la maladie, la prostitution, le féminisme, l'abandon, etc...) sont bien équilibrés 👏🏽🙏🏽!
10 |
11 | 
12 | _© Stromae – Multitude / Universal Music_
13 |
14 | Dans ce blog, je veux partager mes morceaux préférés de cet album.
15 |
16 | - **Invaincu**: est un morceau puissant sur la survie, alimenté par des beats triomphants 🔥🔥:
17 |
18 | > « Tant que je suis en vie je suis invaincu » ...
19 |
20 | VIDEO
21 |
22 | - **La solassitude**: l'instrumental est juste phenoménal. Stromae présente l'ironie de la vie et de l'amour (la solitude quand on est célibataire, la lassitude en couple):
23 |
24 | > « Le problème, c'est la routine, quand les jours se ressеmblent... C'qui m'tue, c'est l'еnnui, est-c'qu'on finira ensemble? » ...
25 |
26 | > « Le célibat me fait souffrir de solitude, La vie de couple me fait souffrir de lassitude » ...
27 |
28 | VIDEO
29 |
30 | - **Riez**: Sûrement le meilleur morceau (numero 1 de mon classement). Le sujet de la chanson est les rêves, les fantasmes de la vie. La chanson se comprend à l'envers: de vouloir la nécessité fondamentale de la vie à tout avoir et pourtant pas satisfait et en vouloir toujours plus. Rions pour le reveur en chacun de nous:
31 |
32 | > « C’que j’voudrais c’est d’manger à ma faim,
33 | > Tous les jours de l’année..
34 | > Et puis j’me demande si enfin,
35 | > En grand, j’pourrais rêver » ...
36 |
37 | > « Moi un jour, je s’rai un grand artiste,
38 | > J’gagnerai même un Grammy..
39 | > J’aurai des sous et tellement je s’rai riche,
40 | > J’aurai même plein d’amis » ...
41 |
42 | VIDEO
43 |
44 | - **Déclaration**: Un délice ce morceau (numero 2 de mon classement). Dans ce sublime, sobre chanson avec un message clair, Stromae plaidoye pour les femmes ✨🎗. "Déclaration" aborde des sujets sociaux qui reposent entièrement sur les épaules des femmes: enfanter, la contraception et l’endométriose:
45 |
46 | > « Si l’courage avait un visage, il aurait l’tien » ...
47 |
48 | > « Toujours obligée d’aimer enfanter, La contraception qui te détruit la santé, Endométriose, enchantée, J'suis mieux payé que toi sans vouloir me vanter » ...
49 |
50 | > « T’inquiète pas ça va aller, faudra bien que ça change. Ça prendra quelques années vu que ça nous arrange » ...
51 |
52 | VIDEO
53 |
54 | - **Bonne journée**: le morceaux plaisir coupable:
55 |
56 | > « Le bonheur est bien la seule chose qui quand on la partage se multiplie
57 | > Je vois la vie en rose, dis moi, est ce que tu la vois aussi ? » ...
58 |
59 | > « Si l'bonheur des autres te rends malheureux, c'est que t'es un rageux
60 | > Si l'malheur des autres te rends heureux hmm, c'est que t'es un rageux » ...
61 |
62 | VIDEO
63 |
64 | Comme le titre l'indique, l'album est vraiment une multitude de sons, une multitude de themes, instruments, etc... **37 minutes de pure qualité** pour les amoureux de la musique et surtout pour les fans de Stromae. L'album est vraiment très propre après plusieurs écoute. Il valait la peine d'attendre :). Voici l'album complet sur YouTube. Enjoy 😊...
65 |
66 | VIDEO
67 |
--------------------------------------------------------------------------------
/posts/drafts/bayesian-for-hackers/probability-distributions.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import ipywidgets\n",
10 | "import numpy as np\n",
11 | "import proplot as plt\n",
12 | "import scipy.stats"
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": 2,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "a = np.arange(16)\n",
22 | "colors = ['#348ABD', '#A60628']"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 3,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "def poisson_dist(λ=1.5):\n",
32 | " fig, ax = plt.subplots(aspect=(3.5, 2), width=6)\n",
33 | " ax.bar(\n",
34 | " a,\n",
35 | " scipy.stats.poisson.pmf(a, λ),\n",
36 | " color=colors[0],\n",
37 | " alpha=0.60,\n",
38 | " edgecolor=colors[0],\n",
39 | " lw='3',\n",
40 | " label=rf'$\\lambda ={λ}',\n",
41 | " )\n",
42 | " ax.format(\n",
43 | " xticks=a,\n",
44 | " ylabel='Probability of $k$',\n",
45 | " xlabel='$k$',\n",
46 | " title='Probability mass function of a Poisson random variable',\n",
47 | " )\n",
48 | " plt.close(fig)\n",
49 | " return fig"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": 4,
55 | "metadata": {},
56 | "outputs": [
57 | {
58 | "data": {
59 | "application/vnd.jupyter.widget-view+json": {
60 | "model_id": "5065558a0b5f4e82a19fa8b6c041e6fd",
61 | "version_major": 2,
62 | "version_minor": 0
63 | },
64 | "text/plain": [
65 | "interactive(children=(FloatSlider(value=1.5, description='λ', max=20.0, min=1.0, step=1.0), Output()), _dom_cl…"
66 | ]
67 | },
68 | "metadata": {},
69 | "output_type": "display_data"
70 | }
71 | ],
72 | "source": [
73 | "ipywidgets.interact(poisson_dist, λ=ipywidgets.FloatSlider(min=1, max=20, value=1.5, step=1))"
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": 5,
79 | "metadata": {},
80 | "outputs": [],
81 | "source": [
82 | "a = np.linspace(0, 4, 100)\n",
83 | "\n",
84 | "\n",
85 | "def exponential_dist(λ=0.5):\n",
86 | " exp = scipy.stats.expon.pdf(a, scale=1.0 / λ)\n",
87 | " fig, ax = plt.subplots(aspect=(3.5, 2), width=6)\n",
88 | " ax.plot(a, exp, color=colors[0], label=rf'$\\lambda ={λ}', lw=3)\n",
89 | " ax.fill_between(a, exp, color=colors[0], alpha=0.33)\n",
90 | " ax.format(\n",
91 | " ylabel='Probability density function at of $z$',\n",
92 | " xlabel='$z$',\n",
93 | " title='Probability density function of an exponential random variable',\n",
94 | " ylim=(0, 1.2),\n",
95 | " )\n",
96 | " plt.close(fig)\n",
97 | " return fig"
98 | ]
99 | },
100 | {
101 | "cell_type": "code",
102 | "execution_count": 6,
103 | "metadata": {},
104 | "outputs": [
105 | {
106 | "data": {
107 | "application/vnd.jupyter.widget-view+json": {
108 | "model_id": "63237957561241fda8edec586f6b4b07",
109 | "version_major": 2,
110 | "version_minor": 0
111 | },
112 | "text/plain": [
113 | "interactive(children=(FloatSlider(value=0.5, description='λ', max=1.0, min=0.1), Output()), _dom_classes=('wid…"
114 | ]
115 | },
116 | "metadata": {},
117 | "output_type": "display_data"
118 | }
119 | ],
120 | "source": [
121 | "ipywidgets.interact(exponential_dist, λ=ipywidgets.FloatSlider(min=0.1, max=1, value=0.5))"
122 | ]
123 | },
124 | {
125 | "cell_type": "code",
126 | "execution_count": 7,
127 | "metadata": {},
128 | "outputs": [
129 | {
130 | "name": "stdout",
131 | "output_type": "stream",
132 | "text": [
133 | "Last updated: 2020-11-27\n",
134 | "\n",
135 | "Git hash: 0f38d2abc8e59398ce2708ab976146a134652ccf\n",
136 | "\n",
137 | "Git repo: git@github.com:andersy005/blog.git\n",
138 | "\n",
139 | "Git branch: main\n",
140 | "\n",
141 | "scipy : 1.5.3\n",
142 | "ipywidgets: 7.5.1\n",
143 | "numpy : 1.19.4\n",
144 | "proplot : 0.6.4\n",
145 | "\n"
146 | ]
147 | }
148 | ],
149 | "source": [
150 | "%load_ext watermark\n",
151 | "%watermark -grb -du -iv"
152 | ]
153 | }
154 | ],
155 | "metadata": {
156 | "kernelspec": {
157 | "display_name": "Python 3",
158 | "language": "python",
159 | "name": "python3"
160 | },
161 | "language_info": {
162 | "codemirror_mode": {
163 | "name": "ipython",
164 | "version": 3
165 | },
166 | "file_extension": ".py",
167 | "mimetype": "text/x-python",
168 | "name": "python",
169 | "nbconvert_exporter": "python",
170 | "pygments_lexer": "ipython3",
171 | "version": "3.8.5"
172 | },
173 | "widgets": {
174 | "application/vnd.jupyter.widget-state+json": {
175 | "state": {},
176 | "version_major": 2,
177 | "version_minor": 0
178 | }
179 | }
180 | },
181 | "nbformat": 4,
182 | "nbformat_minor": 4
183 | }
184 |
--------------------------------------------------------------------------------
/posts/2021/dictionary-merge-and-update-operators.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "difficult-gather",
6 | "metadata": {},
7 | "source": [
8 | "# Dictionary Merge and Update Operators in Python 3.9\n",
9 | "\n",
10 | "When it comes to merging two dictinaries in Python, I find myself googling \"how to merge two dictionaries\" very often. Every time I land on this [StackOverflow answer](https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-taking-union-of-dictiona). This answers recommends using the **dictionary unpacking** feature:"
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 1,
16 | "id": "705af7b6-2a9c-48b8-997e-0085065f2506",
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "x = {'earth': 5.97, 'mercury': 0.330}\n",
21 | "y = {'uranus': 86.8, 'mars': 0.642, 'earth': -999}"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 2,
27 | "id": "e1b0c166-f93f-4b98-812f-1b53d5f19c4c",
28 | "metadata": {},
29 | "outputs": [
30 | {
31 | "data": {
32 | "text/plain": [
33 | "{'earth': -999, 'mercury': 0.33, 'uranus': 86.8, 'mars': 0.642}"
34 | ]
35 | },
36 | "execution_count": 2,
37 | "metadata": {},
38 | "output_type": "execute_result"
39 | }
40 | ],
41 | "source": [
42 | "a = {**x, **y}\n",
43 | "a"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "id": "610a134b-99c6-40a6-b840-61f14e1ab183",
49 | "metadata": {},
50 | "source": [
51 | "Even though I have seen dictionary unpacking used for unpacking keyword arguments in functions, I've **rarely seen it being used as a method for merging dictionaries**, and this makes it a **bit confusing** if you haven't seen it used in this context. I was delighted when I found out that Python 3.9 introduced a dedicated binary operator that permits merging two dictionaries. In Python 3.9, we can use the `|` (bitwise `OR`) to perform a dictionary merge:"
52 | ]
53 | },
54 | {
55 | "cell_type": "code",
56 | "execution_count": 3,
57 | "id": "c8ec51c4-9d85-4acd-b95a-ff9fe39c5142",
58 | "metadata": {},
59 | "outputs": [
60 | {
61 | "data": {
62 | "text/plain": [
63 | "{'earth': -999, 'mercury': 0.33, 'uranus': 86.8, 'mars': 0.642}"
64 | ]
65 | },
66 | "execution_count": 3,
67 | "metadata": {},
68 | "output_type": "execute_result"
69 | }
70 | ],
71 | "source": [
72 | "b = x | y\n",
73 | "b"
74 | ]
75 | },
76 | {
77 | "cell_type": "markdown",
78 | "id": "bccd2266-d5dc-4c7b-aa47-166022184e32",
79 | "metadata": {},
80 | "source": [
81 | "As you can see, the resulting dictionary consists of a new dictionary with all the keys of both `x` and `y` dictionaries. Because `x` and `y` have overlapping key `earth`, the new dictionary uses the values from the rightmost dictionary (i.e. `y`)"
82 | ]
83 | },
84 | {
85 | "cell_type": "markdown",
86 | "id": "830c0a36-e825-4753-9845-e3a4aa0e47f6",
87 | "metadata": {},
88 | "source": [
89 | "If we prefer to update one of the dictionary inplace (i.e. without needing to create a new dictionary), we can use the `|=` (in-place bitwise `OR`) operator"
90 | ]
91 | },
92 | {
93 | "cell_type": "code",
94 | "execution_count": 4,
95 | "id": "daaf995f-d201-4945-b9a7-e4c17b582054",
96 | "metadata": {},
97 | "outputs": [],
98 | "source": [
99 | "x |= y"
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": 5,
105 | "id": "fab77b58-cc3d-4ea1-83bd-f6752a993447",
106 | "metadata": {},
107 | "outputs": [
108 | {
109 | "data": {
110 | "text/plain": [
111 | "{'earth': -999, 'mercury': 0.33, 'uranus': 86.8, 'mars': 0.642}"
112 | ]
113 | },
114 | "execution_count": 5,
115 | "metadata": {},
116 | "output_type": "execute_result"
117 | }
118 | ],
119 | "source": [
120 | "x"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "id": "727bce58-99fc-45e9-bf14-ca0f7a30b55d",
126 | "metadata": {},
127 | "source": [
128 | "I really dig this new `|` operator. I find the syntax easy to remember and understand compared with the **dictionary unpacking** feature that I used prior to Python 3.9. There's one problem though. This operator is only available for Python 3.9+ and I have to write code for older versions of Python for the time being 😞."
129 | ]
130 | }
131 | ],
132 | "metadata": {
133 | "author": "Anderson Banihirwe",
134 | "date": "2021-06-04",
135 | "kernelspec": {
136 | "display_name": "Python 3",
137 | "language": "python",
138 | "name": "python3"
139 | },
140 | "language_info": {
141 | "codemirror_mode": {
142 | "name": "ipython",
143 | "version": 3
144 | },
145 | "file_extension": ".py",
146 | "mimetype": "text/x-python",
147 | "name": "python",
148 | "nbconvert_exporter": "python",
149 | "pygments_lexer": "ipython3",
150 | "version": "3.9.4"
151 | },
152 | "tags": "python,todayilearned",
153 | "title": "Dictionary Merge and Update Operators in Python 3.9",
154 | "widgets": {
155 | "application/vnd.jupyter.widget-state+json": {
156 | "state": {},
157 | "version_major": 2,
158 | "version_minor": 0
159 | }
160 | }
161 | },
162 | "nbformat": 4,
163 | "nbformat_minor": 5
164 | }
165 |
--------------------------------------------------------------------------------
/posts/2019/scipy-2019.md:
--------------------------------------------------------------------------------
1 | ---
2 | author: Anderson Banihirwe
3 | date: 2019-07-21
4 | tags: scipy, conference
5 | ---
6 |
7 | # Reflecting on SciPy 2019: My first SciPy, definitely not my last
8 |
9 | It's been a week since SciPy 2019 conference came to a close. I had the pleasure of speaking at SciPy 2019 about [**interactive supercomputing with Dask and Jupyter**](https://andersonbanihirwe.dev/talks/dask-jupyter-scipy-2019.html). I am so thankful for the chance to speak in the Earth, Ocean, Geo and Atmospheric Science track! Here's a recording of my talk:
10 |
11 | VIDEO
12 |
13 | As I look back at my first [SciPy](https://www.scipy2019.scipy.org/), I can say that it was the most productive conference that I've been to so far. So, I wanted to take this opportunity to summarize my key takeaways.
14 |
15 | ## 1. The Awesomeness of SciPy Community
16 |
17 | The biggest highlight of SciPy for me was the **community**.
18 | **What an authentic, super-talented, enthusiastic and welcoming community!** I met and interacted with a lot of amazing people that I only knew via Github prior the conference :). The community is really what makes SciPy such a special conference.
19 |
20 | ## 2. Invisible Work in Open Source Software Projects
21 |
22 | > Because so much of the work in OSS is tracked on public platforms, it is easy to forget about the work that takes place outside of them.
23 |
24 | This quote by Stuart really hit home. For the last few months, I've become a core maintainer of a few projects, and one of the things I've learned so far as a user, a contributor to, and core maintainer of an open source project is that it's really important to recognize that the github repository does not fully represent a project. **There's quite a lot of crucial, untracked work that goes on in the background** such as:
25 |
26 | 
27 |
28 | > Credit: Karthik Ram: http://inundata.org/talks/sdss
29 |
30 | You can watch the full key note here:
31 |
32 | VIDEO
33 |
34 | ## 3. Tell People When You Appreciate Their Work
35 |
36 | Another key lessons I learned is from [Carol Willing's keynote](https://www.youtube.com/watch?v=s-W-UvGgDco&list=PLYx7XA2nY5GcDQblpQ_M1V3PQPoLWiDAC&index=71) is that research shows that meeting someone who has befitted from your work can double your effort and triple your productivity:
37 |
38 | 
39 |
40 | > Credit: Carol Willing: https://speakerdeck.com/willingc/jupyter-always-open-for-learning-and-discovery
41 |
42 | ## 4. We Should Think About Open Source Standards
43 |
44 | Matthew Rocklin gave a great talk on [refactoring the SciPy ecosystem for heterogeneous computing](http://matthewrocklin.com/slides/scipy-2019.html).
45 |
46 | VIDEO
47 |
48 | My takeaway from his talk is that
49 |
50 | > The Python scientific community fractures when we develop competing packages that are not compatible with each other and thrives when we develop tools based on common standards.
51 |
52 | As software developers, we should try to follow already existing standards when we can, because standards level the playing field in so many ways:
53 |
54 | - new technologies can quickly compete
55 | - new developers can quickly engage
56 | - incentivize support (e.g. GitHub renders `.ipynb` since Jupyter notebooks are built on a widely used standard)
57 |
58 | ## 5. Jupyter Notebooks Come Alive with Jupyter Widgets
59 |
60 | One of my favorite SciPy 2019 talks is Martin and Maarten's talk on **Dashboarding with Jupyter Notebooks, Voilà and Widgets**. It is really fun and full of cool stuffs.
61 |
62 | VIDEO
63 |
64 | I am looking forward to making my own widgets and dashboards! And exclaiming **voilà!** after I deploy them!
65 |
66 | ## 6. Maslow’s Hierarchy of Software Needs
67 |
68 | Stan's talk on **How to Accelerate an Existing Codebase with Numba** is also among my favorites. The Key lesson from this talk is the following:
69 |
70 | > Be honest with yourself about where your project is in this hierarchy. If your program doesn't run, there's no point in making it faster.
71 |
72 | 
73 |
74 | > Credit: Stan Seibert
75 |
76 | VIDEO
77 |
78 | ## 7. Final Thoughts
79 |
80 | I left SciPy 2019 feeling:
81 |
82 | - **very thankful** that so many amazing people are able to come out and collaborate on the projects that are so vital to the Python scientific ecocystem!
83 | - **grateful** to be part of this community.
84 | - **inspired** to keep contributing to this community.
85 | - **so excited** about the technology, the science, and the people.
86 |
87 | **Thank you so much to the SciPy Conference organizers for putting on a great conference.**
88 |
--------------------------------------------------------------------------------
/posts/2021/function-expressions-in-js.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Function Expressions in JavaScript\n",
8 | "\n",
9 | "I'm currently learning JavaScript, and here are a few things I learned about\n",
10 | "function expressions in JavaScript ;)\n"
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {},
16 | "source": [
17 | "## Anonymous vs Named Functions\n"
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": 1,
23 | "metadata": {},
24 | "outputs": [],
25 | "source": [
26 | "// An anonymous function ==> lambda function in Python\n",
27 | "const clickHandler = function(){\n",
28 | " console.log('The user clicked this button.')\n",
29 | "}"
30 | ]
31 | },
32 | {
33 | "cell_type": "code",
34 | "execution_count": 2,
35 | "metadata": {},
36 | "outputs": [],
37 | "source": [
38 | "// Named Function \n",
39 | "const keyHandler = function keyHandler() {\n",
40 | " console.log('This is a named function.')\n",
41 | "}"
42 | ]
43 | },
44 | {
45 | "cell_type": "code",
46 | "execution_count": 3,
47 | "metadata": {},
48 | "outputs": [
49 | {
50 | "name": "stdout",
51 | "output_type": "stream",
52 | "text": [
53 | "The user clicked this button.\n"
54 | ]
55 | }
56 | ],
57 | "source": [
58 | "clickHandler()"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": 4,
64 | "metadata": {},
65 | "outputs": [
66 | {
67 | "name": "stdout",
68 | "output_type": "stream",
69 | "text": [
70 | "This is a named function.\n"
71 | ]
72 | }
73 | ],
74 | "source": [
75 | "keyHandler()"
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": 5,
81 | "metadata": {},
82 | "outputs": [],
83 | "source": [
84 | "const cars = [{make: 'toyota', id: 'Rav4'}, {make: 'tesla', id: 'S'}]"
85 | ]
86 | },
87 | {
88 | "cell_type": "code",
89 | "execution_count": 6,
90 | "metadata": {},
91 | "outputs": [
92 | {
93 | "name": "stdout",
94 | "output_type": "stream",
95 | "text": [
96 | "[ \u001b[32m'Rav4'\u001b[39m, \u001b[32m'S'\u001b[39m ]\n"
97 | ]
98 | }
99 | ],
100 | "source": [
101 | "// Arrow Function \n",
102 | "let ids = cars.map(car => car.id)\n",
103 | "console.log(ids)"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 7,
109 | "metadata": {},
110 | "outputs": [
111 | {
112 | "name": "stdout",
113 | "output_type": "stream",
114 | "text": [
115 | "[ \u001b[32m'Rav4'\u001b[39m, \u001b[32m'S'\u001b[39m ]\n"
116 | ]
117 | }
118 | ],
119 | "source": [
120 | "// An equivalent named function\n",
121 | "ids = cars.map(function getId(car){\n",
122 | " return car.id\n",
123 | "})\n",
124 | "console.log(ids)"
125 | ]
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "metadata": {},
130 | "source": [
131 | "### Takeaways:\n",
132 | "\n",
133 | "- When it comes to\n",
134 | " [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions),\n",
135 | " I often find myself having to carefully read the function body to figure out\n",
136 | " what's going on.\n",
137 | "- IMHO, named functions are the best because they tell us in their name what\n",
138 | " they do.\n"
139 | ]
140 | },
141 | {
142 | "cell_type": "markdown",
143 | "metadata": {},
144 | "source": [
145 | "## Immediately Invoked Function Expressions (IIFE)\n"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": 8,
151 | "metadata": {},
152 | "outputs": [],
153 | "source": [
154 | "const school = 'MIT'"
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": 9,
160 | "metadata": {},
161 | "outputs": [
162 | {
163 | "name": "stdout",
164 | "output_type": "stream",
165 | "text": [
166 | "CMU\n"
167 | ]
168 | }
169 | ],
170 | "source": [
171 | "(function anotherSchool(){\n",
172 | " const school = 'CMU'\n",
173 | " console.log(school)\n",
174 | "})()"
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "execution_count": 10,
180 | "metadata": {},
181 | "outputs": [
182 | {
183 | "name": "stdout",
184 | "output_type": "stream",
185 | "text": [
186 | "MIT\n"
187 | ]
188 | }
189 | ],
190 | "source": [
191 | "console.log(school)"
192 | ]
193 | },
194 | {
195 | "cell_type": "markdown",
196 | "metadata": {},
197 | "source": [
198 | "### Takeaways:\n",
199 | "\n",
200 | "- IIFEs are typically used in places in our code where we need to collect a set\n",
201 | " of variables and protect them from intruding an outer scope.\n"
202 | ]
203 | }
204 | ],
205 | "metadata": {
206 | "author": "Anderson Banihirwe",
207 | "date": "2021-01-14",
208 | "kernelspec": {
209 | "display_name": "JavaScript",
210 | "language": "javascript",
211 | "name": "jslab"
212 | },
213 | "language_info": {
214 | "file_extension": ".js",
215 | "mimetype": "text/javascript",
216 | "name": "javascript",
217 | "version": ""
218 | },
219 | "tags": "javascript,todayilearned",
220 | "title": "Function Expressions in JavaScript",
221 | "widgets": {
222 | "application/vnd.jupyter.widget-state+json": {
223 | "state": {},
224 | "version_major": 2,
225 | "version_minor": 0
226 | }
227 | }
228 | },
229 | "nbformat": 4,
230 | "nbformat_minor": 4
231 | }
232 |
--------------------------------------------------------------------------------
/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | import datetime
3 | import pathlib
4 | from textwrap import dedent
5 | from urllib.parse import urlparse
6 |
7 | import yaml
8 | from sphinx.application import Sphinx
9 | from sphinx.util import logging
10 |
11 | LOGGER = logging.getLogger('conf')
12 |
13 | # -- Project information -----------------------------------------------------
14 |
15 | project = 'Paysage Pythonique'
16 | license_message = (
17 | 'Except where otherwise noted, this work is licensed under '
18 | 'a Creative Commons Attribution-ShareAlike 4.0 International License'
19 | )
20 | copyright = f'2018-{datetime.datetime.now().year}. {license_message}'
21 | author = 'Anderson Banihirwe'
22 | html_last_updated_fmt = '%b %d, %Y'
23 |
24 | extensions = [
25 | 'myst_nb',
26 | 'ablog',
27 | 'sphinx_panels',
28 | 'sphinx_design',
29 | 'sphinxcontrib.bibtex',
30 | 'sphinxext.opengraph',
31 | 'sphinx_comments',
32 | ]
33 |
34 | # Add any paths that contain templates here, relative to this directory.
35 | templates_path = ['_templates']
36 |
37 | exclude_patterns = [
38 | '_build',
39 | 'Thumbs.db',
40 | '.DS_Store',
41 | '*import_posts*',
42 | '**/pandoc_ipynb/inputs/*',
43 | ]
44 |
45 | html_theme = 'pydata_sphinx_theme'
46 |
47 | html_theme_options = {
48 | 'github_url': 'https://github.com/andersy005/',
49 | 'twitter_url': 'https://twitter.com/andersy005',
50 | 'search_bar_text': 'Search this site...',
51 | 'google_analytics_id': 'UA-91185106-1',
52 | 'search_bar_position': 'navbar',
53 | }
54 | html_theme_options['analytics'] = {
55 | # The domain you'd like to use for this analytics instance
56 | 'plausible_analytics_domain': 'blog.andersonbanihirwe.dev',
57 | # The analytics script that is served by Plausible
58 | 'plausible_analytics_url': 'https://plausible.andersonb.xyz/js/script.js',
59 | }
60 |
61 | html_favicon = '_static/share.png'
62 | html_title = ''
63 |
64 | # Add any paths that contain custom static files (such as style sheets) here,
65 | # relative to this directory. They are copied after the builtin static files,
66 | # so a file named "default.css" will overwrite the builtin "default.css".
67 | html_static_path = ['_static']
68 | html_extra_path = ['feed.xml']
69 | html_sidebars = {
70 | 'index': ['hello.html'],
71 | 'about': ['hello.html'],
72 | 'publications': ['hello.html'],
73 | 'projects': ['hello.html'],
74 | 'talks': ['hello.html'],
75 | 'posts': ['tagcloud.html', 'archives.html'],
76 | 'posts/**': ['postcard.html', 'recentposts.html', 'archives.html'],
77 | }
78 | blog_baseurl = 'https://blog.andersonbanihirwe.dev'
79 | blog_title = 'Paysage Pythonique'
80 | blog_path = 'posts'
81 | fontawesome_included = True
82 | blog_post_pattern = 'posts/*/*'
83 | post_redirect_refresh = 1
84 | post_auto_image = 1
85 | post_auto_excerpt = 1
86 |
87 |
88 | # Panels config
89 | panels_add_bootstrap_css = False
90 |
91 | # MyST config
92 | myst_enable_extensions = ['amsmath', 'colon_fence', 'deflist', 'html_image']
93 | myst_url_schemes = ['http', 'https', 'mailto']
94 |
95 | # OpenGraph config
96 | ogp_site_url = 'https://blog.andersonbanihirwe.dev'
97 | ogp_image = 'https://blog.andersonbanihirwe.dev/_static/share.png'
98 | ogp_site_name = f' {blog_title} | Anderson Banihirwe'
99 | ogp_custom_meta_tags = [
100 | ' ',
101 | ' ',
102 | ' ',
103 | ]
104 |
105 | # Temporarily stored as off until we fix it
106 | jupyter_execute_notebooks = 'off'
107 |
108 | comments_config = {
109 | 'utterances': {'repo': 'andersy005/blog', 'optional': 'config', 'label': '💬 comment'},
110 | 'hypothesis': False,
111 | }
112 |
113 |
114 | def build_teaching_gallery(app: Sphinx):
115 | LOGGER.info('Building teaching gallery')
116 | path = pathlib.Path(app.srcdir) / 'config_data/teaching.yaml'
117 | teaching = yaml.safe_load(path.read_text())
118 | teaching = sorted(teaching, key=lambda item: item['date'])
119 | grid_items = []
120 | for item in teaching:
121 | if not item.get('video'):
122 | item['video'] = '...'
123 |
124 | repo_text = ''
125 | star_text = ''
126 |
127 | if item['repository']:
128 | repo_text = f'{{bdg-link-secondary}}`repo <{item["repository"]}>`'
129 |
130 | try:
131 | url = urlparse(item['repository'])
132 | if url.netloc == 'github.com':
133 | _, org, repo = url.path.rstrip('/').split('/')
134 | link = f'https://img.shields.io/github/stars/{org}/{repo}?style=social'
135 | star_text = f"[]({item['repository']})"
136 | except Exception:
137 | pass
138 |
139 | grid_items.append(
140 | f"""\
141 | `````{{grid-item-card}} {" ".join(item["name"].split())}
142 | :text-align: center
143 | {item["video"]}
144 | +++
145 |
146 | ````{{grid}} 2 2 2 2
147 | :margin: 0 0 0 0
148 | :padding: 0 0 0 0
149 | :gutter: 1
150 |
151 | ```{{grid-item}}
152 | :child-direction: row
153 | :child-align: start
154 | :class: sd-fs-5
155 | {repo_text}
156 | ```
157 |
158 | ```{{grid-item}}
159 | :child-direction: row
160 | :child-align: end
161 | {star_text}
162 | ```
163 |
164 | ````
165 |
166 | `````
167 | """
168 | )
169 | grid_items = '\n'.join(grid_items)
170 |
171 | panels = f"""``````{{grid}} 2
172 | :class-container: full-width
173 |
174 | {dedent(grid_items)}
175 | ``````
176 | """
177 | (pathlib.Path(app.srcdir) / 'teaching_gallery.md').write_text(panels)
178 |
179 |
180 | def build_talks_gallery(app: Sphinx):
181 | LOGGER.info('Building talks gallery')
182 | path = pathlib.Path(app.srcdir) / 'config_data/talks.yaml'
183 | talks = yaml.safe_load(path.read_text())
184 | talks = sorted(talks, key=lambda item: item['conference']['date'], reverse=True)
185 | LOGGER.info(f'Found {len(talks)} talks')
186 | content = [
187 | """\
188 | ```{panels}
189 | :card: text-center
190 | """
191 | ]
192 | for index, item in enumerate(talks):
193 | content.append(
194 | f"""\
195 | [{item['title']}]({item['slides']})
196 | ^^^
197 | {item['video']}
198 | +++
199 | {item['conference']['name']} | {item['conference']['location']} | {item['conference']['date']}
200 | """
201 | )
202 |
203 | if index < len(talks) - 1:
204 | content.append(
205 | """\
206 | ---
207 | """
208 | )
209 |
210 | content.append(
211 | """\
212 | ```"""
213 | )
214 |
215 | content = dedent('\n'.join(content))
216 | out_path = pathlib.Path(app.srcdir) / 'talks_gallery.md'
217 | out_path.write_text(content)
218 |
219 |
220 | def setup(app: Sphinx):
221 | app.add_css_file('custom.css')
222 | app.connect('builder-inited', build_talks_gallery)
223 | app.connect('builder-inited', build_teaching_gallery)
224 |
--------------------------------------------------------------------------------
/data/advent-of-code/2020/day-8-input:
--------------------------------------------------------------------------------
1 | acc -7
2 | acc +2
3 | acc +20
4 | acc +14
5 | jmp +191
6 | acc +47
7 | nop +339
8 | acc +49
9 | jmp +104
10 | jmp +629
11 | jmp +374
12 | acc +24
13 | jmp +220
14 | nop +474
15 | acc +25
16 | jmp +340
17 | acc +16
18 | acc +3
19 | acc +41
20 | jmp +566
21 | jmp +296
22 | acc +15
23 | jmp +452
24 | acc +21
25 | jmp +129
26 | acc +10
27 | acc -8
28 | acc +39
29 | jmp +396
30 | acc +5
31 | acc -4
32 | acc +0
33 | jmp +496
34 | nop +181
35 | acc +48
36 | acc +7
37 | jmp +1
38 | jmp +370
39 | acc +16
40 | acc -18
41 | acc +47
42 | acc +48
43 | jmp +99
44 | nop +17
45 | acc +25
46 | acc -15
47 | jmp +285
48 | nop +545
49 | nop +147
50 | nop +479
51 | acc -4
52 | jmp +386
53 | acc +36
54 | acc -12
55 | jmp +50
56 | acc +37
57 | nop +133
58 | acc +11
59 | acc +20
60 | jmp +32
61 | jmp +1
62 | nop +210
63 | acc -15
64 | acc -6
65 | jmp +446
66 | acc +25
67 | acc +1
68 | acc +17
69 | acc -4
70 | jmp +355
71 | acc -4
72 | jmp +292
73 | acc +16
74 | acc +44
75 | acc +26
76 | jmp +157
77 | acc -18
78 | acc +15
79 | acc -8
80 | acc -3
81 | jmp +46
82 | acc +30
83 | acc +16
84 | jmp -7
85 | acc +34
86 | jmp +515
87 | acc +11
88 | acc -8
89 | acc -9
90 | acc -3
91 | jmp +548
92 | jmp +278
93 | nop +332
94 | acc -19
95 | acc +49
96 | jmp +536
97 | acc -9
98 | acc +46
99 | jmp +124
100 | acc +41
101 | acc +47
102 | acc -5
103 | acc -13
104 | jmp +41
105 | nop +178
106 | acc +12
107 | acc +45
108 | jmp +461
109 | acc +37
110 | acc +12
111 | acc +38
112 | jmp -68
113 | acc -6
114 | nop +494
115 | acc -9
116 | jmp -63
117 | acc +42
118 | acc +16
119 | acc +30
120 | jmp +70
121 | acc +13
122 | jmp +1
123 | acc -18
124 | jmp +528
125 | acc +48
126 | jmp +493
127 | nop +402
128 | jmp +381
129 | acc -8
130 | jmp +372
131 | acc +20
132 | acc +25
133 | jmp +425
134 | acc -10
135 | jmp +510
136 | jmp +439
137 | nop +78
138 | acc +36
139 | acc +7
140 | nop +281
141 | jmp +504
142 | jmp -108
143 | acc +40
144 | jmp -122
145 | acc +23
146 | acc -2
147 | acc +7
148 | jmp +370
149 | acc +25
150 | nop -5
151 | acc +33
152 | acc +37
153 | jmp +70
154 | acc -6
155 | nop +336
156 | jmp +34
157 | jmp +1
158 | acc -18
159 | jmp +473
160 | jmp +1
161 | acc +20
162 | acc +4
163 | acc +25
164 | jmp -87
165 | acc -12
166 | acc +47
167 | acc +49
168 | jmp +323
169 | jmp +1
170 | jmp +1
171 | jmp +167
172 | acc -10
173 | acc +45
174 | jmp +355
175 | acc +32
176 | acc +38
177 | acc +2
178 | jmp -93
179 | acc +8
180 | acc +20
181 | acc +4
182 | acc -1
183 | jmp +108
184 | nop +164
185 | acc +41
186 | jmp +440
187 | acc -16
188 | acc +47
189 | jmp +355
190 | acc -13
191 | acc +29
192 | acc +50
193 | jmp -101
194 | acc -8
195 | jmp +316
196 | acc +27
197 | acc +31
198 | nop -29
199 | jmp +1
200 | jmp +250
201 | acc +12
202 | acc -13
203 | jmp +73
204 | jmp +72
205 | acc +36
206 | acc +44
207 | jmp +1
208 | jmp -33
209 | acc -18
210 | acc +16
211 | acc -8
212 | acc +6
213 | jmp +104
214 | jmp +295
215 | acc +10
216 | nop -80
217 | jmp +74
218 | acc -13
219 | jmp +1
220 | acc +22
221 | acc +50
222 | jmp +280
223 | jmp +265
224 | jmp +278
225 | acc +46
226 | acc -14
227 | acc -17
228 | jmp -19
229 | acc +39
230 | acc +31
231 | acc -11
232 | jmp +400
233 | jmp +80
234 | acc +0
235 | acc +27
236 | nop +209
237 | jmp -184
238 | acc +12
239 | acc +21
240 | acc +23
241 | jmp +352
242 | acc +29
243 | jmp -5
244 | acc +15
245 | acc +7
246 | jmp +6
247 | acc +31
248 | acc -5
249 | nop +83
250 | acc +31
251 | jmp -239
252 | acc +8
253 | acc -2
254 | acc +49
255 | acc -12
256 | jmp -52
257 | acc -15
258 | acc -14
259 | jmp +126
260 | jmp +385
261 | acc +30
262 | acc -5
263 | acc +6
264 | jmp -187
265 | acc +39
266 | acc +40
267 | acc +0
268 | acc +6
269 | jmp +24
270 | acc +20
271 | jmp +131
272 | jmp -127
273 | acc +8
274 | acc +30
275 | jmp -265
276 | acc -2
277 | jmp -265
278 | acc +22
279 | acc -19
280 | acc -9
281 | nop +10
282 | jmp +148
283 | acc -14
284 | acc +38
285 | acc +50
286 | acc -7
287 | jmp +197
288 | acc +11
289 | acc +22
290 | jmp +201
291 | jmp -155
292 | jmp -32
293 | acc +48
294 | nop -50
295 | jmp -99
296 | jmp -5
297 | acc +11
298 | acc -18
299 | jmp -186
300 | acc +6
301 | acc +43
302 | jmp +159
303 | jmp +249
304 | acc +44
305 | acc +29
306 | nop +313
307 | acc +23
308 | jmp +311
309 | jmp +152
310 | acc +0
311 | acc +41
312 | jmp -251
313 | jmp +102
314 | nop -17
315 | nop +176
316 | jmp +40
317 | acc +28
318 | jmp -21
319 | acc -4
320 | acc -10
321 | acc -19
322 | acc -15
323 | jmp +23
324 | nop +144
325 | acc +9
326 | acc +18
327 | jmp +141
328 | acc -19
329 | acc -10
330 | acc +48
331 | jmp -7
332 | acc +46
333 | acc -9
334 | jmp -174
335 | acc +30
336 | acc +30
337 | jmp -201
338 | acc +34
339 | acc +24
340 | acc +37
341 | acc +44
342 | jmp -158
343 | acc +4
344 | acc +39
345 | jmp -52
346 | jmp -329
347 | jmp +68
348 | acc +25
349 | nop -105
350 | acc -15
351 | acc +34
352 | jmp -6
353 | jmp +1
354 | acc +1
355 | jmp +163
356 | nop -285
357 | acc +8
358 | acc +48
359 | jmp +143
360 | acc -3
361 | nop -269
362 | acc -16
363 | jmp -310
364 | acc -5
365 | jmp -304
366 | acc +45
367 | nop -231
368 | jmp +1
369 | jmp +245
370 | nop -243
371 | jmp +187
372 | acc -6
373 | acc +7
374 | acc +17
375 | acc +6
376 | jmp -111
377 | acc +24
378 | acc -10
379 | acc +21
380 | jmp -97
381 | jmp +1
382 | acc -12
383 | acc +10
384 | jmp +127
385 | acc +0
386 | jmp -211
387 | acc -11
388 | acc +36
389 | acc +45
390 | acc -19
391 | jmp -182
392 | jmp -366
393 | acc +38
394 | acc -11
395 | acc +32
396 | jmp -260
397 | acc +6
398 | acc +31
399 | jmp +3
400 | acc +5
401 | jmp +101
402 | jmp -64
403 | acc +48
404 | acc +5
405 | nop +40
406 | acc -13
407 | jmp +95
408 | nop +76
409 | acc +44
410 | acc +43
411 | acc +43
412 | jmp +196
413 | acc +34
414 | jmp +161
415 | acc +5
416 | acc +45
417 | acc +7
418 | jmp +20
419 | acc +13
420 | jmp -127
421 | acc +5
422 | acc +18
423 | jmp -239
424 | jmp -76
425 | nop +214
426 | jmp -284
427 | acc +10
428 | acc -8
429 | jmp -81
430 | acc +48
431 | acc -3
432 | jmp -55
433 | nop -288
434 | acc +37
435 | acc +1
436 | acc -12
437 | jmp +1
438 | nop +91
439 | acc +20
440 | acc +18
441 | jmp +4
442 | acc -7
443 | acc -10
444 | jmp -229
445 | nop -230
446 | nop +45
447 | acc +37
448 | jmp +127
449 | jmp +69
450 | jmp -153
451 | acc -15
452 | acc -19
453 | acc +32
454 | jmp -33
455 | nop +164
456 | acc +32
457 | jmp -133
458 | acc +20
459 | acc -8
460 | jmp +8
461 | acc -11
462 | nop +82
463 | acc +7
464 | acc +40
465 | jmp +79
466 | acc +0
467 | jmp +159
468 | acc +4
469 | acc -8
470 | acc +20
471 | nop +143
472 | jmp -351
473 | acc -7
474 | jmp +78
475 | acc +0
476 | acc +4
477 | jmp +20
478 | jmp -3
479 | acc +2
480 | acc +23
481 | jmp -256
482 | acc +33
483 | jmp -473
484 | acc +29
485 | acc -13
486 | jmp +77
487 | jmp +158
488 | acc -16
489 | jmp -10
490 | jmp -181
491 | jmp -135
492 | nop -95
493 | acc +46
494 | acc +39
495 | acc -3
496 | jmp -94
497 | jmp -67
498 | acc +49
499 | nop -78
500 | nop -9
501 | jmp +107
502 | acc -19
503 | acc -1
504 | acc +0
505 | acc -4
506 | jmp -189
507 | acc +11
508 | jmp -106
509 | jmp -200
510 | jmp +122
511 | acc +8
512 | acc +48
513 | acc +15
514 | acc +0
515 | jmp -493
516 | acc +13
517 | jmp -8
518 | acc +36
519 | acc -10
520 | jmp +1
521 | acc +9
522 | jmp +7
523 | jmp +85
524 | acc +22
525 | acc -8
526 | nop -124
527 | jmp -517
528 | jmp -338
529 | acc +39
530 | nop -438
531 | acc -11
532 | jmp +69
533 | acc +8
534 | acc +34
535 | acc +34
536 | acc -9
537 | jmp -205
538 | nop -528
539 | jmp -495
540 | acc +47
541 | acc +40
542 | acc +30
543 | jmp -328
544 | acc -2
545 | acc +41
546 | jmp -475
547 | acc +42
548 | acc +48
549 | acc +2
550 | acc +7
551 | jmp -415
552 | nop -249
553 | acc -3
554 | jmp +65
555 | acc +23
556 | nop -4
557 | jmp -254
558 | acc -12
559 | acc +22
560 | acc +27
561 | jmp -176
562 | jmp -408
563 | acc -15
564 | acc +14
565 | acc +30
566 | acc +0
567 | jmp -363
568 | jmp -426
569 | acc +38
570 | nop -425
571 | jmp -440
572 | jmp +1
573 | acc +22
574 | jmp -63
575 | jmp -406
576 | nop -445
577 | acc -5
578 | acc +34
579 | nop -425
580 | jmp +65
581 | acc +33
582 | jmp -91
583 | acc -12
584 | jmp +1
585 | jmp -541
586 | nop -489
587 | jmp -490
588 | acc +20
589 | acc +20
590 | acc +38
591 | acc -18
592 | jmp -548
593 | acc +43
594 | acc -7
595 | jmp -351
596 | acc -9
597 | acc +50
598 | acc +1
599 | nop -587
600 | jmp -230
601 | jmp +1
602 | nop +43
603 | jmp -65
604 | acc +31
605 | acc +5
606 | acc +1
607 | jmp -105
608 | nop -477
609 | acc +21
610 | nop -92
611 | jmp -263
612 | acc +28
613 | jmp -265
614 | jmp -311
615 | acc +2
616 | acc +23
617 | acc +50
618 | jmp -4
619 | acc +42
620 | acc +42
621 | acc +31
622 | jmp -167
623 | acc +49
624 | acc +46
625 | jmp -73
626 | nop -135
627 | acc +43
628 | jmp -236
629 | acc -14
630 | acc -3
631 | jmp -406
632 | acc +2
633 | acc -3
634 | acc +47
635 | jmp -420
636 | acc -8
637 | acc +18
638 | jmp -604
639 | jmp -218
640 | acc +37
641 | acc -16
642 | nop -278
643 | acc -15
644 | jmp -214
645 | acc -6
646 | acc +18
647 | acc +7
648 | acc +0
649 | jmp -252
650 | acc +14
651 | jmp -266
652 | acc +27
653 | acc -16
654 | nop -533
655 | nop -534
656 | jmp +1
657 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-6.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 6: Custom Customs\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "As your flight approaches the regional airport where you'll switch to a much\n",
17 | "larger plane,\n",
18 | "[customs declaration forms](https://en.wikipedia.org/wiki/Customs_declaration)\n",
19 | "are distributed to the passengers.\n",
20 | "\n",
21 | "The form asks a series of 26 yes-or-no questions marked a through z. All you\n",
22 | "need to do is identify the questions for which anyone in your group answers\n",
23 | "\"yes\". Since your group is just you, this doesn't take very long.\n",
24 | "\n",
25 | "However, the person sitting next to you seems to be experiencing a language\n",
26 | "barrier and asks if you can help. For each of the people in their group, you\n",
27 | "write down the questions for which they answer \"yes\", one per line. For example:\n",
28 | "\n",
29 | "```\n",
30 | "abcx\n",
31 | "abcy\n",
32 | "abcz\n",
33 | "```\n",
34 | "\n",
35 | "In this group, there are 6 questions to which anyone answered \"yes\": a, b, c, x,\n",
36 | "y, and z. (Duplicate answers to the same question don't count extra; each\n",
37 | "question counts at most once.)\n",
38 | "\n",
39 | "Another group asks for your help, then another, and eventually you've collected\n",
40 | "answers from every group on the plane (your puzzle input). Each group's answers\n",
41 | "are separated by a blank line, and within each group, each person's answers are\n",
42 | "on a single line. For example:\n",
43 | "\n",
44 | "```\n",
45 | "abc\n",
46 | "\n",
47 | "a\n",
48 | "b\n",
49 | "c\n",
50 | "\n",
51 | "ab\n",
52 | "ac\n",
53 | "\n",
54 | "a\n",
55 | "a\n",
56 | "a\n",
57 | "a\n",
58 | "\n",
59 | "b\n",
60 | "\n",
61 | "```\n",
62 | "\n",
63 | "This list represents answers from five groups:\n",
64 | "\n",
65 | "- The first group contains one person who answered \"yes\" to 3 questions: a, b,\n",
66 | " and c.\n",
67 | "- The second group contains three people; combined, they answered \"yes\" to 3\n",
68 | " questions: a, b, and c.\n",
69 | "- The third group contains two people; combined, they answered \"yes\" to 3\n",
70 | " questions: a, b, and c.\n",
71 | "- The fourth group contains four people; combined, they answered \"yes\" to only 1\n",
72 | " question, a.\n",
73 | "- The last group contains one person who answered \"yes\" to only 1 question, b.\n",
74 | "\n",
75 | "In this example, the sum of these counts is 3 + 3 + 3 + 1 + 1 = 11.\n",
76 | "\n",
77 | "For each group, count the number of questions to which anyone answered \"yes\".\n",
78 | "**What is the sum of those counts?**\n"
79 | ]
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "metadata": {},
84 | "source": [
85 | "### Load Input data\n"
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {},
91 | "source": [
92 | ":::{note} The input data can be found\n",
93 | "[here](https://adventofcode.com/2020/day/6). :::\n"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": 1,
99 | "metadata": {},
100 | "outputs": [
101 | {
102 | "name": "stdout",
103 | "output_type": "stream",
104 | "text": [
105 | "461\n",
106 | "[['b', 'b', 'b', 'b'], ['x', 'xfkj', 'xb'], ['ovuxdgiheszjbaltw', 'oxwjiubhfylzavst'], ['se', 'u', 'j', 'se'], ['eaxzstqkujdlhi', 'dsinkoqhjxz']]\n"
107 | ]
108 | }
109 | ],
110 | "source": [
111 | "def parse_input_data(data):\n",
112 | " data = data.split('\\n\\n')\n",
113 | " return [x.strip().split() for x in data]\n",
114 | "\n",
115 | "\n",
116 | "with open('../../data/advent-of-code/2020/day-6-input') as fid:\n",
117 | " data = fid.read()\n",
118 | " data = parse_input_data(data)\n",
119 | "\n",
120 | "print(len(data))\n",
121 | "print(data[0:5])"
122 | ]
123 | },
124 | {
125 | "cell_type": "markdown",
126 | "metadata": {},
127 | "source": [
128 | "### Solution\n"
129 | ]
130 | },
131 | {
132 | "cell_type": "code",
133 | "execution_count": 2,
134 | "metadata": {},
135 | "outputs": [],
136 | "source": [
137 | "def counter(group):\n",
138 | " return len(set(''.join(group)))"
139 | ]
140 | },
141 | {
142 | "cell_type": "code",
143 | "execution_count": 3,
144 | "metadata": {},
145 | "outputs": [
146 | {
147 | "data": {
148 | "text/plain": [
149 | "[['abc'], ['a', 'b', 'c'], ['ab', 'ac'], ['a', 'a', 'a', 'a'], ['b']]"
150 | ]
151 | },
152 | "execution_count": 3,
153 | "metadata": {},
154 | "output_type": "execute_result"
155 | }
156 | ],
157 | "source": [
158 | "test_sample = parse_input_data(\n",
159 | " \"\"\"abc\n",
160 | "\n",
161 | "a\n",
162 | "b\n",
163 | "c\n",
164 | "\n",
165 | "ab\n",
166 | "ac\n",
167 | "\n",
168 | "a\n",
169 | "a\n",
170 | "a\n",
171 | "a\n",
172 | "\n",
173 | "b\"\"\"\n",
174 | ")\n",
175 | "test_sample"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "execution_count": 4,
181 | "metadata": {},
182 | "outputs": [
183 | {
184 | "data": {
185 | "text/plain": [
186 | "[3, 3, 3, 1, 1]"
187 | ]
188 | },
189 | "execution_count": 4,
190 | "metadata": {},
191 | "output_type": "execute_result"
192 | }
193 | ],
194 | "source": [
195 | "[counter(group) for group in test_sample]"
196 | ]
197 | },
198 | {
199 | "cell_type": "code",
200 | "execution_count": 5,
201 | "metadata": {},
202 | "outputs": [
203 | {
204 | "data": {
205 | "text/plain": [
206 | "6534"
207 | ]
208 | },
209 | "execution_count": 5,
210 | "metadata": {},
211 | "output_type": "execute_result"
212 | }
213 | ],
214 | "source": [
215 | "sum(counter(group) for group in data)"
216 | ]
217 | },
218 | {
219 | "cell_type": "markdown",
220 | "metadata": {},
221 | "source": [
222 | "## Part Two\n",
223 | "\n",
224 | "As you finish the last group's customs declaration, you notice that you misread\n",
225 | "one word in the instructions:\n",
226 | "\n",
227 | "You don't need to identify the questions to which anyone answered \"yes\"; you\n",
228 | "need to identify the questions to which everyone answered \"yes\"!\n",
229 | "\n",
230 | "Using the same example as above:\n",
231 | "\n",
232 | "```\n",
233 | "abc\n",
234 | "\n",
235 | "a\n",
236 | "b\n",
237 | "c\n",
238 | "\n",
239 | "ab\n",
240 | "ac\n",
241 | "\n",
242 | "a\n",
243 | "a\n",
244 | "a\n",
245 | "a\n",
246 | "\n",
247 | "b\n",
248 | "\n",
249 | "```\n",
250 | "\n",
251 | "This list represents answers from five groups:\n",
252 | "\n",
253 | "- In the first group, everyone (all 1 person) answered \"yes\" to 3 questions: a,\n",
254 | " b, and c.\n",
255 | "- In the second group, there is no question to which everyone answered \"yes\".\n",
256 | "- In the third group, everyone answered yes to only 1 question, a. Since some\n",
257 | " people did not answer \"yes\" to b or c, they don't count.\n",
258 | "- In the fourth group, everyone answered yes to only 1 question, a.\n",
259 | "- In the fifth group, everyone (all 1 person) answered \"yes\" to 1 question, b.\n",
260 | "\n",
261 | "In this example, the sum of these counts is 3 + 0 + 1 + 1 + 1 = 6.\n",
262 | "\n",
263 | "For each group, count the number of questions to which everyone answered \"yes\".\n",
264 | "**What is the sum of those counts?**\n"
265 | ]
266 | },
267 | {
268 | "cell_type": "markdown",
269 | "metadata": {},
270 | "source": [
271 | "### Solution\n"
272 | ]
273 | },
274 | {
275 | "cell_type": "code",
276 | "execution_count": 6,
277 | "metadata": {},
278 | "outputs": [],
279 | "source": [
280 | "def counter(group):\n",
281 | " answers = set(''.join(group))\n",
282 | " inter = set(group[0])\n",
283 | " for entry in group[1:]:\n",
284 | " inter = inter.intersection(set(entry))\n",
285 | " return len(inter)"
286 | ]
287 | },
288 | {
289 | "cell_type": "code",
290 | "execution_count": 7,
291 | "metadata": {},
292 | "outputs": [
293 | {
294 | "data": {
295 | "text/plain": [
296 | "[3, 0, 1, 1, 1]"
297 | ]
298 | },
299 | "execution_count": 7,
300 | "metadata": {},
301 | "output_type": "execute_result"
302 | }
303 | ],
304 | "source": [
305 | "[counter(group) for group in test_sample]"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": 8,
311 | "metadata": {},
312 | "outputs": [
313 | {
314 | "data": {
315 | "text/plain": [
316 | "3402"
317 | ]
318 | },
319 | "execution_count": 8,
320 | "metadata": {},
321 | "output_type": "execute_result"
322 | }
323 | ],
324 | "source": [
325 | "sum(counter(group) for group in data)"
326 | ]
327 | }
328 | ],
329 | "metadata": {
330 | "author": "Anderson Banihirwe",
331 | "date": "2020-12-06",
332 | "kernelspec": {
333 | "display_name": "Python 3",
334 | "language": "python",
335 | "name": "python3"
336 | },
337 | "language_info": {
338 | "codemirror_mode": {
339 | "name": "ipython",
340 | "version": 3
341 | },
342 | "file_extension": ".py",
343 | "mimetype": "text/x-python",
344 | "name": "python",
345 | "nbconvert_exporter": "python",
346 | "pygments_lexer": "ipython3",
347 | "version": "3.8.8"
348 | },
349 | "tags": "python,adventofcode",
350 | "title": "Advent of Code - Day 6: Custom Customs",
351 | "widgets": {
352 | "application/vnd.jupyter.widget-state+json": {
353 | "state": {},
354 | "version_major": 2,
355 | "version_minor": 0
356 | }
357 | }
358 | },
359 | "nbformat": 4,
360 | "nbformat_minor": 4
361 | }
362 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-5.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 5: Binary Boarding\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "You board your plane only to discover a new problem: you dropped your boarding\n",
17 | "pass! You aren't sure which seat is yours, and all of the flight attendants are\n",
18 | "busy with the flood of people that suddenly made it through passport control.\n",
19 | "\n",
20 | "You write a quick program to use your phone's camera to scan all of the nearby\n",
21 | "boarding passes (your puzzle input); perhaps you can find your seat through\n",
22 | "process of elimination.\n",
23 | "\n",
24 | "Instead of [zones or groups](https://www.youtube.com/watch?v=oAHbLRjF0vo), this\n",
25 | "airline uses binary space partitioning to seat people. A seat might be specified\n",
26 | "like FBFBBFFRLR, where F means \"front\", B means \"back\", L means \"left\", and R\n",
27 | "means \"right\".\n",
28 | "\n",
29 | "The first 7 characters will either be F or B; these specify exactly one of the\n",
30 | "128 rows on the plane (numbered 0 through 127). Each letter tells you which half\n",
31 | "of a region the given seat is in. Start with the whole list of rows; the first\n",
32 | "letter indicates whether the seat is in the front (0 through 63) or the back (64\n",
33 | "through 127). The next letter indicates which half of that region the seat is\n",
34 | "in, and so on until you're left with exactly one row.\n",
35 | "\n",
36 | "For example, consider just the first seven characters of FBFBBFFRLR:\n",
37 | "\n",
38 | "Start by considering the whole range, rows 0 through 127.\n",
39 | "\n",
40 | "- F means to take the lower half, keeping rows 0 through 63.\n",
41 | "- B means to take the upper half, keeping rows 32 through 63.\n",
42 | "- F means to take the lower half, keeping rows 32 through 47.\n",
43 | "- B means to take the upper half, keeping rows 40 through 47.\n",
44 | "- B keeps rows 44 through 47.\n",
45 | "- F keeps rows 44 through 45.\n",
46 | "\n",
47 | "The final F keeps the lower of the two, row 44. The last three characters will\n",
48 | "be either L or R; these specify exactly one of the 8 columns of seats on the\n",
49 | "plane (numbered 0 through 7). The same process as above proceeds again, this\n",
50 | "time with only three steps. L means to keep the lower half, while R means to\n",
51 | "keep the upper half.\n",
52 | "\n",
53 | "For example, consider just the last 3 characters of FBFBBFFRLR:\n",
54 | "\n",
55 | "- Start by considering the whole range, columns 0 through 7.\n",
56 | "- R means to take the upper half, keeping columns 4 through 7.\n",
57 | "- L means to take the lower half, keeping columns 4 through 5.\n",
58 | "- The final R keeps the upper of the two, column 5. So, decoding FBFBBFFRLR\n",
59 | " reveals that it is the seat at row 44, column 5.\n",
60 | "\n",
61 | "Every seat also has a unique seat ID: multiply the row by 8, then add the\n",
62 | "column. In this example, the seat has ID 44 \\* 8 + 5 = 357.\n",
63 | "\n",
64 | "Here are some other boarding passes:\n",
65 | "\n",
66 | "- BFFFBBFRRR: row 70, column 7, seat ID 567.\n",
67 | "- FFFBBBFRRR: row 14, column 7, seat ID 119.\n",
68 | "- BBFFBBFRLL: row 102, column 4, seat ID 820.\n",
69 | "\n",
70 | "As a sanity check, look through your list of boarding passes. **What is the\n",
71 | "highest seat ID on a boarding pass?**\n"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | "### Load Input data\n"
79 | ]
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "metadata": {},
84 | "source": [
85 | ":::{note} The input data can be found\n",
86 | "[here](https://adventofcode.com/2020/day/5). :::\n"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 1,
92 | "metadata": {},
93 | "outputs": [
94 | {
95 | "name": "stdout",
96 | "output_type": "stream",
97 | "text": [
98 | "846\n",
99 | "FBBFFBBLLL\n",
100 | "\n"
101 | ]
102 | }
103 | ],
104 | "source": [
105 | "with open('../../data/advent-of-code/2020/day-5-input') as fid:\n",
106 | " data = fid.readlines()\n",
107 | "\n",
108 | "print(len(data))\n",
109 | "print(data[0])"
110 | ]
111 | },
112 | {
113 | "cell_type": "markdown",
114 | "metadata": {},
115 | "source": [
116 | "### Solution\n"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": 2,
122 | "metadata": {},
123 | "outputs": [],
124 | "source": [
125 | "import math\n",
126 | "\n",
127 | "\n",
128 | "def find_seat_info(seat_number, nrows, ncols, row_identifiers, col_identifiers):\n",
129 | " \"\"\"Function to decode the seat_id when given the seat number\"\"\"\n",
130 | "\n",
131 | " def decode_seat(seat, n_entries, identifiers):\n",
132 | " lo, hi = 0, n_entries\n",
133 | " for letter in seat:\n",
134 | " if letter == identifiers[0]:\n",
135 | " lo, hi = lo, math.floor((lo + hi) / 2)\n",
136 | " elif letter == identifiers[1]:\n",
137 | " lo, hi = math.ceil((lo + hi) / 2), hi\n",
138 | "\n",
139 | " return lo\n",
140 | "\n",
141 | " row = decode_seat(seat_number[:7], nrows, row_identifiers)\n",
142 | " col = decode_seat(seat_number[7:], ncols, col_identifiers)\n",
143 | " return {\n",
144 | " 'seat_number': seat_number,\n",
145 | " 'row': row,\n",
146 | " 'column': col,\n",
147 | " 'seat_id': row * 8 + col,\n",
148 | " }"
149 | ]
150 | },
151 | {
152 | "cell_type": "code",
153 | "execution_count": 3,
154 | "metadata": {},
155 | "outputs": [],
156 | "source": [
157 | "nrows, ncols = 128, 8\n",
158 | "row_identifiers = ('F', 'B')\n",
159 | "col_identifiers = ('L', 'R')"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": 4,
165 | "metadata": {},
166 | "outputs": [
167 | {
168 | "data": {
169 | "text/plain": [
170 | "{'seat_number': 'FBFBBFFRLR', 'row': 44, 'column': 5, 'seat_id': 357}"
171 | ]
172 | },
173 | "execution_count": 4,
174 | "metadata": {},
175 | "output_type": "execute_result"
176 | }
177 | ],
178 | "source": [
179 | "# Test our function on sample input seat number\n",
180 | "find_seat_info('FBFBBFFRLR', nrows, ncols, row_identifiers, col_identifiers)"
181 | ]
182 | },
183 | {
184 | "cell_type": "markdown",
185 | "metadata": {},
186 | "source": [
187 | "Everything appears to be working.... Let's loop over all the seat numbers and\n",
188 | "collect the ids:\n"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": 5,
194 | "metadata": {},
195 | "outputs": [
196 | {
197 | "data": {
198 | "text/plain": [
199 | "(12, 858)"
200 | ]
201 | },
202 | "execution_count": 5,
203 | "metadata": {},
204 | "output_type": "execute_result"
205 | }
206 | ],
207 | "source": [
208 | "ids = [\n",
209 | " find_seat_info(seat, nrows, ncols, row_identifiers, col_identifiers)['seat_id'] for seat in data\n",
210 | "]\n",
211 | "min(ids), max(ids)"
212 | ]
213 | },
214 | {
215 | "cell_type": "markdown",
216 | "metadata": {},
217 | "source": [
218 | "## Part Two\n",
219 | "\n",
220 | "Ding! The \"fasten seat belt\" signs have turned on. Time to find your seat.\n",
221 | "\n",
222 | "It's a completely full flight, so your seat should be the only missing boarding\n",
223 | "pass in your list. However, there's a catch: some of the seats at the very front\n",
224 | "and back of the plane don't exist on this aircraft, so they'll be missing from\n",
225 | "your list as well.\n",
226 | "\n",
227 | "Your seat wasn't at the very front or back, though; the seats with IDs +1 and -1\n",
228 | "from yours will be in your list.\n",
229 | "\n",
230 | "**What is the ID of your seat?**\n"
231 | ]
232 | },
233 | {
234 | "cell_type": "markdown",
235 | "metadata": {},
236 | "source": [
237 | "### Solution\n"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": 6,
243 | "metadata": {},
244 | "outputs": [
245 | {
246 | "data": {
247 | "text/plain": [
248 | "178"
249 | ]
250 | },
251 | "execution_count": 6,
252 | "metadata": {},
253 | "output_type": "execute_result"
254 | }
255 | ],
256 | "source": [
257 | "# Find missing ids\n",
258 | "missing_ids = [seat_id for seat_id in range(5, nrows * 8 + 5) if seat_id not in set(ids)]\n",
259 | "len(missing_ids)"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 7,
265 | "metadata": {},
266 | "outputs": [
267 | {
268 | "data": {
269 | "text/plain": [
270 | "[11, 557, 859]"
271 | ]
272 | },
273 | "execution_count": 7,
274 | "metadata": {},
275 | "output_type": "execute_result"
276 | }
277 | ],
278 | "source": [
279 | "# Loop over missing ids, and find possible candidates\n",
280 | "possible_candidates = []\n",
281 | "for idx in range(1, len(missing_ids) - 1):\n",
282 | " if not (\n",
283 | " (missing_ids[idx - 1] == missing_ids[idx] - 1)\n",
284 | " and (missing_ids[idx + 1] == missing_ids[idx] + 1)\n",
285 | " ):\n",
286 | " possible_candidates.append(missing_ids[idx])\n",
287 | "possible_candidates"
288 | ]
289 | },
290 | {
291 | "cell_type": "markdown",
292 | "metadata": {},
293 | "source": [
294 | "We can use a process of elimination to get the ID of our seat by checking for\n",
295 | "the ids of the front and back seats:\n"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": 8,
301 | "metadata": {},
302 | "outputs": [
303 | {
304 | "data": {
305 | "text/plain": [
306 | "(12, 858)"
307 | ]
308 | },
309 | "execution_count": 8,
310 | "metadata": {},
311 | "output_type": "execute_result"
312 | }
313 | ],
314 | "source": [
315 | "min(ids), max(ids)"
316 | ]
317 | },
318 | {
319 | "cell_type": "markdown",
320 | "metadata": {},
321 | "source": [
322 | "Since it was pointed out that our seat wasn't at the very front or back, we can\n",
323 | "eliminate `11` and `859`. So, the id our seat is **`557`**\n"
324 | ]
325 | }
326 | ],
327 | "metadata": {
328 | "author": "Anderson Banihirwe",
329 | "date": "2020-12-05",
330 | "kernelspec": {
331 | "display_name": "Python 3",
332 | "language": "python",
333 | "name": "python3"
334 | },
335 | "language_info": {
336 | "codemirror_mode": {
337 | "name": "ipython",
338 | "version": 3
339 | },
340 | "file_extension": ".py",
341 | "mimetype": "text/x-python",
342 | "name": "python",
343 | "nbconvert_exporter": "python",
344 | "pygments_lexer": "ipython3",
345 | "version": "3.8.8"
346 | },
347 | "tags": "python,adventofcode",
348 | "title": "Advent of Code - Day 5: Binary Boarding",
349 | "widgets": {
350 | "application/vnd.jupyter.widget-state+json": {
351 | "state": {},
352 | "version_major": 2,
353 | "version_minor": 0
354 | }
355 | }
356 | },
357 | "nbformat": 4,
358 | "nbformat_minor": 4
359 | }
360 |
--------------------------------------------------------------------------------
/data/advent-of-code/2020/day-3-input:
--------------------------------------------------------------------------------
1 | ........#.............#........
2 | ...#....#...#....#.............
3 | .#..#...#............#.....#..#
4 | ..#......#..##............###..
5 | ..........#......#..#..#.......
6 | .#..#.......#.........#.#......
7 | .........#..#....##..#.##....#.
8 | ..#....##...#..................
9 | ##..........#.##...#....##..#..
10 | ...#....#...#..............#...
11 | ...........................#..#
12 | ..##.##.#..................#...
13 | ...#.##..#............#........
14 | ........#.......#...#.....##.#.
15 | .##..........#......#.......#..
16 | ...#..........#...#..#.......#.
17 | ......#...#...#.##.......#.#...
18 | ........#...#...#...##.........
19 | #..............#.#....#.......#
20 | ..#..#..#.#....#...............
21 | .....#........#...#..........#.
22 | ##......#...#..#.##.......#....
23 | ..#.#.....#.#.............#.#.#
24 | #..#..##......##...#...........
25 | ..#......#........#.....#......
26 | .....#.......#....#.#...#......
27 | ...#........#...........#...#..
28 | .......#.#...........###....#..
29 | ...#...........##....##........
30 | #....#..####....#.....#..#....#
31 | ..........#...........#........
32 | ...#.......#....#.#.........#..
33 | ....#...#.......#..###.........
34 | ......#......#..#......#..#....
35 | ...#.....#............#..#.....
36 | ...#.#.#.#..#.......#.....#....
37 | #....##...#.........#...##.....
38 | #..#.......#..#..#..#...##.....
39 | #.......#............#.....#...
40 | .#........##....##...#........#
41 | .....#...#.....................
42 | .......#........#..............
43 | .....#............#.#.#...#.#..
44 | .....##..#.............#.......
45 | ..#.##..#........#..#...#......
46 | .........#.#....#...........#..
47 | .#.....#..#....#.....#...#.....
48 | ....#.#................#.......
49 | ...............##......#...#...
50 | .##...#...#.......##.#....#....
51 | ............#........#.......#.
52 | ......##.#.#...................
53 | .#.#..............#.......#....
54 | #.....#...#.......#..#...#.....
55 | .............#....#..#......#..
56 | ........#...##................#
57 | .......#...#..#..##............
58 | ..#..#...##...#..#.#.....#...#.
59 | .#.#...#.........#.#...........
60 | ...###....#.......#...#........
61 | ........#......##.#...#..##..#.
62 | .....................#.#.......
63 | .............#...........#...#.
64 | #..#..#.....#.#...#............
65 | ...#....#.....#...........#....
66 | ..##.....##...#......#..##.....
67 | #.....#.....###.#.....#....##..
68 | .#...........###...............
69 | ..................#..##.#...#..
70 | ................#....##.#......
71 | .#.#.#...#....#.........#..#.#.
72 | #.......#........##............
73 | .......##.#....#.#............#
74 | ..........#..##.#....#.........
75 | ........##..#....#.............
76 | .........#....#...........##...
77 | #.........#.#..#..#..........#.
78 | .....#........#......#.........
79 | ....#.#.#...............#......
80 | .#..#..##...#.##..........#....
81 | ..#....................#.#.....
82 | .........#....#...........#.#.#
83 | ........#....##.##.............
84 | ..#.....#.......#..#......#....
85 | #..........#.#.....#.#....#....
86 | ........##.#.....#..#.....#.#..
87 | ...................#...#....#.#
88 | ............#..#....#...#...#..
89 | ..............#.#.........#....
90 | ...#..#..#.#..##..##...........
91 | .#...........................#.
92 | .#.......#...........#....#.#.#
93 | ......#..#...#........#...##...
94 | .........#......#.#.......#...#
95 | ...#..##................#......
96 | .............#.#..##....#.#....
97 | ...............#..#......#.....
98 | .#......#.#.#....#........#....
99 | ........#..#.##..#..#.........#
100 | ...#....#.#...#..#.......#..#..
101 | ..#...##.........#..#...#......
102 | ...#...........#.............#.
103 | ....#.....................#....
104 | .....#..#...............#.#...#
105 | ....#..........#........#......
106 | ..#....#........##..##.........
107 | ...#....#..#.#.......#...#.....
108 | ..#........#....#...##....#.#..
109 | .#...#........##.....#....###..
110 | #....#....##......#........#...
111 | .........#..#.#..........#....#
112 | ....#...#.....#.......##.......
113 | ..............#..........#.##..
114 | #...#..#..............#......#.
115 | .................#......##....#
116 | ..#..##..#.......#..#.#......#.
117 | .............#........#.....#.#
118 | .#.##............#..#..........
119 | ..#...#...........#..##........
120 | .#....#...#....#.......#.......
121 | ...#.#..#..#..#....#.....#..#..
122 | ....#..##..............#...#...
123 | #..........###......###........
124 | .##.##......#..#............#..
125 | .#...........#.#.....#...#.....
126 | #.#..#...#............#........
127 | .........#...#...#..........##.
128 | .......###..#..........#.......
129 | ...........###.....#........#..
130 | .#.............#.....#......#..
131 | ...#.....#....#.#.........##...
132 | ....##..##...#.......##........
133 | ......#....##.........#......#.
134 | ..........#.....##..#.....#..#.
135 | ..........####...#..#.........#
136 | .##....#..#.#...#.......#......
137 | ...#.#.##.#.#...#....#.#.#.....
138 | .........#...##........##.....#
139 | ..#........#..........##...##.#
140 | ##...##..........#.#...........
141 | ..............#......#.........
142 | ........#.....#.#.......#......
143 | .#...#.....#....#.#..#.........
144 | .....#....................##...
145 | ....#..................#.#...##
146 | .....#............#..##........
147 | #..........#....#.#.......##.#.
148 | ....#..#.....................#.
149 | #..#....##.....#...............
150 | ..#...#..#..##....#.#..........
151 | .......#......#.#.......#.....#
152 | ...#.#.......#...#.##..........
153 | ....#..........#....#.#.#......
154 | .......#..#..........#..##.....
155 | #......#......#...#......#...#.
156 | ###..#....##......##........#..
157 | .#..........#.....#.......#.#..
158 | .......#.....#.....#.#.........
159 | ..#...#....#...................
160 | ..............#.##.............
161 | .#...#.......#.##...#.#.......#
162 | .......#......................#
163 | ....#.#...#.#........#.........
164 | .#......#....#...#.............
165 | #.......#...###.....#.#.#..#...
166 | #....##.#...............##.....
167 | ..#.......#..................#.
168 | .....####...............#......
169 | .##......#......#.#.......##.#.
170 | #......##..###....#....#......#
171 | .##.......##.##...#.##.........
172 | ......##............#.......#..
173 | ......#..#.....##.#............
174 | .#..........#.....##...........
175 | #.........#......#......##.#...
176 | .........#.......#..#......#.#.
177 | .........#.......#...........#.
178 | .#..##.#..................##...
179 | .............#.............#...
180 | .....##........#......##...##..
181 | ..#..#.#.....#..#....#.........
182 | .....#....#.....#.....#........
183 | #......##.....#....#....#......
184 | #.................#..#.#......#
185 | .......#..#......#....#.#...#.#
186 | ....#.........#..#..........#.#
187 | ##......#............#...#...#.
188 | ....##......#...#.....#....##..
189 | .#...##.........#..............
190 | ......#.....................#..
191 | ..#..........###....#..........
192 | #....#...#..#.............#....
193 | #........#.#......#....#.......
194 | .#...#.......#..#...#.#...#..#.
195 | ................##.#.....#.....
196 | ###.......#...#................
197 | ...#.......#...#.#.....#.......
198 | ..#.........#.....#.#.......#..
199 | ......#.......................#
200 | #.....#.#..#....#.......#......
201 | ...#....#..#....####...........
202 | .............#.....#...##......
203 | .......#.........#...#..#......
204 | .##..#.........#....#.#........
205 | ....##...#.#...........#....#..
206 | .........................##....
207 | ..###.......##....#.#.........#
208 | .#....#.#.#...........##....#..
209 | ......#...#..#..#..#..#.......#
210 | ..#....#.#.......#..#..#..#...#
211 | .....##...#.##....#.#...#......
212 | .........#..#....#..#..........
213 | .##..##.........#.#.....#......
214 | ..........#...##...#.#...#.....
215 | #.##..#..#.............#.......
216 | ...#...........#.......#......#
217 | .......#....#....#...##.......#
218 | ..#.##........###..#......#....
219 | ...#...........###......#..#..#
220 | .#.........#.#.........#.#.....
221 | ##.......##.##.##......##......
222 | ............#...#..........#...
223 | ....................#..........
224 | ...#..#...........#...#...#....
225 | .................#...#......###
226 | ...#................#.#.##.....
227 | ...............#........#......
228 | #.............##......#.#..#...
229 | ..#.#.....#..#.##.....##...#...
230 | ......#.........#......#.......
231 | #.......#......#....#........#.
232 | .#..##.....#.........#.........
233 | ....##.##.#...#.........##.#...
234 | ...............#..#..#..##.....
235 | .#..#...............###........
236 | .##............##..............
237 | ...............#...##...#...#.#
238 | ..#.#......#.#..#.............#
239 | #.#..#..##.........#.#.#...#...
240 | ....##.#....................##.
241 | .........#..#.....#.....#..#..#
242 | ....#......#......#.##....#....
243 | ........###..#.............#..#
244 | ##................#.........#..
245 | #.....#.......#....#...........
246 | ..#.......#..#........#....#...
247 | ..#.#.##..#.#...##........#.##.
248 | ..#..........#............#....
249 | ..........#...............##...
250 | ..........###........#.#.......
251 | .....###..#.............#......
252 | ##.............#...#.....#.....
253 | .....#......#....#........#.#..
254 | ............#..#..............#
255 | .................#...........##
256 | #........#.........###.....#...
257 | ..#.#..............##......#.#.
258 | .#...........#.........#..##..#
259 | ...............................
260 | .#.....#..#....#....#......#...
261 | .#...#......#.#..#....#.......#
262 | ......#.##.......#......#......
263 | ......#..###..#................
264 | #..#.....#........##...#.......
265 | ......##.........##....#...##..
266 | .#..........#.................#
267 | #..#.......#...............#...
268 | .........#..###....#.#.##.#....
269 | ..#...#.##..##...............##
270 | .........#.....................
271 | .#....##...#......#....#.......
272 | ............#..........#..#....
273 | ...#......##....#....#........#
274 | .#...................#.........
275 | #.#........###....#..........#.
276 | .........#....#....#........##.
277 | .#....#..#.........#..#........
278 | ...............#..#...#..#...##
279 | .........#....##....#......#...
280 | .#.............................
281 | ...#........#...#.#...#.#..#...
282 | .....#..##...#.#...............
283 | #.....#....#.........#.........
284 | #...#...........##.........#...
285 | ..##........#.#...#...#......#.
286 | ...........#.....#...#.#.......
287 | ......###....#.....#...........
288 | ......##...#..........#....#.#.
289 | .......##..##..........#.......
290 | ....#............#..#....##....
291 | ..##...................#.#.....
292 | ...#.#..#.#....................
293 | .#..##..#............##.###..#.
294 | #.#...#....#.#..........#.#....
295 | ........#....#.....#...........
296 | ..##....#...#.......#..........
297 | ...........##.##....#..........
298 | .....#............#............
299 | .......#.............#....#....
300 | .................#......#......
301 | ......##.......#....#..##...#..
302 | .#..#....#.....................
303 | ...#.#.#...#......##...........
304 | ##........##.#....#....#.......
305 | .......#.....#..#..#...#.##....
306 | #..........#....#.#..#..#..#...
307 | ...##..............#...........
308 | .........#.....#.#....#.......#
309 | .........#....##..#..##..#.....
310 | .....#......................#..
311 | ...###...#..#......#...........
312 | ....#.....................#....
313 | ...............................
314 | ..#.....###.......#..#....#....
315 | #..........#.................#.
316 | ......#.......###.......#..##..
317 | .............#.##..............
318 | ......#..#.#..#...........#....
319 | ...#....##.#...#..#.#...#....#.
320 | ..................#...#....#.##
321 | ......#.#....#.................
322 | ......#.#.....#.....#..##......
323 | #..##...........#..#.....#.##..
324 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-9.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 9: Encoding Error\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "With your neighbor happily enjoying their video game, you turn your attention to\n",
17 | "an open data port on the little screen in the seat in front of you.\n",
18 | "\n",
19 | "Though the port is non-standard, you manage to connect it to your computer\n",
20 | "through the clever use of several paperclips. Upon connection, the port outputs\n",
21 | "a series of numbers (your puzzle input).\n",
22 | "\n",
23 | "The data appears to be encrypted with the eXchange-Masking Addition System\n",
24 | "(XMAS) which, conveniently for you, is an old cypher with an important weakness.\n",
25 | "\n",
26 | "XMAS starts by transmitting a preamble of 25 numbers. After that, each number\n",
27 | "you receive should be the sum of any two of the 25 immediately previous numbers.\n",
28 | "The two numbers will have different values, and there might be more than one\n",
29 | "such pair.\n",
30 | "\n",
31 | "For example, suppose your preamble consists of the numbers 1 through 25 in a\n",
32 | "random order. To be valid, the next number must be the sum of two of those\n",
33 | "numbers:\n",
34 | "\n",
35 | "- 26 would be a valid next number, as it could be 1 plus 25 (or many other\n",
36 | " pairs, like 2 and 24).\n",
37 | "- 49 would be a valid next number, as it is the sum of 24 and 25.\n",
38 | "- 100 would not be valid; no two of the previous 25 numbers sum to 100.\n",
39 | "- 50 would also not be valid; although 25 appears in the previous 25 numbers,\n",
40 | " the two numbers in the pair must be different.\n",
41 | "\n",
42 | "Suppose the 26th number is 45, and the first number (no longer an option, as it\n",
43 | "is more than 25 numbers ago) was 20. Now, for the next number to be valid, there\n",
44 | "needs to be some pair of numbers among 1-19, 21-25, or 45 that add up to it:\n",
45 | "\n",
46 | "- 26 would still be a valid next number, as 1 and 25 are still within the\n",
47 | " previous 25 numbers.\n",
48 | "- 65 would not be valid, as no two of the available numbers sum to it.\n",
49 | "- 64 and 66 would both be valid, as they are the result of 19+45 and 21+45\n",
50 | " respectively.\n",
51 | "\n",
52 | "Here is a larger example which only considers the previous 5 numbers (and has a\n",
53 | "preamble of length 5):\n",
54 | "\n",
55 | "```\n",
56 | "35\n",
57 | "20\n",
58 | "15\n",
59 | "25\n",
60 | "47\n",
61 | "40\n",
62 | "62\n",
63 | "55\n",
64 | "65\n",
65 | "95\n",
66 | "102\n",
67 | "117\n",
68 | "150\n",
69 | "182\n",
70 | "127\n",
71 | "219\n",
72 | "299\n",
73 | "277\n",
74 | "309\n",
75 | "576\n",
76 | "```\n",
77 | "\n",
78 | "In this example, after the 5-number preamble, almost every number is the sum of\n",
79 | "two of the previous 5 numbers; the only number that does not follow this rule\n",
80 | "is 127.\n",
81 | "\n",
82 | "The first step of attacking the weakness in the XMAS data is to find the first\n",
83 | "number in the list (after the preamble) which is not the sum of two of the 25\n",
84 | "numbers before it. **What is the first number that does not have this\n",
85 | "property?**\n"
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {},
91 | "source": [
92 | "## Load and Clean Input data\n"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | ":::{note} The input data can be found\n",
100 | "[here](https://adventofcode.com/2020/day/9). :::\n"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "execution_count": null,
106 | "metadata": {},
107 | "outputs": [],
108 | "source": [
109 | "with open('../../data/advent-of-code/2020/day-9-input') as fid:\n",
110 | " data = fid.readlines()\n",
111 | " data = [int(x) for x in data]\n",
112 | "\n",
113 | "print(len(data))\n",
114 | "print(data[0:2])"
115 | ]
116 | },
117 | {
118 | "cell_type": "code",
119 | "execution_count": null,
120 | "metadata": {},
121 | "outputs": [],
122 | "source": [
123 | "test_data = [\n",
124 | " 35,\n",
125 | " 20,\n",
126 | " 15,\n",
127 | " 25,\n",
128 | " 47,\n",
129 | " 40,\n",
130 | " 62,\n",
131 | " 55,\n",
132 | " 65,\n",
133 | " 95,\n",
134 | " 102,\n",
135 | " 117,\n",
136 | " 150,\n",
137 | " 182,\n",
138 | " 127,\n",
139 | " 219,\n",
140 | " 299,\n",
141 | " 277,\n",
142 | " 309,\n",
143 | " 576,\n",
144 | "]"
145 | ]
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {},
150 | "source": [
151 | "### Solution\n"
152 | ]
153 | },
154 | {
155 | "cell_type": "code",
156 | "execution_count": 3,
157 | "metadata": {},
158 | "outputs": [],
159 | "source": [
160 | "def pairs_addup(data, target):\n",
161 | " n1, n2 = None, None\n",
162 | " for idx, num in enumerate(data):\n",
163 | " remain = target - num\n",
164 | " if remain in data[:idx] + data[idx + 1 :]:\n",
165 | " n1, n2 = num, remain\n",
166 | " break\n",
167 | " return n1, n2\n",
168 | "\n",
169 | "\n",
170 | "def find_invalid_number(data, preamble_length, return_index=False):\n",
171 | " arr = data[preamble_length:]\n",
172 | " for idx, num in enumerate(arr):\n",
173 | " start, stop = idx, idx + preamble_length\n",
174 | " arr_to_check = data[start:stop]\n",
175 | " n1, n2 = pairs_addup(arr_to_check, num)\n",
176 | " if n1 is None:\n",
177 | " if return_index:\n",
178 | " return num, stop\n",
179 | " else:\n",
180 | " return num\n",
181 | " return None"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": 4,
187 | "metadata": {},
188 | "outputs": [
189 | {
190 | "name": "stdout",
191 | "output_type": "stream",
192 | "text": [
193 | "127 is the number that does not have the required property\n"
194 | ]
195 | }
196 | ],
197 | "source": [
198 | "print(f'{find_invalid_number(test_data, 5)} is the number that does not have the required property')"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "execution_count": 5,
204 | "metadata": {},
205 | "outputs": [
206 | {
207 | "name": "stdout",
208 | "output_type": "stream",
209 | "text": [
210 | "25918798 is the number that does not have the required property\n"
211 | ]
212 | }
213 | ],
214 | "source": [
215 | "print(f'{find_invalid_number(data, 25)} is the number that does not have the required property')"
216 | ]
217 | },
218 | {
219 | "cell_type": "markdown",
220 | "metadata": {},
221 | "source": [
222 | "## Part Two\n",
223 | "\n",
224 | "The final step in breaking the XMAS encryption relies on the invalid number you\n",
225 | "just found: you must find a contiguous set of at least two numbers in your list\n",
226 | "which sum to the invalid number from step 1.\n",
227 | "\n",
228 | "Again consider the above example:\n",
229 | "\n",
230 | "```\n",
231 | "35\n",
232 | "20\n",
233 | "15\n",
234 | "25\n",
235 | "47\n",
236 | "40\n",
237 | "62\n",
238 | "55\n",
239 | "65\n",
240 | "95\n",
241 | "102\n",
242 | "117\n",
243 | "150\n",
244 | "182\n",
245 | "127\n",
246 | "219\n",
247 | "299\n",
248 | "277\n",
249 | "309\n",
250 | "576\n",
251 | "```\n",
252 | "\n",
253 | "In this list, adding up all of the numbers from 15 through 40 produces the\n",
254 | "invalid number from step 1, 127. (Of course, the contiguous set of numbers in\n",
255 | "your actual list might be much longer.)\n",
256 | "\n",
257 | "To find the encryption weakness, add together the smallest and largest number in\n",
258 | "this contiguous range; in this example, these are 15 and 47, producing 62.\n",
259 | "\n",
260 | "**What is the encryption weakness in your XMAS-encrypted list of numbers?**\n"
261 | ]
262 | },
263 | {
264 | "cell_type": "markdown",
265 | "metadata": {},
266 | "source": [
267 | "### Solution\n"
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "execution_count": 6,
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "data": {
277 | "text/plain": [
278 | "25918798"
279 | ]
280 | },
281 | "execution_count": 6,
282 | "metadata": {},
283 | "output_type": "execute_result"
284 | }
285 | ],
286 | "source": [
287 | "num = find_invalid_number(data, 25)\n",
288 | "num"
289 | ]
290 | },
291 | {
292 | "cell_type": "code",
293 | "execution_count": 7,
294 | "metadata": {},
295 | "outputs": [],
296 | "source": [
297 | "def find_contiguous_block(data, target):\n",
298 | " count = 0\n",
299 | " length = len(data)\n",
300 | " # Check each size from second index all the way up to the end of the array\n",
301 | " for idx in range(2, length):\n",
302 | " # At each size, shift the window from front to back\n",
303 | " for i in range(0, length - idx + 1):\n",
304 | " total = 0\n",
305 | " candidates = []\n",
306 | " # Add numbers in the computed window and check if they sum to the target\n",
307 | " for j in range(0, idx):\n",
308 | " total += data[i + j]\n",
309 | " candidates.append(data[i + j])\n",
310 | "\n",
311 | " # Does the total equal to the target?\n",
312 | " if total == target:\n",
313 | " min_num, max_num = min(candidates), max(candidates)\n",
314 | " return min_num, max_num"
315 | ]
316 | },
317 | {
318 | "cell_type": "code",
319 | "execution_count": 8,
320 | "metadata": {},
321 | "outputs": [
322 | {
323 | "data": {
324 | "text/plain": [
325 | "(15, 47)"
326 | ]
327 | },
328 | "execution_count": 8,
329 | "metadata": {},
330 | "output_type": "execute_result"
331 | }
332 | ],
333 | "source": [
334 | "find_contiguous_block(test_data, 127)"
335 | ]
336 | },
337 | {
338 | "cell_type": "code",
339 | "execution_count": 9,
340 | "metadata": {},
341 | "outputs": [
342 | {
343 | "data": {
344 | "text/plain": [
345 | "(1127699, 2213243)"
346 | ]
347 | },
348 | "execution_count": 9,
349 | "metadata": {},
350 | "output_type": "execute_result"
351 | }
352 | ],
353 | "source": [
354 | "min_num, max_num = find_contiguous_block(data, num)\n",
355 | "min_num, max_num"
356 | ]
357 | },
358 | {
359 | "cell_type": "code",
360 | "execution_count": 10,
361 | "metadata": {},
362 | "outputs": [
363 | {
364 | "name": "stdout",
365 | "output_type": "stream",
366 | "text": [
367 | "The the encryption weakness in our XMAS-encrypted list of numbers is 3340942\n"
368 | ]
369 | }
370 | ],
371 | "source": [
372 | "print(f'The the encryption weakness in our XMAS-encrypted list of numbers is {min_num + max_num}')"
373 | ]
374 | }
375 | ],
376 | "metadata": {
377 | "author": "Anderson Banihirwe",
378 | "date": "2020-12-09",
379 | "kernelspec": {
380 | "display_name": "Python 3",
381 | "language": "python",
382 | "name": "python3"
383 | },
384 | "language_info": {
385 | "codemirror_mode": {
386 | "name": "ipython",
387 | "version": 3
388 | },
389 | "file_extension": ".py",
390 | "mimetype": "text/x-python",
391 | "name": "python",
392 | "nbconvert_exporter": "python",
393 | "pygments_lexer": "ipython3",
394 | "version": "3.8.8"
395 | },
396 | "tags": "python,adventofcode",
397 | "title": "Advent of Code - Day 9: Encoding Error",
398 | "widgets": {
399 | "application/vnd.jupyter.widget-state+json": {
400 | "state": {},
401 | "version_major": 2,
402 | "version_minor": 0
403 | }
404 | }
405 | },
406 | "nbformat": 4,
407 | "nbformat_minor": 4
408 | }
409 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 3: Toboggan Trajectory\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "With the toboggan login problems resolved, you set off toward the airport. While\n",
17 | "travel by toboggan might be easy, it's certainly not safe: there's very minimal\n",
18 | "steering and the area is covered in trees. You'll need to see which angles will\n",
19 | "take you near the fewest trees.\n",
20 | "\n",
21 | "Due to the local geology, trees in this area only grow on exact integer\n",
22 | "coordinates in a grid. You make a map (your puzzle input) of the open squares\n",
23 | "(.) and trees (#) you can see. For example:\n",
24 | "\n",
25 | "```\n",
26 | "..##.......\n",
27 | "#...#...#..\n",
28 | ".#....#..#.\n",
29 | "..#.#...#.#\n",
30 | ".#...##..#.\n",
31 | "..#.##.....\n",
32 | ".#.#.#....#\n",
33 | ".#........#\n",
34 | "#.##...#...\n",
35 | "#...##....#\n",
36 | ".#..#...#.#\n",
37 | "```\n",
38 | "\n",
39 | "These aren't the only trees, though; due to something you read about once\n",
40 | "involving arboreal genetics and biome stability, the same pattern repeats to the\n",
41 | "right many times:\n",
42 | "\n",
43 | "```\n",
44 | "..##.........##.........##.........##.........##.........##....... --->\n",
45 | "#...#...#..#...#...#..#...#...#..#...#...#..#...#...#..#...#...#..\n",
46 | ".#....#..#..#....#..#..#....#..#..#....#..#..#....#..#..#....#..#.\n",
47 | "..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#\n",
48 | ".#...##..#..#...##..#..#...##..#..#...##..#..#...##..#..#...##..#.\n",
49 | "..#.##.......#.##.......#.##.......#.##.......#.##.......#.##..... --->\n",
50 | ".#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#\n",
51 | ".#........#.#........#.#........#.#........#.#........#.#........#\n",
52 | "#.##...#...#.##...#...#.##...#...#.##...#...#.##...#...#.##...#...\n",
53 | "#...##....##...##....##...##....##...##....##...##....##...##....#\n",
54 | ".#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.# --->\n",
55 | "```\n",
56 | "\n",
57 | "You start on the open square (.) in the top-left corner and need to reach the\n",
58 | "bottom (below the bottom-most row on your map).\n",
59 | "\n",
60 | "The toboggan can only follow a few specific slopes (you opted for a cheaper\n",
61 | "model that prefers rational numbers); start by counting all the trees you would\n",
62 | "encounter for the slope right 3, down 1:\n",
63 | "\n",
64 | "From your starting position at the top-left, check the position that is right 3\n",
65 | "and down 1. Then, check the position that is right 3 and down 1 from there, and\n",
66 | "so on until you go past the bottom of the map.\n",
67 | "\n",
68 | "The locations you'd check in the above example are marked here with O where\n",
69 | "there was an open square and X where there was a tree:\n",
70 | "\n",
71 | "```\n",
72 | "..##.........##.........##.........##.........##.........##....... --->\n",
73 | "#..O#...#..#...#...#..#...#...#..#...#...#..#...#...#..#...#...#..\n",
74 | ".#....X..#..#....#..#..#....#..#..#....#..#..#....#..#..#....#..#.\n",
75 | "..#.#...#O#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#\n",
76 | ".#...##..#..X...##..#..#...##..#..#...##..#..#...##..#..#...##..#.\n",
77 | "..#.##.......#.X#.......#.##.......#.##.......#.##.......#.##..... --->\n",
78 | ".#.#.#....#.#.#.#.O..#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#\n",
79 | ".#........#.#........X.#........#.#........#.#........#.#........#\n",
80 | "#.##...#...#.##...#...#.X#...#...#.##...#...#.##...#...#.##...#...\n",
81 | "#...##....##...##....##...#X....##...##....##...##....##...##....#\n",
82 | ".#..#...#.#.#..#...#.#.#..#...X.#.#..#...#.#.#..#...#.#.#..#...#.# --->\n",
83 | "```\n",
84 | "\n",
85 | "In this example, traversing the map using this slope would cause you to\n",
86 | "encounter 7 trees.\n",
87 | "\n",
88 | "Starting at the top-left corner of your map and following a slope of right 3 and\n",
89 | "down 1, **how many trees would you encounter?**\n"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {},
95 | "source": [
96 | "### Load Input data\n"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | ":::{note} The input data can be found\n",
104 | "[here](https://adventofcode.com/2020/day/3). :::\n"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": 1,
110 | "metadata": {},
111 | "outputs": [
112 | {
113 | "name": "stdout",
114 | "output_type": "stream",
115 | "text": [
116 | "323\n",
117 | "['.', '.', '.', '.', '.', '.', '.', '.', '#', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '#', '.', '.', '.', '.', '.', '.', '.', '.']\n"
118 | ]
119 | }
120 | ],
121 | "source": [
122 | "with open('../../data/advent-of-code/2020/day-3-input') as fid:\n",
123 | " data = fid.readlines()\n",
124 | " data = [list(x.strip()) for x in data if x != '\\n']\n",
125 | "\n",
126 | "print(len(data))\n",
127 | "print(data[0])"
128 | ]
129 | },
130 | {
131 | "cell_type": "markdown",
132 | "metadata": {},
133 | "source": [
134 | "### Solution\n"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "execution_count": 2,
140 | "metadata": {},
141 | "outputs": [],
142 | "source": [
143 | "def tree_counter(terrain, slope, tree='#'):\n",
144 | " \"\"\"Count how many trees we encounter\"\"\"\n",
145 | " right_step, down_step = slope\n",
146 | " tree_count, idx = 0, 0\n",
147 | " for row in terrain[down_step::down_step]:\n",
148 | " idx += right_step\n",
149 | " indexer = idx % len(row)\n",
150 | " if row[indexer] == tree:\n",
151 | " tree_count += 1\n",
152 | " return tree_count"
153 | ]
154 | },
155 | {
156 | "cell_type": "markdown",
157 | "metadata": {},
158 | "source": [
159 | "Let's create a small test sample to use for validating the solution above:\n"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": 3,
165 | "metadata": {},
166 | "outputs": [],
167 | "source": [
168 | "test_data = \"\"\"..##.........##.........##.........##.........##.........##.......\n",
169 | "#...#...#..#...#...#..#...#...#..#...#...#..#...#...#..#...#...#..\n",
170 | ".#....#..#..#....#..#..#....#..#..#....#..#..#....#..#..#....#..#.\n",
171 | "..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#..#.#...#.#\n",
172 | ".#...##..#..#...##..#..#...##..#..#...##..#..#...##..#..#...##..#.\n",
173 | "..#.##.......#.##.......#.##.......#.##.......#.##.......#.##.....\n",
174 | ".#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#.#.#.#....#\n",
175 | ".#........#.#........#.#........#.#........#.#........#.#........#\n",
176 | "#.##...#...#.##...#...#.##...#...#.##...#...#.##...#...#.##...#...\n",
177 | "#...##....##...##....##...##....##...##....##...##....##...##....#\n",
178 | ".#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.#.#..#...#.#\"\"\".splitlines()\n",
179 | "\n",
180 | "test_data = [list(line) for line in test_data]"
181 | ]
182 | },
183 | {
184 | "cell_type": "markdown",
185 | "metadata": {},
186 | "source": [
187 | "Running the `tree_counter` function with a slope of `(3, 1)` produces the right\n",
188 | "output:\n"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": 4,
194 | "metadata": {},
195 | "outputs": [
196 | {
197 | "data": {
198 | "text/plain": [
199 | "7"
200 | ]
201 | },
202 | "execution_count": 4,
203 | "metadata": {},
204 | "output_type": "execute_result"
205 | }
206 | ],
207 | "source": [
208 | "tree_counter(test_data, slope=(3, 1))"
209 | ]
210 | },
211 | {
212 | "cell_type": "markdown",
213 | "metadata": {},
214 | "source": [
215 | "Now that we are somewhat confident about the validity of our solution, let's use\n",
216 | "our full input data to count how many trees we will encounter:\n"
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": 5,
222 | "metadata": {},
223 | "outputs": [
224 | {
225 | "name": "stdout",
226 | "output_type": "stream",
227 | "text": [
228 | "Found 148 Trees\n"
229 | ]
230 | }
231 | ],
232 | "source": [
233 | "print(f'Found {tree_counter(data, slope=(3, 1))} Trees')"
234 | ]
235 | },
236 | {
237 | "cell_type": "markdown",
238 | "metadata": {},
239 | "source": [
240 | "## Part Two\n",
241 | "\n",
242 | "Time to check the rest of the slopes - you need to minimize the probability of a\n",
243 | "sudden arboreal stop, after all.\n",
244 | "\n",
245 | "Determine the number of trees you would encounter if, for each of the following\n",
246 | "slopes, you start at the top-left corner and traverse the map all the way to the\n",
247 | "bottom:\n",
248 | "\n",
249 | "- Right 1, down 1.\n",
250 | "- Right 3, down 1. (This is the slope you already checked.)\n",
251 | "- Right 5, down 1.\n",
252 | "- Right 7, down 1.\n",
253 | "- Right 1, down 2.\n",
254 | "\n",
255 | "In the above example, these slopes would find 2, 7, 3, 4, and 2 tree(s)\n",
256 | "respectively; multiplied together, these produce the answer 336.\n",
257 | "\n",
258 | "**What do you get if you multiply together the number of trees encountered on\n",
259 | "each of the listed slopes?**\n"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "### Solution\n",
267 | "\n",
268 | "For part two, all we have to do is compute the number of trees for each slope,\n",
269 | "and use the `math.prod` function to multiply together the number of trees found.\n",
270 | "Here's a code cell that demonstrates that this logic works as expected when\n",
271 | "using the test sample data:\n"
272 | ]
273 | },
274 | {
275 | "cell_type": "code",
276 | "execution_count": 6,
277 | "metadata": {},
278 | "outputs": [
279 | {
280 | "data": {
281 | "text/plain": [
282 | "([2, 7, 3, 4, 2], 336)"
283 | ]
284 | },
285 | "execution_count": 6,
286 | "metadata": {},
287 | "output_type": "execute_result"
288 | }
289 | ],
290 | "source": [
291 | "import math\n",
292 | "\n",
293 | "slopes = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]\n",
294 | "counts = [tree_counter(test_data, slope) for slope in slopes]\n",
295 | "counts, math.prod(counts)"
296 | ]
297 | },
298 | {
299 | "cell_type": "markdown",
300 | "metadata": {},
301 | "source": [
302 | "It's now time to get the value for the full input data:\n"
303 | ]
304 | },
305 | {
306 | "cell_type": "code",
307 | "execution_count": 7,
308 | "metadata": {},
309 | "outputs": [
310 | {
311 | "name": "stdout",
312 | "output_type": "stream",
313 | "text": [
314 | "Counts for the given slopes [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]: \n",
315 | "\t\t\t\t[50, 148, 53, 64, 29]\n",
316 | "The total number of trees encountered: 727923200\n"
317 | ]
318 | }
319 | ],
320 | "source": [
321 | "counts = [tree_counter(data, slope) for slope in slopes]\n",
322 | "counts, math.prod(counts)\n",
323 | "\n",
324 | "print(\n",
325 | " f'Counts for the given slopes {slopes}: \\n\\t\\t\\t\\t{counts}\\nThe total number of trees encountered: {math.prod(counts)}'\n",
326 | ")"
327 | ]
328 | }
329 | ],
330 | "metadata": {
331 | "author": "Anderson Banihirwe",
332 | "date": "2020-12-03",
333 | "kernelspec": {
334 | "display_name": "Python 3",
335 | "language": "python",
336 | "name": "python3"
337 | },
338 | "language_info": {
339 | "codemirror_mode": {
340 | "name": "ipython",
341 | "version": 3
342 | },
343 | "file_extension": ".py",
344 | "mimetype": "text/x-python",
345 | "name": "python",
346 | "nbconvert_exporter": "python",
347 | "pygments_lexer": "ipython3",
348 | "version": "3.8.8"
349 | },
350 | "tags": "python,adventofcode",
351 | "title": "Advent of Code - Day 3: Toboggan Trajectory",
352 | "widgets": {
353 | "application/vnd.jupyter.widget-state+json": {
354 | "state": {},
355 | "version_major": 2,
356 | "version_minor": 0
357 | }
358 | }
359 | },
360 | "nbformat": 4,
361 | "nbformat_minor": 4
362 | }
363 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-2.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 2: Password Philosophy\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "Your flight departs in a few days from the coastal airport; the easiest way down\n",
17 | "to the coast from here is via\n",
18 | "[toboggan](https://en.wikipedia.org/wiki/Toboggan).\n",
19 | "\n",
20 | "The shopkeeper at the North Pole Toboggan Rental Shop is having a bad day.\n",
21 | "\"Something's wrong with our computers; we can't log in!\" You ask if you can take\n",
22 | "a look.\n",
23 | "\n",
24 | "Their password database seems to be a little corrupted: some of the passwords\n",
25 | "wouldn't have been allowed by the Official Toboggan Corporate Policy that was in\n",
26 | "effect when they were chosen.\n",
27 | "\n",
28 | "To try to debug the problem, they have created a list (your puzzle input) of\n",
29 | "passwords (according to the corrupted database) and the corporate policy when\n",
30 | "that password was set.\n",
31 | "\n",
32 | "For example, suppose you have the following list:\n",
33 | "\n",
34 | "- 1-3 a: abcde\n",
35 | "- 1-3 b: cdefg\n",
36 | "- 2-9 c: ccccccccc\n",
37 | "\n",
38 | "Each line gives the password policy and then the password. The password policy\n",
39 | "indicates the lowest and highest number of times a given letter must appear for\n",
40 | "the password to be valid. For example, 1-3 a means that the password must\n",
41 | "contain a at least 1 time and at most 3 times.\n",
42 | "\n",
43 | "In the above example, 2 passwords are valid. The middle password, cdefg, is not;\n",
44 | "it contains no instances of b, but needs at least 1. The first and third\n",
45 | "passwords are valid: they contain one a or nine c, both within the limits of\n",
46 | "their respective policies.\n",
47 | "\n",
48 | "How many passwords are valid according to their policies?\n"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "### Load Input data\n"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | ":::{note} The input data can be found\n",
63 | "[here](https://adventofcode.com/2020/day/2). :::\n"
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": 1,
69 | "metadata": {},
70 | "outputs": [],
71 | "source": [
72 | "with open('../../data/advent-of-code/2020/day-2-input') as fid:\n",
73 | " data = fid.readlines()\n",
74 | " data = [x.strip() for x in data if x != '\\n']"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": 2,
80 | "metadata": {},
81 | "outputs": [
82 | {
83 | "data": {
84 | "text/plain": [
85 | "(['6-7 z: dqzzzjbzz',\n",
86 | " '13-16 j: jjjvjmjjkjjjjjjj',\n",
87 | " '5-6 m: mmbmmlvmbmmgmmf',\n",
88 | " '2-4 k: pkkl'],\n",
89 | " 1000)"
90 | ]
91 | },
92 | "execution_count": 2,
93 | "metadata": {},
94 | "output_type": "execute_result"
95 | }
96 | ],
97 | "source": [
98 | "data[:4], len(data)"
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | "### Solution\n",
106 | "\n",
107 | "My solution consists of a single function that parses and validates a single\n",
108 | "password and returns `True` when the password is valid.\n"
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "execution_count": 3,
114 | "metadata": {},
115 | "outputs": [],
116 | "source": [
117 | "import collections"
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": 4,
123 | "metadata": {},
124 | "outputs": [],
125 | "source": [
126 | "def is_valid_password(entry):\n",
127 | " \"\"\"\n",
128 | " Checks whether the password is valid according to the policy.\n",
129 | " \"\"\"\n",
130 | " required_count, letter, password = entry.split()\n",
131 | " letter = letter.split(':')[0]\n",
132 | " min_req_count, max_req_count = required_count.split('-')\n",
133 | " min_req_count, max_req_count = int(min_req_count), int(max_req_count)\n",
134 | " count = collections.Counter(password) # Get a count for each letter in the password\n",
135 | " return min_req_count <= count[letter] <= max_req_count"
136 | ]
137 | },
138 | {
139 | "cell_type": "markdown",
140 | "metadata": {},
141 | "source": [
142 | "Let's validate the password in the example so as to make sure this function is\n",
143 | "working properly:\n"
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": 5,
149 | "metadata": {},
150 | "outputs": [
151 | {
152 | "data": {
153 | "text/plain": [
154 | "True"
155 | ]
156 | },
157 | "execution_count": 5,
158 | "metadata": {},
159 | "output_type": "execute_result"
160 | }
161 | ],
162 | "source": [
163 | "is_valid_password('1-3 a: abcde')"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 6,
169 | "metadata": {},
170 | "outputs": [
171 | {
172 | "data": {
173 | "text/plain": [
174 | "False"
175 | ]
176 | },
177 | "execution_count": 6,
178 | "metadata": {},
179 | "output_type": "execute_result"
180 | }
181 | ],
182 | "source": [
183 | "is_valid_password('1-3 b: cdefg')"
184 | ]
185 | },
186 | {
187 | "cell_type": "code",
188 | "execution_count": 7,
189 | "metadata": {},
190 | "outputs": [
191 | {
192 | "data": {
193 | "text/plain": [
194 | "True"
195 | ]
196 | },
197 | "execution_count": 7,
198 | "metadata": {},
199 | "output_type": "execute_result"
200 | }
201 | ],
202 | "source": [
203 | "is_valid_password('2-9 c: ccccccccc')"
204 | ]
205 | },
206 | {
207 | "cell_type": "markdown",
208 | "metadata": {},
209 | "source": [
210 | "Now that we are confident this function is working properly, let's loop over all\n",
211 | "entries in the input dataset, and count how many passwords are valid:\n"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "execution_count": 8,
217 | "metadata": {},
218 | "outputs": [],
219 | "source": [
220 | "valid_passwords = 0\n",
221 | "for entry in data:\n",
222 | " if is_valid_password(entry):\n",
223 | " valid_passwords += 1"
224 | ]
225 | },
226 | {
227 | "cell_type": "code",
228 | "execution_count": 9,
229 | "metadata": {},
230 | "outputs": [
231 | {
232 | "data": {
233 | "text/plain": [
234 | "542"
235 | ]
236 | },
237 | "execution_count": 9,
238 | "metadata": {},
239 | "output_type": "execute_result"
240 | }
241 | ],
242 | "source": [
243 | "valid_passwords"
244 | ]
245 | },
246 | {
247 | "cell_type": "code",
248 | "execution_count": 10,
249 | "metadata": {},
250 | "outputs": [
251 | {
252 | "name": "stdout",
253 | "output_type": "stream",
254 | "text": [
255 | "Out of 1000 passwords, 542 are found to be valid.\n"
256 | ]
257 | }
258 | ],
259 | "source": [
260 | "print(f'Out of {len(data)} passwords, {valid_passwords} are found to be valid.')"
261 | ]
262 | },
263 | {
264 | "cell_type": "markdown",
265 | "metadata": {},
266 | "source": [
267 | "## Part Two\n",
268 | "\n",
269 | "While it appears you validated the passwords correctly, they don't seem to be\n",
270 | "what the Official Toboggan Corporate Authentication System is expecting.\n",
271 | "\n",
272 | "The shopkeeper suddenly realizes that he just accidentally explained the\n",
273 | "password policy rules from his old job at the sled rental place down the street!\n",
274 | "The Official Toboggan Corporate Policy actually works a little differently.\n",
275 | "\n",
276 | "Each policy actually describes two positions in the password, where 1 means the\n",
277 | "first character, 2 means the second character, and so on. (Be careful; Toboggan\n",
278 | "Corporate Policies have no concept of \"index zero\"!) **Exactly one of these\n",
279 | "positions must contain the given letter**. Other occurrences of the letter are\n",
280 | "irrelevant for the purposes of policy enforcement.\n",
281 | "\n",
282 | "Given the same example list from above:\n",
283 | "\n",
284 | "- 1-3 a: abcde is valid: position 1 contains a and position 3 does not.\n",
285 | "- 1-3 b: cdefg is invalid: neither position 1 nor position 3 contains b.\n",
286 | "- 2-9 c: ccccccccc is invalid: both position 2 and position 9 contain c.\n",
287 | "\n",
288 | "**How many passwords are valid according to the new interpretation of the\n",
289 | "policies?**\n"
290 | ]
291 | },
292 | {
293 | "cell_type": "markdown",
294 | "metadata": {},
295 | "source": [
296 | "### Solution\n",
297 | "\n",
298 | "My approach to part two is similar to my solution to part one in that I still\n",
299 | "have a single function for validating a single entry. In this function, I use a\n",
300 | "[bitwise XOR operator](https://en.wikipedia.org/wiki/Bitwise_operation#XOR_2).\n",
301 | "The Bitwise XOR sets the bits in the result to 1 if either, but not both, of the\n",
302 | "corresponding bits in the two operands is 1:\n"
303 | ]
304 | },
305 | {
306 | "cell_type": "code",
307 | "execution_count": 11,
308 | "metadata": {},
309 | "outputs": [],
310 | "source": [
311 | "def is_valid_password(entry):\n",
312 | " required_positions, letter, password = entry.split()\n",
313 | " letter = letter.split(':')[0]\n",
314 | " first_position, second_position = required_positions.split('-')\n",
315 | " first_position, second_position = int(first_position), int(second_position)\n",
316 | " # use bitwise XOR to make sure exactly one of the positions contains the given letter\n",
317 | " if (password[first_position - 1] == letter) ^ (password[second_position - 1] == letter):\n",
318 | " return True\n",
319 | " return False"
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {},
325 | "source": [
326 | "Once again, let's make sure this function is working properly by using the three\n",
327 | "sample examples above:\n"
328 | ]
329 | },
330 | {
331 | "cell_type": "code",
332 | "execution_count": 12,
333 | "metadata": {},
334 | "outputs": [
335 | {
336 | "data": {
337 | "text/plain": [
338 | "True"
339 | ]
340 | },
341 | "execution_count": 12,
342 | "metadata": {},
343 | "output_type": "execute_result"
344 | }
345 | ],
346 | "source": [
347 | "is_valid_password('1-3 a: abcde')"
348 | ]
349 | },
350 | {
351 | "cell_type": "code",
352 | "execution_count": 13,
353 | "metadata": {},
354 | "outputs": [
355 | {
356 | "data": {
357 | "text/plain": [
358 | "False"
359 | ]
360 | },
361 | "execution_count": 13,
362 | "metadata": {},
363 | "output_type": "execute_result"
364 | }
365 | ],
366 | "source": [
367 | "is_valid_password('1-3 b: cdefg')"
368 | ]
369 | },
370 | {
371 | "cell_type": "code",
372 | "execution_count": 14,
373 | "metadata": {},
374 | "outputs": [
375 | {
376 | "data": {
377 | "text/plain": [
378 | "False"
379 | ]
380 | },
381 | "execution_count": 14,
382 | "metadata": {},
383 | "output_type": "execute_result"
384 | }
385 | ],
386 | "source": [
387 | "is_valid_password('2-9 c: ccccccccc')"
388 | ]
389 | },
390 | {
391 | "cell_type": "markdown",
392 | "metadata": {},
393 | "source": [
394 | "It appears that this function is working.... It's now time to count all valid\n",
395 | "passwords from our input data:\n"
396 | ]
397 | },
398 | {
399 | "cell_type": "code",
400 | "execution_count": 15,
401 | "metadata": {},
402 | "outputs": [
403 | {
404 | "name": "stdout",
405 | "output_type": "stream",
406 | "text": [
407 | "Out of 1000 passwords, 360 are found to be valid.\n"
408 | ]
409 | }
410 | ],
411 | "source": [
412 | "valid_passwords = 0\n",
413 | "for entry in data:\n",
414 | " if is_valid_password(entry):\n",
415 | " valid_passwords += 1\n",
416 | "\n",
417 | "print(f'Out of {len(data)} passwords, {valid_passwords} are found to be valid.')"
418 | ]
419 | }
420 | ],
421 | "metadata": {
422 | "author": "Anderson Banihirwe",
423 | "date": "2020-12-02",
424 | "kernelspec": {
425 | "display_name": "Python 3",
426 | "language": "python",
427 | "name": "python3"
428 | },
429 | "language_info": {
430 | "codemirror_mode": {
431 | "name": "ipython",
432 | "version": 3
433 | },
434 | "file_extension": ".py",
435 | "mimetype": "text/x-python",
436 | "name": "python",
437 | "nbconvert_exporter": "python",
438 | "pygments_lexer": "ipython3",
439 | "version": "3.8.8"
440 | },
441 | "tags": "python,adventofcode",
442 | "title": "Advent of Code - Day 2: Password Philosophy",
443 | "widgets": {
444 | "application/vnd.jupyter.widget-state+json": {
445 | "state": {},
446 | "version_major": 2,
447 | "version_minor": 0
448 | }
449 | }
450 | },
451 | "nbformat": 4,
452 | "nbformat_minor": 4
453 | }
454 |
--------------------------------------------------------------------------------
/data/advent-of-code/2020/day-5-input:
--------------------------------------------------------------------------------
1 | FBBFFBBLLL
2 | FFBFFFBRLL
3 | FFBBBBFRRL
4 | FBFBBBBRLL
5 | BFBBBBFLLR
6 | FFFBBBBLRR
7 | BFFFFFBLLL
8 | BBFFFBFRRL
9 | FFBFFFFLLR
10 | BFFFBBBRRL
11 | FBFBFFFLRL
12 | FFFBBFBLRR
13 | FBFBFBFLRR
14 | FBBBBFBRRL
15 | BFFBFFBRRR
16 | FBBBFBBRLL
17 | FBFFBFBRLR
18 | BBFBFFFLRL
19 | FFBFFFFRLR
20 | FFBBFBFRRR
21 | BFBBBFBLRR
22 | FFBBFFFLRL
23 | FBBBBFFRLR
24 | FBBBBBBRLR
25 | FFBFBFBLLL
26 | BBFBFBBLLL
27 | FFFFFBBRRL
28 | FBFFBFBRRR
29 | FFFBFFFRLL
30 | BFBFBFFLLL
31 | BFBFFBFLLL
32 | FFFFBFFRRL
33 | FBFFFFFRLR
34 | FBBFFBBLLR
35 | BFFFFFBLRL
36 | BFBFFFBLLR
37 | FBBBBBBLLL
38 | BBFBFBFLLL
39 | FFBFFBFLRR
40 | BBFFFBBRLL
41 | FFBFFFFLLL
42 | FBBFFBFLLL
43 | FFFBBBFRRR
44 | BFBBFBFRLL
45 | FBBFBFFRRL
46 | FBFBBFBLRR
47 | FFBBBBBRLR
48 | FFBFBFFLLL
49 | FBFFFBFRRL
50 | BFFBBFFRLL
51 | BFFBBFFLLR
52 | BBFFBFFRRL
53 | FBFBFBFLLR
54 | BBFFBFBLRL
55 | BFBFBFBLRR
56 | FFBBFBBRRL
57 | BFBBBFBRLR
58 | FBFFFFBLLR
59 | BFBFFBBLRR
60 | BBFBFBFRRR
61 | FFBFBBBRRL
62 | BFBFBBFRLR
63 | FBFBBBBRLR
64 | BFFFFBBRRR
65 | BBFFFBFLLR
66 | FBFFFFBRRL
67 | BBFFBFBLLL
68 | BFFFBBBLLL
69 | FFBFFFBLRR
70 | BFBFBBBRRR
71 | FBFFBFFRRR
72 | BFFBFFBLLL
73 | BFBBFFFLRL
74 | BBFBFFBRLR
75 | FBBFFFFLLL
76 | FBFFFFBLLL
77 | BBFFFFBRLR
78 | BBFBFFBRRL
79 | FBBFBFBRRR
80 | FBFFBFFLRR
81 | FFBBBFBLLR
82 | FFFFFBFRRR
83 | BFBBBBBLLR
84 | BBFBFFFRLL
85 | BFFBFBBLRR
86 | BFFBBFBRLL
87 | FBFFBFFRLR
88 | FBFBBFFLLR
89 | FFFFFBFRRL
90 | FFBFFBFRLR
91 | FBFBBBFLLL
92 | FFBFBBFLLR
93 | FBFFBBBRLR
94 | FFFBFBFLLR
95 | BFBBFBBLRL
96 | BFFFFBFLLL
97 | BFBFFBFLRL
98 | BBFFBFBLLR
99 | BFFFBFBRRL
100 | BBFBFFBLLR
101 | FFBBFFFRLL
102 | FFFFFBBRLR
103 | FFBFBFBRLL
104 | FBBBBFBLRR
105 | FFFBFFFRRL
106 | FFFFBFFLRL
107 | FFFFBFFRLR
108 | BFFFFFFRRR
109 | BBFFBFBRRL
110 | BBFBFFFLRR
111 | FFBBBFFLLR
112 | FBFBFBBRLR
113 | FBBFBBBLRR
114 | BFFBBBFRLL
115 | BFBBFBBLLL
116 | FBFFFBBLLR
117 | FBBBBFFRRL
118 | BFBBFFFLLR
119 | BFBBBFFLRL
120 | FFBFFBBRLL
121 | FBFBFFBRRR
122 | FBBFBBBLRL
123 | BFFFBFFLRL
124 | BFFBFFBLRR
125 | BFBFBBFLRL
126 | FBFBBFFRLL
127 | BFFFFBBRRL
128 | FFBBBBBLRL
129 | FBBFFBFRRL
130 | BBFFBFBRLL
131 | FBFFFFFLRL
132 | FFFBFBFRLR
133 | FFBBBBFLLR
134 | FFFBBBFRLR
135 | FFBBFFBRRR
136 | FFFBFFBLRL
137 | FBFBFBBLLL
138 | BFFFFBBLRR
139 | BBFFBBFLLR
140 | FFFFFFBRLL
141 | FBBBBBBLRR
142 | FFFFBFBLLR
143 | BBFFBBFRRL
144 | BFBBBBBLRR
145 | BFBBFBBLRR
146 | BBFFFFBRRR
147 | BFBBBFBLLR
148 | BBFFBBBRRR
149 | FBBFBFBRLL
150 | FFFFFBBLRR
151 | BBFBFBBLLR
152 | FBFFFBFRLR
153 | BBFFBFFLLR
154 | BBFBFFFRLR
155 | FFFFBFBLRL
156 | FFBBBBBLRR
157 | FBBBFFBLRR
158 | FBBFBBFRLL
159 | FBBFBFBRLR
160 | FFBFBBBLRL
161 | FBFFBBBLLL
162 | FFFBBBBRRR
163 | FFBFFBFLRL
164 | BFFFBBFRLL
165 | BFFFFBBLLR
166 | BFFFFFBRRL
167 | BFFBFBBRRL
168 | FFBFFFBRRL
169 | BFFBFFFLRL
170 | BFFBBBFLLL
171 | FFBBFFFLRR
172 | FBBBFFBRLL
173 | FFBBFFFRLR
174 | BFBFBFFRLL
175 | FFFFBBFRRR
176 | BFBFBBFRRL
177 | FBFBBBFLRL
178 | FFFBFBBRLL
179 | FFBBBFFLLL
180 | BBFFFBBLRL
181 | FBBBFFBRRR
182 | BFBFBFBLLL
183 | FFBFFBBRLR
184 | FFBFBBBRLR
185 | FFFFFFBRLR
186 | BFFBBFFLRL
187 | FFBFFBFRRR
188 | FFBFBFFRLL
189 | FBFBFFBLLR
190 | FBFBFBBRRR
191 | FFFBBFBRRR
192 | FBBBBFBLLR
193 | FFFFBFBRLR
194 | FFFBBBFRLL
195 | FBFFBFBLLL
196 | FBFBFFFLRR
197 | FFFBBFFLLL
198 | BFBFFFFLLL
199 | BBFFFBFLLL
200 | FFFFBFBRRL
201 | FFBBBFBRRL
202 | BFBFFBBRLR
203 | FFFBBFFLRL
204 | FFFBFBBLLR
205 | FFBBBFFRLR
206 | FBBBBFBLRL
207 | BFFFBBFLLL
208 | BFFBFBFLLR
209 | FBFFBBFLRR
210 | BFFBBBBLLR
211 | FBBBFFFRRR
212 | FBFFBFBLRL
213 | BFFFFFFRLR
214 | FBBBBFBRRR
215 | FFBBBBFLRL
216 | BBFBFFBLRL
217 | BFBFBBBLRR
218 | FFFFFBFLLR
219 | FBBFFBFLLR
220 | BFFFFBBRLL
221 | FFBFBBBLRR
222 | FFFFBFFLLR
223 | BBFFFFFRLR
224 | FBBBBFFRLL
225 | BFFFBFBLRR
226 | FBFBBBBLLR
227 | BFFBFFBRLL
228 | BFBFBFFLRR
229 | BFFFFBFLRR
230 | FBBFFBFLRR
231 | BFFBBFBLLR
232 | FBBFFFBLRL
233 | FBFBFBBRRL
234 | FBFFBFFRRL
235 | BFBBFBFLLR
236 | FFFFBFFLRR
237 | BFBFFFBLRL
238 | BFFBBBBRRR
239 | FFFFBBBLRR
240 | FFFBBFBLLL
241 | FFBBFBFLLR
242 | BFBBFBFLLL
243 | FBBFBFFLLR
244 | FFFBBFFRRR
245 | FFBBBBBRRR
246 | FFFBFFFRLR
247 | BFFBFBFLRR
248 | FBFFBFBRLL
249 | FFFFBFFLLL
250 | FFBBBFFRLL
251 | FBFBFFBLLL
252 | FBFBBBFLLR
253 | BFBBBFFRLL
254 | BFBBBBBRRL
255 | FFFFFFBRRL
256 | FBBFBBFLRL
257 | BFFBFBBRLL
258 | FFFFFBFLRL
259 | BFBFFFBLRR
260 | BBFFFBFLRR
261 | BFBFBBBLRL
262 | FBFFFFBRLR
263 | BFBFBBBLLL
264 | BFFFFFFRRL
265 | FBBFFFBRRR
266 | FBBFBFFLRL
267 | BBFFFFFLRL
268 | BFFFFBBLRL
269 | FBFBBFFRRR
270 | FBBFFFFLRR
271 | FFFBFFFLRR
272 | FBFBBFFRRL
273 | BFFBFFBRRL
274 | BFFBFBFRRL
275 | FFBBFBBLLR
276 | FBFFBFFRLL
277 | BFBFFBBLLL
278 | FFBBFFBLLL
279 | BBFFFBBRRL
280 | BFFFFFFLLL
281 | FFBBBBFRLL
282 | BFBBBBFRRR
283 | BFFBBBBRLR
284 | FBFFBBFRLL
285 | BBFBFFBLRR
286 | FBFFBBBLRR
287 | BBFBFFFRRL
288 | BFBFFFFLRR
289 | BFBFFBBRRR
290 | FBBFFFBLLL
291 | BFFBBBFRLR
292 | BFFFFBFRLL
293 | FBFBBBBRRL
294 | BBFFBBFLRL
295 | FBBBBFFLLR
296 | BFBBFFBRRR
297 | FBBFFBBLRR
298 | FBBBBBBRRL
299 | BBFFFBBLLR
300 | BFBBBBFLRL
301 | BFFBFFFRLR
302 | FFFFBFBRRR
303 | FFFFBFBRLL
304 | BFFFFFFRLL
305 | BFFFBBBRLL
306 | FFFFFBBLLL
307 | FBFFFBFLRR
308 | FBFBFBFLLL
309 | BFBBFFBRLL
310 | BFFFBBFRLR
311 | BFBBFFFRLL
312 | FFFBBFBLRL
313 | BBFFFFFLRR
314 | BBFFFBFRLR
315 | BFBBBBFLRR
316 | FBFFFBBLLL
317 | BBFFBFBRRR
318 | FBFBFBBLRR
319 | FBBFBFFRLR
320 | FBFBBBBLLL
321 | FFFBBFBLLR
322 | FFFFBBBRRL
323 | FFBBBBFRLR
324 | FFFBFFBRRL
325 | BFBBFBBLLR
326 | FFBFFFFLRL
327 | BFFBFBFRLR
328 | FFBBFBBLLL
329 | BFFBBBFLRL
330 | FFFFFBFRLL
331 | BFFBFFBRLR
332 | BFFFBFFRRL
333 | BFBFBBBRLL
334 | BFFFFFBLRR
335 | FBBFFBBRLL
336 | FFFFBBBLRL
337 | BBFFFFBLRR
338 | BFBFBBBLLR
339 | BFFFBFFRLR
340 | BFBBFBFRRR
341 | BFFBBBFLRR
342 | FFBFBBFRRR
343 | FBBBFBFRLR
344 | BFBFFBBRLL
345 | BBFFBFFRLL
346 | BFFFBFBLLR
347 | FBFBBFFLRL
348 | BFFFFBBLLL
349 | BFBBFBBRRL
350 | BFFFBFFLLL
351 | BFBBBFBLLL
352 | FFBBFBFLRR
353 | FFBBFBFRLR
354 | BFBBBFFRRR
355 | BBFBFFFLLL
356 | BFFFFFBRLL
357 | FBBFBBFRRR
358 | BFFFBBFLRR
359 | BFFBBBFRRL
360 | FFBFFFFRRL
361 | FBFFBFBLRR
362 | FFBFBFBRLR
363 | BBFFBFFLRR
364 | BFFBBFFLLL
365 | FFBBBFBRRR
366 | BBFFBFFRRR
367 | FBBFFFFRRR
368 | FBBBBFFLRR
369 | FBBFBBBRRR
370 | FFBFBFBLRL
371 | FBBFFFBLRR
372 | FBFFBFFLRL
373 | BFBBFFFRRR
374 | FBFBBBFRLR
375 | BFFFFFBRRR
376 | FBFBFFFRRR
377 | BBFFFBFLRL
378 | FFBFBFBLLR
379 | FBFFFBBRRL
380 | FBBBFFBLLL
381 | BFBFBFFRRR
382 | FBFFBBBRLL
383 | FFBFFBBLLR
384 | FFBBFBBRLL
385 | BFBFBBFRLL
386 | BFBBFFBLLL
387 | BFFBBBFRRR
388 | BFBFBFBRRL
389 | BFFFFFFLLR
390 | BFFFBBBRRR
391 | FBBBFBFRRR
392 | FFFBFFBRLL
393 | BFFFFBFLRL
394 | FBFBBFFRLR
395 | FBBBBBFLRL
396 | FFFBBBFRRL
397 | BFBFFFFLLR
398 | FBFFFBBLRR
399 | FBBFBBBRRL
400 | FFFBBBFLRR
401 | BFBFFBFRRL
402 | BFFFBBFRRL
403 | FBBBFFBLLR
404 | FFBBFBBLRL
405 | BBFBFBFRLR
406 | FFBFFBFLLL
407 | FFFFBFBLLL
408 | BBFFFFBRLL
409 | FBFFFBBRLR
410 | FFBBBFFRRR
411 | FFFBFFFRRR
412 | FFBFBBBLLR
413 | FFBFFFBRLR
414 | FFBBBFBLRR
415 | BFFBBBBLRL
416 | BFFFFBFRRR
417 | BBFBFBFRLL
418 | FBFBBBFLRR
419 | FFFFFBFLLL
420 | BFBBBFFLLR
421 | BFFBFBFRRR
422 | BFBBFFBLRR
423 | BBFFFBBRLR
424 | FBBBBBBLRL
425 | BFFBBBBRRL
426 | FFBFBFFRLR
427 | BFFFFFBLLR
428 | BBFFFFBRRL
429 | FFFBBFFLRR
430 | BFFFFBFRRL
431 | BBFFBFFLRL
432 | BBFBFBFLRR
433 | FBFBBBBLRR
434 | BFFBBFBRRR
435 | FFFBBBBRLL
436 | FBFBBBFRRL
437 | FFFFFFBRRR
438 | BFFFFFFLRL
439 | FFBBFFFLLR
440 | FBBFBFBLLL
441 | FBBFBBFRLR
442 | BFFBFFBLLR
443 | FBFBBFBRLL
444 | FBFBFBFLRL
445 | FFBFFFBLLR
446 | FBBFFBBLRL
447 | FFFBBBBLLR
448 | BFFBBBBLRR
449 | BFFBFBBLLR
450 | FFBBFFBRLR
451 | FBBBBFFLLL
452 | BFFFFFBRLR
453 | BFBBBBFRLL
454 | FFFBBFFRLR
455 | BFFFBFBLLL
456 | BBFFFFFRRL
457 | FBFFFFBRLL
458 | BFBFBFBLRL
459 | FBBFBBFLRR
460 | FFBFBBFLRR
461 | FFBFBFFLRR
462 | FFBFFFFRLL
463 | BFBFBFBRRR
464 | FBBBBFFLRL
465 | FFBFFFBLLL
466 | BFBBBFFRLR
467 | FBFBFFBRLL
468 | FBBBBBFRRL
469 | FBFFBFFLLL
470 | BBFFBBBLLR
471 | BFFFBFFRRR
472 | BBFFBBBRLL
473 | BBFFFBBLRR
474 | FBBFBBBRLR
475 | BFBFBBFRRR
476 | FBFFBBFLRL
477 | FFFFBBFLRR
478 | BFFFBFBRLL
479 | BBFFFFFRLL
480 | FFFBFBFRRR
481 | BFBBBBFLLL
482 | FFBBBFBRLR
483 | FFFFBBBRRR
484 | BFBFFBFRLR
485 | FBFFBBFLLL
486 | FFBFFBBLRR
487 | FBFBFFBLRR
488 | FFBFFBBRRL
489 | FFFBBBBRRL
490 | BFFBFBBLRL
491 | BBFFBBBLRR
492 | FFFBBFBRLL
493 | FFFBFBBLRL
494 | BFBFFFBRRL
495 | FBBFFFFLLR
496 | BBFBFFBLLL
497 | BFBFBBFLLR
498 | BFFBFBBRRR
499 | FBFFFFFLLR
500 | FFBBBFFLRL
501 | FBFFBBFRLR
502 | BFFFBFBLRL
503 | FBFBBBFRRR
504 | FFBFFBFRRL
505 | FBFBBFBRLR
506 | BFBFBFFRLR
507 | FBFFBBBRRR
508 | BBFBFFFLLR
509 | FBBFBBBLLL
510 | FFBBBFBLLL
511 | FFBFFFFRRR
512 | BFFBFBFLLL
513 | BFFBBBFLLR
514 | FBBBBBBRLL
515 | FBBFFBFRLL
516 | FFFBFFBLLR
517 | FFBBFFBLRL
518 | BFBBFBFLRR
519 | BFBFFFBLLL
520 | FBFFFBBRRR
521 | FFBFBFFLLR
522 | FBFFBBBRRL
523 | FBBBBFBLLL
524 | FFFFFBBLLR
525 | FBBFBFBLRL
526 | BFBBFBBRLL
527 | FFFFBFBLRR
528 | BBFFBBFLLL
529 | FBBBFBFRLL
530 | FBFBBFBLLL
531 | BBFBFBFLLR
532 | BFBFBFBRLR
533 | FFFFFBFRLR
534 | FFFFFBBRLL
535 | FBFBFBFRRR
536 | FBBBFBFLRL
537 | BBFFBBBLRL
538 | FFBBBBBRLL
539 | FBBBFBBRRR
540 | BFFFBBBLLR
541 | BFBBBBBRLL
542 | FFFFFBBLRL
543 | BBFFBFFRLR
544 | BFBFBFBRLL
545 | FFFFBBFLLL
546 | BFBFBFFRRL
547 | FFBBFFBLLR
548 | BFBBFFFLLL
549 | BFBBFFBRLR
550 | FBFBFFBRLR
551 | FBFFFBFRLL
552 | FBBFBFFLRR
553 | FBBFFBFRRR
554 | BFBFFFFRLL
555 | BFFFBBBLRL
556 | FBFBBBBRRR
557 | BBFFBBFLRR
558 | FBBBBFBRLL
559 | BBFFBBBRRL
560 | BFBBBFFLLL
561 | FBFFFFBLRL
562 | FBFFFFFRRL
563 | BFBBBFFLRR
564 | FBBFBFBLRR
565 | FBFBFBBLRL
566 | FFBFBFFRRL
567 | BFFBBFBRLR
568 | FFBFFBBLLL
569 | FBBBFBBLLL
570 | FBBBFBBRRL
571 | FBBBFBBLLR
572 | FBFFFBFLLL
573 | FBBBFFBRLR
574 | FBBFBBBRLL
575 | FBBFFFBLLR
576 | FFFBFBBRRR
577 | FBBFFFFLRL
578 | BFFFFBFRLR
579 | FBBBFFFLLL
580 | FFBBFBFLLL
581 | BBFFFFFRRR
582 | BBFFFBFRRR
583 | FFBFFBBLRL
584 | FBBBFFBLRL
585 | FFBBFBFRRL
586 | FBFFFBFLRL
587 | FBBBFFFLRL
588 | FFFFBBBRLR
589 | FFBBFBBRLR
590 | FBFBFFBRRL
591 | BFBFFBFRRR
592 | BFBFBFFLRL
593 | BFFBFFFLLL
594 | FBBFBFBRRL
595 | FFBBBFBLRL
596 | BFFFFBFLLR
597 | FBBBFBFLLL
598 | FBFFFBBLRL
599 | FBBFFFBRRL
600 | FBBBBBFLLR
601 | FBBBFBFRRL
602 | FFFBBFBRRL
603 | FBBBFFBRRL
604 | FBFBFBBRLL
605 | BFBBBBBLLL
606 | FBFBFFFLLR
607 | FFFBFFBRLR
608 | BBFFBFBLRR
609 | BFFFBFFLLR
610 | FBBFBBFRRL
611 | FFBBBBBLLL
612 | FBBFBFFRLL
613 | FFFBBBFLRL
614 | FFBBBBFLRR
615 | FBFFFFFRLL
616 | BBFFFFBLLR
617 | FFFFBBFRRL
618 | FFBBBBFRRR
619 | FBBBFBBLRL
620 | BFFBBFBLRL
621 | BFBBFFFRLR
622 | FFFBFBBRRL
623 | BBFBFBFRRL
624 | FFFBBBFLLR
625 | BFFFFBBRLR
626 | BFFBFFFLLR
627 | BBFBFFFRRR
628 | FFFFBBFRLR
629 | BFBBBFBRRR
630 | FBFBBBBLRL
631 | FFFFBBFLLR
632 | FBFBBBFRLL
633 | BFBBFBBRLR
634 | FFBBFFFRRR
635 | FFBBBFBRLL
636 | FBBFFBFLRL
637 | BFBFFFBRRR
638 | BFFFBBBRLR
639 | FFFFBFFRRR
640 | FFBBFFBLRR
641 | FBBFBFBLLR
642 | FFFBBBFLLL
643 | FBBBBBFLLL
644 | FFFFBBBLLL
645 | FFFBFFBLLL
646 | BFBBBBBRLR
647 | BFBFBBFLRR
648 | FBFBBFBRRR
649 | BFBBFFFLRR
650 | FFBBFFFLLL
651 | BFFFBBFLLR
652 | FFBBFBFRLL
653 | FBBBFFFRLL
654 | FFFBBFBRLR
655 | BFBFFBFLRR
656 | FBFBBFBLLR
657 | FBFFFFBRRR
658 | FFFBFBBLLL
659 | FBFBFFFRRL
660 | FFFBFBFLRR
661 | FFBBBBBRRL
662 | FFFBFFFLLR
663 | BFFFBFFRLL
664 | BFBBBBBLRL
665 | FBBBFBFLRR
666 | FFFFBBBLLR
667 | BFFFBFFLRR
668 | FBBBBBFLRR
669 | FBBBBBFRLR
670 | BFFBFFFRRR
671 | FFBFBBFLRL
672 | FFBFBBFRRL
673 | FFBFFBBRRR
674 | FFFFBBFRLL
675 | BBFBFBFLRL
676 | FBFBBFFLLL
677 | BBFFFFBLLL
678 | FBBBBFFRRR
679 | BFFBFBFRLL
680 | BFBBFBFRRL
681 | FFBFBBFLLL
682 | FBFFFBFRRR
683 | FFBFFBFLLR
684 | BFBBFFBRRL
685 | FBBFFBBRRR
686 | FFBFBBBRLL
687 | FBBBBBBLLR
688 | FBFBBFBRRL
689 | BFFBFFFRLL
690 | BBFFBBFRRR
691 | FBBBBBFRLL
692 | FBBFFFFRLR
693 | FBBFFBBRLR
694 | BFBFBFBLLR
695 | FBFFBFBRRL
696 | FFFBBFFRRL
697 | FFBFBBFRLR
698 | BFFBFBBRLR
699 | BFFFBFBRRR
700 | BFBBBFFRRL
701 | FBBBFBBLRR
702 | FFFBFBFRLL
703 | FFBBFFBRLL
704 | FFFBBBBRLR
705 | FBBBFBFLLR
706 | BFBFBBBRRL
707 | FBBBFFFRLR
708 | FBFFFFFLRR
709 | FFBFBFFRRR
710 | FFFBFBBLRR
711 | FBBFBFFLLL
712 | FFBFFBFRLL
713 | FFBBBFFLRR
714 | FFBFBFBRRR
715 | FFFBBBBLRL
716 | FFBFBFFLRL
717 | FBFBBFBLRL
718 | FFFBFBFLRL
719 | BFBFFBFLLR
720 | BBFFFBFRLL
721 | FFBBBBBLLR
722 | BBFFFBBLLL
723 | BBFBFFBRRR
724 | BFBFFFBRLL
725 | FFFBFBFRRL
726 | FFBFFFFLRR
727 | BBFFFFFLLL
728 | FBBBFFFLRR
729 | BFFFBBFRRR
730 | FBBFBBBLLR
731 | BFBFFFFRRL
732 | FFBBFFBRRL
733 | BFBFFBBLRL
734 | BBFFFBBRRR
735 | FFFBBFFRLL
736 | BFFBBFBRRL
737 | BFFFFFFLRR
738 | BFBBBBFRLR
739 | FBBFFBFRLR
740 | BFFBBFFRRL
741 | BFFBFFFRRL
742 | FFFFBBBRLL
743 | FBFBFFFRLR
744 | BBFFBBFRLR
745 | BBFFBBFRLL
746 | BFFFBBFLRL
747 | FBFFBFFLLR
748 | BFBBFBFLRL
749 | FBFBFBFRLL
750 | BFBFBBBRLR
751 | BFBFFBBLLR
752 | FBBBBFBRLR
753 | FBFFFFBLRR
754 | FBFFBBFRRR
755 | BBFFBFFLLL
756 | FFFBFBFLLL
757 | BFFBBFFRRR
758 | FBBFBFFRRR
759 | BBFFBBBRLR
760 | FFFBFFBLRR
761 | FBFBFBFRLR
762 | BFBBBBBRRR
763 | BFFBFBFLRL
764 | BBFFBBBLLL
765 | BBFFFFFLLR
766 | BFBFFBFRLL
767 | BFBBBBFRRL
768 | BFBBFFBLRL
769 | BFFBBFBLLL
770 | BFFBBBBLLL
771 | BFBFBBFLLL
772 | FBFBFFFRLL
773 | FBFBFBFRRL
774 | BFFBFBBLLL
775 | FFBBFBBRRR
776 | FFFBFFBRRR
777 | FBFFFBFLLR
778 | FBFFFFFRRR
779 | FBBFBBFLLL
780 | FFFBFBBRLR
781 | FBFFFFFLLL
782 | FBBFFFFRRL
783 | BFBBFFBLLR
784 | BBFBFBBLRL
785 | FBBFBBFLLR
786 | BFBFFFFLRL
787 | FFBBFBBLRR
788 | BFBBBFBLRL
789 | BFFBBFFRLR
790 | FFFFBFFRLL
791 | BFFBBFFLRR
792 | FBBBFBBRLR
793 | FBFBFFFLLL
794 | FFBBBFFRRL
795 | BFBBFBFRLR
796 | FBFFFBBRLL
797 | FFFBFFFLRL
798 | BFBBBFBRRL
799 | FBBFFFBRLR
800 | FFBBBBFLLL
801 | FBBBFFFLLR
802 | FBFFBBFLLR
803 | FFBFBBFRLL
804 | BBFFBFBRLR
805 | FBFFBBBLLR
806 | FFBFBFBRRL
807 | BFFBFFBLRL
808 | FBFFBFBLLR
809 | FFBFBFBLRR
810 | FFBBFBFLRL
811 | FFBBFFFRRL
812 | BFBFBFFLLR
813 | FBBBBBBRRR
814 | BFBFFFFRLR
815 | BFFBBBBRLL
816 | FFFFFBBRRR
817 | FFBFFFBRRR
818 | FFFBFFFLLL
819 | BFBFFFFRRR
820 | FBBBBBFRRR
821 | FBBBFFFRRL
822 | FBBFFFFRLL
823 | FFFFFBFLRR
824 | FFBFBBBLLL
825 | BFBFFBBRRL
826 | FFFFBBFLRL
827 | BFBBBFBRLL
828 | FFBFFFBLRL
829 | FBBFFFBRLL
830 | BFFBBFBLRR
831 | FFFBBFFLLR
832 | FBBFFBBRRL
833 | FFBFBBBRRR
834 | FBFBFFBLRL
835 | BFBBFBBRRR
836 | BBFFFFBLRL
837 | FBFBFBBLLR
838 | BFFFBBBLRR
839 | BFBFFFBRLR
840 | FFFBBBBLLL
841 | BFFBFFFLRR
842 | BFBBFFFRRL
843 | FBFFBBBLRL
844 | FBFBBFFLRR
845 | FBFFBBFRRL
846 | BBFBFFBRLL
847 |
--------------------------------------------------------------------------------
/posts/2020/advent-of-code-day-8.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Advent of Code - Day 8: Handheld Halting\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## Part One\n",
15 | "\n",
16 | "Your flight to the major airline hub reaches cruising altitude without incident.\n",
17 | "While you consider checking the in-flight menu for one of those drinks that come\n",
18 | "with a little umbrella, you are interrupted by the kid sitting next to you.\n",
19 | "\n",
20 | "Their\n",
21 | "[handheld game console](https://en.wikipedia.org/wiki/Handheld_game_console)\n",
22 | "won't turn on! They ask if you can take a look.\n",
23 | "\n",
24 | "You narrow the problem down to a strange infinite loop in the boot code (your\n",
25 | "puzzle input) of the device. You should be able to fix it, but first you need to\n",
26 | "be able to run the code in isolation.\n",
27 | "\n",
28 | "The boot code is represented as a text file with one instruction per line of\n",
29 | "text. Each instruction consists of an operation (acc, jmp, or nop) and an\n",
30 | "argument (a signed number like +4 or -20).\n",
31 | "\n",
32 | "- `acc` increases or decreases a single global value called the accumulator by\n",
33 | " the value given in the argument. For example, acc +7 would increase the\n",
34 | " accumulator by 7. The accumulator starts at 0. After an acc instruction, the\n",
35 | " instruction immediately below it is executed next.\n",
36 | "- `jmp` jumps to a new instruction relative to itself. The next instruction to\n",
37 | " execute is found using the argument as an offset from the jmp instruction; for\n",
38 | " example, jmp +2 would skip the next instruction, jmp +1 would continue to the\n",
39 | " instruction immediately below it, and jmp -20 would cause the instruction 20\n",
40 | " lines above to be executed next.\n",
41 | "- `nop` stands for No OPeration - it does nothing. The instruction immediately\n",
42 | " below it is executed next.\n",
43 | "\n",
44 | "For example, consider the following program:\n",
45 | "\n",
46 | "```\n",
47 | "nop +0\n",
48 | "acc +1\n",
49 | "jmp +4\n",
50 | "acc +3\n",
51 | "jmp -3\n",
52 | "acc -99\n",
53 | "acc +1\n",
54 | "jmp -4\n",
55 | "acc +6\n",
56 | "```\n",
57 | "\n",
58 | "These instructions are visited in this order:\n",
59 | "\n",
60 | "```\n",
61 | "nop +0 | 1\n",
62 | "acc +1 | 2, 8(!)\n",
63 | "jmp +4 | 3\n",
64 | "acc +3 | 6\n",
65 | "jmp -3 | 7\n",
66 | "acc -99 |\n",
67 | "acc +1 | 4\n",
68 | "jmp -4 | 5\n",
69 | "acc +6 |\n",
70 | "```\n",
71 | "\n",
72 | "First, the nop +0 does nothing. Then, the accumulator is increased from 0 to 1\n",
73 | "(acc +1) and jmp +4 sets the next instruction to the other acc +1 near the\n",
74 | "bottom. After it increases the accumulator from 1 to 2, jmp -4 executes, setting\n",
75 | "the next instruction to the only acc +3. It sets the accumulator to 5, and jmp\n",
76 | "-3 causes the program to continue back at the first acc +1.\n",
77 | "\n",
78 | "This is an infinite loop: with this sequence of jumps, the program will run\n",
79 | "forever. The moment the program tries to run any instruction a second time, you\n",
80 | "know it will never terminate.\n",
81 | "\n",
82 | "Immediately before the program would run an instruction a second time, the value\n",
83 | "in the accumulator is 5.\n",
84 | "\n",
85 | "Run your copy of the boot code. Immediately before any instruction is executed a\n",
86 | "second time, **what value is in the accumulator?**\n"
87 | ]
88 | },
89 | {
90 | "cell_type": "markdown",
91 | "metadata": {},
92 | "source": [
93 | "## Load and Clean Input data\n"
94 | ]
95 | },
96 | {
97 | "cell_type": "markdown",
98 | "metadata": {},
99 | "source": [
100 | ":::{note} The input data can be found\n",
101 | "[here](https://adventofcode.com/2020/day/8). :::\n"
102 | ]
103 | },
104 | {
105 | "cell_type": "code",
106 | "execution_count": 1,
107 | "metadata": {},
108 | "outputs": [
109 | {
110 | "name": "stdout",
111 | "output_type": "stream",
112 | "text": [
113 | "656\n",
114 | "[Instruction(operation='acc', argument=-7), Instruction(operation='acc', argument=2)]\n"
115 | ]
116 | }
117 | ],
118 | "source": [
119 | "from collections import namedtuple\n",
120 | "\n",
121 | "\n",
122 | "def parse_instruction(instruction):\n",
123 | " a, b = instruction.strip().split(' ')\n",
124 | " return Instruction(a, int(b))\n",
125 | "\n",
126 | "\n",
127 | "with open('../../data/advent-of-code/2020/day-8-input') as fid:\n",
128 | " data = fid.readlines()\n",
129 | " Instruction = namedtuple('Instruction', ['operation', 'argument'])\n",
130 | " data = [parse_instruction(x) for x in data]\n",
131 | "\n",
132 | "print(len(data))\n",
133 | "print(data[0:2])"
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": 2,
139 | "metadata": {},
140 | "outputs": [
141 | {
142 | "data": {
143 | "text/plain": [
144 | "[Instruction(operation='nop', argument=0),\n",
145 | " Instruction(operation='acc', argument=1),\n",
146 | " Instruction(operation='jmp', argument=4),\n",
147 | " Instruction(operation='acc', argument=3),\n",
148 | " Instruction(operation='jmp', argument=-3),\n",
149 | " Instruction(operation='acc', argument=-99),\n",
150 | " Instruction(operation='acc', argument=1),\n",
151 | " Instruction(operation='jmp', argument=-4),\n",
152 | " Instruction(operation='acc', argument=6)]"
153 | ]
154 | },
155 | "execution_count": 2,
156 | "metadata": {},
157 | "output_type": "execute_result"
158 | }
159 | ],
160 | "source": [
161 | "test_data = \"\"\"\n",
162 | "nop +0\n",
163 | "acc +1\n",
164 | "jmp +4\n",
165 | "acc +3\n",
166 | "jmp -3\n",
167 | "acc -99\n",
168 | "acc +1\n",
169 | "jmp -4\n",
170 | "acc +6\n",
171 | "\"\"\".strip().split('\\n')\n",
172 | "\n",
173 | "clean_test_data = [parse_instruction(instruction) for instruction in test_data]\n",
174 | "clean_test_data"
175 | ]
176 | },
177 | {
178 | "cell_type": "markdown",
179 | "metadata": {},
180 | "source": [
181 | "### Solution\n"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": 3,
187 | "metadata": {},
188 | "outputs": [],
189 | "source": [
190 | "def find_program_status(instructions):\n",
191 | " accumulator, pointer = 0, 0\n",
192 | " visited = set()\n",
193 | " terminated = False\n",
194 | "\n",
195 | " while not terminated and pointer not in visited:\n",
196 | " instruction = instructions[pointer]\n",
197 | " visited.add(pointer)\n",
198 | "\n",
199 | " if instruction.operation == 'nop':\n",
200 | " pointer += 1\n",
201 | " elif instruction.operation == 'jmp':\n",
202 | " pointer += instruction.argument\n",
203 | "\n",
204 | " elif instruction.operation == 'acc':\n",
205 | " pointer += 1\n",
206 | " accumulator += instruction.argument\n",
207 | "\n",
208 | " terminated = pointer == len(instructions)\n",
209 | "\n",
210 | " return accumulator, terminated"
211 | ]
212 | },
213 | {
214 | "cell_type": "code",
215 | "execution_count": 4,
216 | "metadata": {},
217 | "outputs": [
218 | {
219 | "data": {
220 | "text/plain": [
221 | "(5, False)"
222 | ]
223 | },
224 | "execution_count": 4,
225 | "metadata": {},
226 | "output_type": "execute_result"
227 | }
228 | ],
229 | "source": [
230 | "accumulator, terminated = find_program_status(clean_test_data)\n",
231 | "accumulator, terminated"
232 | ]
233 | },
234 | {
235 | "cell_type": "code",
236 | "execution_count": 5,
237 | "metadata": {},
238 | "outputs": [
239 | {
240 | "data": {
241 | "text/plain": [
242 | "(1594, False)"
243 | ]
244 | },
245 | "execution_count": 5,
246 | "metadata": {},
247 | "output_type": "execute_result"
248 | }
249 | ],
250 | "source": [
251 | "accumulator, terminated = find_program_status(data)\n",
252 | "accumulator, terminated"
253 | ]
254 | },
255 | {
256 | "cell_type": "markdown",
257 | "metadata": {},
258 | "source": [
259 | "## Part Two\n",
260 | "\n",
261 | "After some careful analysis, you believe **that exactly one instruction is\n",
262 | "corrupted**.\n",
263 | "\n",
264 | "Somewhere in the program, either a `jmp` is supposed to be a `nop`, or a `nop`\n",
265 | "is supposed to be a `jmp`. (No `acc` instructions were harmed in the corruption\n",
266 | "of this boot code.)\n",
267 | "\n",
268 | "The program is supposed to terminate by attempting to execute an instruction\n",
269 | "immediately after the last instruction in the file. By changing exactly one\n",
270 | "`jmp` or `nop`, you can repair the boot code and make it terminate correctly.\n",
271 | "\n",
272 | "For example, consider the same program from above:\n",
273 | "\n",
274 | "```\n",
275 | "nop +0\n",
276 | "acc +1\n",
277 | "jmp +4\n",
278 | "acc +3\n",
279 | "jmp -3\n",
280 | "acc -99\n",
281 | "acc +1\n",
282 | "jmp -4\n",
283 | "acc +6\n",
284 | "```\n",
285 | "\n",
286 | "If you change the first instruction from `nop +0` to `jmp +0`, it would create a\n",
287 | "single-instruction infinite loop, never leaving that instruction. If you change\n",
288 | "almost any of the jmp instructions, the program will still eventually find\n",
289 | "another jmp instruction and loop forever.\n",
290 | "\n",
291 | "However, if you change the second-to-last instruction (from `jmp -4` to\n",
292 | "`nop -4`), the program terminates! The instructions are visited in this order:\n",
293 | "\n",
294 | "```\n",
295 | "nop +0 | 1\n",
296 | "acc +1 | 2\n",
297 | "jmp +4 | 3\n",
298 | "acc +3 |\n",
299 | "jmp -3 |\n",
300 | "acc -99 |\n",
301 | "acc +1 | 4\n",
302 | "nop -4 | 5\n",
303 | "acc +6 | 6\n",
304 | "```\n",
305 | "\n",
306 | "After the last instruction (`acc +6`), the program terminates by attempting to\n",
307 | "run the instruction below the last instruction in the file. With this change,\n",
308 | "after the program terminates, the accumulator contains the value 8 (`acc +1`,\n",
309 | "`acc +1`, `acc +6`).\n",
310 | "\n",
311 | "Fix the program so that it terminates normally by changing exactly one `jmp` (to\n",
312 | "`nop`) or `nop` (to `jmp`). **What is the value of the accumulator after the\n",
313 | "program terminates?**\n"
314 | ]
315 | },
316 | {
317 | "cell_type": "markdown",
318 | "metadata": {},
319 | "source": [
320 | "### Solution\n"
321 | ]
322 | },
323 | {
324 | "cell_type": "code",
325 | "execution_count": 6,
326 | "metadata": {},
327 | "outputs": [
328 | {
329 | "data": {
330 | "text/plain": [
331 | "8"
332 | ]
333 | },
334 | "execution_count": 6,
335 | "metadata": {},
336 | "output_type": "execute_result"
337 | }
338 | ],
339 | "source": [
340 | "import copy\n",
341 | "\n",
342 | "\n",
343 | "def fix_program(data):\n",
344 | " instructions = copy.deepcopy(data)\n",
345 | " flip = (\n",
346 | " lambda x: x._replace(operation='jmp')\n",
347 | " if x.operation == 'nop'\n",
348 | " else x._replace(operation='nop')\n",
349 | " )\n",
350 | " for idx, instruction in enumerate(instructions):\n",
351 | " if instruction.operation == 'nop' or instruction.operation == 'jmp':\n",
352 | " previous = instruction\n",
353 | " instructions[idx] = flip(instruction)\n",
354 | " accumulator, terminated = find_program_status(instructions)\n",
355 | " if terminated:\n",
356 | " break\n",
357 | " instructions[idx] = previous\n",
358 | " return accumulator\n",
359 | "\n",
360 | "\n",
361 | "fix_program(clean_test_data)"
362 | ]
363 | },
364 | {
365 | "cell_type": "code",
366 | "execution_count": 7,
367 | "metadata": {},
368 | "outputs": [
369 | {
370 | "name": "stdout",
371 | "output_type": "stream",
372 | "text": [
373 | "The value of the accumulator after the program terminates is: 758\n"
374 | ]
375 | }
376 | ],
377 | "source": [
378 | "print(f'The value of the accumulator after the program terminates is: {fix_program(data)}')"
379 | ]
380 | }
381 | ],
382 | "metadata": {
383 | "author": "Anderson Banihirwe",
384 | "date": "2020-12-08",
385 | "kernelspec": {
386 | "display_name": "Python 3",
387 | "language": "python",
388 | "name": "python3"
389 | },
390 | "language_info": {
391 | "codemirror_mode": {
392 | "name": "ipython",
393 | "version": 3
394 | },
395 | "file_extension": ".py",
396 | "mimetype": "text/x-python",
397 | "name": "python",
398 | "nbconvert_exporter": "python",
399 | "pygments_lexer": "ipython3",
400 | "version": "3.8.8"
401 | },
402 | "tags": "python,adventofcode",
403 | "title": "Advent of Code - Day 8: Handheld Halting",
404 | "widgets": {
405 | "application/vnd.jupyter.widget-state+json": {
406 | "state": {},
407 | "version_major": 2,
408 | "version_minor": 0
409 | }
410 | }
411 | },
412 | "nbformat": 4,
413 | "nbformat_minor": 4
414 | }
415 |
--------------------------------------------------------------------------------
/data/advent-of-code/2020/day-9-input:
--------------------------------------------------------------------------------
1 | 14
2 | 9
3 | 43
4 | 18
5 | 13
6 | 24
7 | 3
8 | 38
9 | 33
10 | 8
11 | 41
12 | 4
13 | 32
14 | 15
15 | 31
16 | 44
17 | 17
18 | 34
19 | 21
20 | 10
21 | 50
22 | 37
23 | 2
24 | 23
25 | 6
26 | 47
27 | 5
28 | 9
29 | 11
30 | 16
31 | 12
32 | 18
33 | 7
34 | 13
35 | 26
36 | 14
37 | 19
38 | 8
39 | 20
40 | 15
41 | 29
42 | 58
43 | 17
44 | 22
45 | 21
46 | 24
47 | 25
48 | 10
49 | 27
50 | 31
51 | 33
52 | 23
53 | 28
54 | 30
55 | 34
56 | 32
57 | 35
58 | 38
59 | 49
60 | 18
61 | 26
62 | 36
63 | 37
64 | 47
65 | 39
66 | 56
67 | 40
68 | 42
69 | 43
70 | 41
71 | 44
72 | 45
73 | 46
74 | 48
75 | 50
76 | 51
77 | 53
78 | 79
79 | 73
80 | 69
81 | 117
82 | 54
83 | 55
84 | 90
85 | 57
86 | 62
87 | 75
88 | 114
89 | 85
90 | 94
91 | 110
92 | 81
93 | 98
94 | 153
95 | 86
96 | 89
97 | 204
98 | 96
99 | 101
100 | 103
101 | 104
102 | 152
103 | 169
104 | 124
105 | 135
106 | 109
107 | 143
108 | 171
109 | 119
110 | 132
111 | 137
112 | 207
113 | 166
114 | 167
115 | 184
116 | 185
117 | 170
118 | 175
119 | 182
120 | 187
121 | 190
122 | 197
123 | 233
124 | 204
125 | 212
126 | 244
127 | 299
128 | 228
129 | 339
130 | 241
131 | 246
132 | 269
133 | 415
134 | 319
135 | 298
136 | 349
137 | 337
138 | 333
139 | 444
140 | 357
141 | 345
142 | 362
143 | 365
144 | 562
145 | 377
146 | 387
147 | 401
148 | 416
149 | 541
150 | 469
151 | 472
152 | 474
153 | 647
154 | 591
155 | 487
156 | 515
157 | 567
158 | 617
159 | 686
160 | 1158
161 | 793
162 | 670
163 | 678
164 | 702
165 | 864
166 | 710
167 | 856
168 | 781
169 | 817
170 | 764
171 | 1251
172 | 1214
173 | 885
174 | 941
175 | 943
176 | 946
177 | 961
178 | 1002
179 | 1082
180 | 1456
181 | 1269
182 | 1184
183 | 2104
184 | 1364
185 | 1348
186 | 2032
187 | 1372
188 | 1742
189 | 1412
190 | 1474
191 | 1792
192 | 1545
193 | 1649
194 | 2305
195 | 2358
196 | 1826
197 | 2725
198 | 1828
199 | 3282
200 | 2043
201 | 1907
202 | 1963
203 | 2910
204 | 2266
205 | 2814
206 | 2453
207 | 2532
208 | 2712
209 | 2957
210 | 2720
211 | 2784
212 | 3903
213 | 3019
214 | 3123
215 | 4131
216 | 4006
217 | 3789
218 | 3871
219 | 3654
220 | 4811
221 | 3735
222 | 3791
223 | 5866
224 | 4309
225 | 4416
226 | 4439
227 | 4229
228 | 4719
229 | 5576
230 | 5237
231 | 8578
232 | 5244
233 | 6447
234 | 5504
235 | 8510
236 | 7445
237 | 9570
238 | 7920
239 | 6777
240 | 8725
241 | 7389
242 | 12460
243 | 7606
244 | 13305
245 | 15899
246 | 9992
247 | 14957
248 | 8748
249 | 12843
250 | 8855
251 | 14092
252 | 8948
253 | 9956
254 | 10741
255 | 10481
256 | 10748
257 | 11951
258 | 25705
259 | 12281
260 | 26647
261 | 14697
262 | 14166
263 | 25855
264 | 19473
265 | 16244
266 | 24048
267 | 16354
268 | 16461
269 | 36446
270 | 22914
271 | 17603
272 | 20704
273 | 28195
274 | 17803
275 | 18811
276 | 29429
277 | 18904
278 | 20437
279 | 41380
280 | 24914
281 | 22699
282 | 46409
283 | 26447
284 | 26978
285 | 57624
286 | 33639
287 | 33847
288 | 32598
289 | 41141
290 | 39160
291 | 33957
292 | 70570
293 | 34064
294 | 35406
295 | 36414
296 | 80323
297 | 50894
298 | 36614
299 | 36707
300 | 48333
301 | 63592
302 | 39341
303 | 43136
304 | 66445
305 | 59313
306 | 49146
307 | 92952
308 | 99043
309 | 99227
310 | 73028
311 | 66237
312 | 69012
313 | 66555
314 | 70771
315 | 68021
316 | 107362
317 | 69470
318 | 70478
319 | 71820
320 | 73121
321 | 91469
322 | 76048
323 | 73321
324 | 107478
325 | 108353
326 | 122905
327 | 142591
328 | 92282
329 | 108459
330 | 115383
331 | 125194
332 | 142791
333 | 137491
334 | 135567
335 | 132792
336 | 199928
337 | 134576
338 | 163289
339 | 138499
340 | 334504
341 | 205037
342 | 197014
343 | 142298
344 | 144941
345 | 267785
346 | 149369
347 | 271642
348 | 165603
349 | 237223
350 | 200635
351 | 207665
352 | 227849
353 | 200741
354 | 352606
355 | 259770
356 | 257986
357 | 431074
358 | 310544
359 | 267368
360 | 283440
361 | 291667
362 | 273075
363 | 304102
364 | 402068
365 | 287239
366 | 294310
367 | 307901
368 | 314972
369 | 345682
370 | 350004
371 | 350110
372 | 437245
373 | 612376
374 | 401376
375 | 408300
376 | 435514
377 | 636046
378 | 695539
379 | 675143
380 | 547009
381 | 525354
382 | 540443
383 | 684816
384 | 550808
385 | 1076162
386 | 560314
387 | 567385
388 | 933654
389 | 581549
390 | 595140
391 | 602211
392 | 664976
393 | 968614
394 | 695686
395 | 700114
396 | 751486
397 | 809676
398 | 1044346
399 | 926730
400 | 1318871
401 | 960868
402 | 1065797
403 | 1091251
404 | 1225951
405 | 1646557
406 | 2157048
407 | 1121992
408 | 1153019
409 | 1519422
410 | 1127699
411 | 1155454
412 | 1277235
413 | 1176689
414 | 1183760
415 | 1197351
416 | 1267187
417 | 1360662
418 | 1626844
419 | 1395800
420 | 1712354
421 | 2213243
422 | 1736406
423 | 1887598
424 | 1992527
425 | 2088567
426 | 2026665
427 | 2187789
428 | 2218950
429 | 2277446
430 | 2329708
431 | 2249691
432 | 2280718
433 | 2283153
434 | 2304388
435 | 2311459
436 | 3516878
437 | 2453924
438 | 2544422
439 | 5605445
440 | 2464538
441 | 3353189
442 | 3949649
443 | 3132206
444 | 3108154
445 | 5319995
446 | 5686055
447 | 3914263
448 | 3880125
449 | 5220773
450 | 4115232
451 | 4214454
452 | 4437480
453 | 4468641
454 | 4554079
455 | 4563871
456 | 4530409
457 | 5807113
458 | 4587541
459 | 4615847
460 | 4998346
461 | 6378801
462 | 10826218
463 | 5008960
464 | 5596744
465 | 7018617
466 | 6485395
467 | 6240360
468 | 6988279
469 | 7022417
470 | 9022720
471 | 8530110
472 | 7794388
473 | 7995357
474 | 8329686
475 | 8552712
476 | 8906121
477 | 13145957
478 | 8999050
479 | 12016963
480 | 12615361
481 | 9528755
482 | 15015505
483 | 14537715
484 | 10007306
485 | 13258977
486 | 10605704
487 | 12027577
488 | 13504012
489 | 11837104
490 | 15518389
491 | 13228639
492 | 14782667
493 | 27928624
494 | 14816805
495 | 15789745
496 | 16525467
497 | 16325043
498 | 16548069
499 | 21016013
500 | 21844410
501 | 17905171
502 | 23751661
503 | 20134459
504 | 26930747
505 | 19536061
506 | 20613010
507 | 22034883
508 | 22442808
509 | 31843432
510 | 25096081
511 | 29553682
512 | 36661215
513 | 25065743
514 | 26619771
515 | 29018384
516 | 36817550
517 | 38968275
518 | 30606550
519 | 41591210
520 | 32114788
521 | 25918798
522 | 36084130
523 | 34453240
524 | 37441232
525 | 38039630
526 | 47100626
527 | 63748297
528 | 57537297
529 | 40149071
530 | 43055818
531 | 42647893
532 | 44477691
533 | 47508551
534 | 54114465
535 | 61883293
536 | 50984541
537 | 56525348
538 | 51685514
539 | 52538569
540 | 54937182
541 | 58033586
542 | 69574825
543 | 93966580
544 | 60372038
545 | 103019931
546 | 62002928
547 | 70537370
548 | 95576927
549 | 75480862
550 | 117862762
551 | 82796964
552 | 178500793
553 | 112987469
554 | 123689290
555 | 85703711
556 | 107880589
557 | 174870762
558 | 103523110
559 | 124512007
560 | 102670055
561 | 120036514
562 | 125474552
563 | 161053517
564 | 107475751
565 | 112970768
566 | 169478679
567 | 122374966
568 | 130909408
569 | 211178263
570 | 132540298
571 | 137483790
572 | 183361451
573 | 278938378
574 | 198674479
575 | 215640823
576 | 293167969
577 | 416857259
578 | 218244009
579 | 188373766
580 | 193179462
581 | 249986559
582 | 206193165
583 | 220446519
584 | 227182062
585 | 210145806
586 | 294953231
587 | 229850717
588 | 235345734
589 | 244959541
590 | 243880176
591 | 382035930
592 | 319283174
593 | 367886032
594 | 270024088
595 | 315901749
596 | 320845241
597 | 371735217
598 | 468230568
599 | 592181736
600 | 381553228
601 | 544939790
602 | 418224483
603 | 394566931
604 | 436043882
605 | 399372627
606 | 416338971
607 | 426639684
608 | 439996523
609 | 474810258
610 | 611886647
611 | 465196451
612 | 473730893
613 | 480305275
614 | 743754981
615 | 710468680
616 | 1175665131
617 | 585925837
618 | 590869329
619 | 636746990
620 | 796207024
621 | 760841764
622 | 891955376
623 | 776120159
624 | 780925855
625 | 793939558
626 | 810905902
627 | 826012311
628 | 1026913211
629 | 835416509
630 | 815711598
631 | 842978655
632 | 906944959
633 | 905192974
634 | 938927344
635 | 1077083098
636 | 945501726
637 | 954036168
638 | 1066231112
639 | 1845872303
640 | 1176795166
641 | 1970734724
642 | 1222672827
643 | 1387076353
644 | 1761213324
645 | 1536961923
646 | 1726427581
647 | 2016010442
648 | 1574865413
649 | 1591831757
650 | 1739441284
651 | 1720904572
652 | 1754638942
653 | 2768626923
654 | 3420737716
655 | 1844120318
656 | 1748171629
657 | 1812137933
658 | 1850694700
659 | 1884429070
660 | 1899537894
661 | 2011732838
662 | 2020267280
663 | 3595132693
664 | 3860130760
665 | 3199214286
666 | 2609749180
667 | 3862427538
668 | 3141715295
669 | 3111827336
670 | 5215224728
671 | 3425560113
672 | 3166697170
673 | 3295769985
674 | 3312736329
675 | 3460345856
676 | 3469076201
677 | 3502810571
678 | 3560309562
679 | 3592291947
680 | 3598866329
681 | 7027362661
682 | 5049908986
683 | 4494178250
684 | 3896161908
685 | 4509287074
686 | 4032000118
687 | 5523077851
688 | 7020655418
689 | 6963156427
690 | 5721576516
691 | 5751464475
692 | 6424563665
693 | 6253542631
694 | 6278524506
695 | 8718035299
696 | 6635773371
697 | 9753576634
698 | 10572986837
699 | 6905028276
700 | 6929422057
701 | 7488453855
702 | 7095102518
703 | 7152601509
704 | 7191158276
705 | 14803485620
706 | 14583556373
707 | 7928162026
708 | 10859318335
709 | 13788374880
710 | 8541287192
711 | 9555077969
712 | 11244654367
713 | 12005007106
714 | 14417875912
715 | 11473040991
716 | 12029988981
717 | 13060337036
718 | 12532067137
719 | 12914297877
720 | 13540801647
721 | 13730875889
722 | 13834450333
723 | 14000130794
724 | 14024524575
725 | 14082023566
726 | 20883477398
727 | 26072868784
728 | 14343759785
729 | 15119320302
730 | 19933169132
731 | 22959163104
732 | 16469449218
733 | 29488247101
734 | 20799732336
735 | 18096365161
736 | 21028118960
737 | 23274643348
738 | 55561115885
739 | 24533378027
740 | 26894787369
741 | 24562056118
742 | 27540932441
743 | 25446365014
744 | 69561246679
745 | 27271677536
746 | 27565326222
747 | 27834581127
748 | 48424409839
749 | 28106548141
750 | 28425783351
751 | 42629743188
752 | 44991152530
753 | 35143492121
754 | 50169430717
755 | 40732901468
756 | 34565814379
757 | 37497568178
758 | 38896097497
759 | 39124484121
760 | 51456843487
761 | 44302762308
762 | 51700426699
763 | 49095434145
764 | 77710363158
765 | 50008421132
766 | 51833733654
767 | 54837003758
768 | 56532331492
769 | 55106258663
770 | 55378225677
771 | 55399907349
772 | 63569275472
773 | 62672362520
774 | 80134644651
775 | 93398196453
776 | 73690298500
777 | 76622052299
778 | 69709306500
779 | 72063382557
780 | 73461911876
781 | 106856750836
782 | 76393665675
783 | 115746536420
784 | 90958217775
785 | 119204694012
786 | 105627765637
787 | 99103855277
788 | 148235200211
789 | 135512870328
790 | 104845424890
791 | 110778133026
792 | 109943262421
793 | 195803642665
794 | 110484484340
795 | 118969182821
796 | 216800013257
797 | 209588339617
798 | 132381669020
799 | 141772689057
800 | 195591235120
801 | 267867025222
802 | 187809918977
803 | 303556455397
804 | 145525294433
805 | 149855577551
806 | 167351883450
807 | 181239090565
808 | 201442702115
809 | 190062073052
810 | 224832459649
811 | 204731620914
812 | 260741871878
813 | 215623557916
814 | 214788687311
815 | 306288127005
816 | 274154358077
817 | 355161802427
818 | 400322856034
819 | 252257173397
820 | 313620759585
821 | 277906963453
822 | 282237246571
823 | 356561376368
824 | 506416953919
825 | 295380871984
826 | 442319246449
827 | 312877177883
828 | 317207461001
829 | 326764384998
830 | 604671348451
831 | 348590974015
832 | 385970711479
833 | 391504775167
834 | 569950489738
835 | 419520308225
836 | 883571249323
837 | 430412245227
838 | 467045860708
839 | 488943045388
840 | 526411531474
841 | 708712236168
842 | 530164136850
843 | 640385144583
844 | 577618118555
845 | 591527723038
846 | 612588332985
847 | 595114424454
848 | 769083631447
849 | 747619706228
850 | 608258049867
851 | 908735184039
852 | 630084638884
853 | 643971845999
854 | 712735096477
855 | 897458105935
856 | 734561685494
857 | 777475486646
858 | 1027778358092
859 | 1197655281556
860 | 849932553452
861 | 919355290615
862 | 1021939968265
863 | 955988906096
864 | 1019107182238
865 | 1260973216968
866 | 1107782255405
867 | 1284356990582
868 | 1169145841593
869 | 1480017192336
870 | 1221612361922
871 | 1203372474321
872 | 1225199063338
873 | 1238342688751
874 | 1356706942476
875 | 1252229895866
876 | 1274056484883
877 | 1562667649929
878 | 2066603947528
879 | 2216762463794
880 | 1753668867732
881 | 1627408040098
882 | 1696830777261
883 | 1769287844067
884 | 2922814709325
885 | 2144554353953
886 | 1938462472853
887 | 3878803615421
888 | 2063771161501
889 | 2126889437643
890 | 2276928096998
891 | 2311154729726
892 | 2372518315914
893 | 4619645486586
894 | 2428571537659
895 | 2424984836243
896 | 2441715163072
897 | 4310980788767
898 | 3379119333509
899 | 2919374592405
900 | 2526286380749
901 | 2836724134812
902 | 4046215941065
903 | 6798178207826
904 | 3324238817359
905 | 3381076907830
906 | 6374751950268
907 | 3466118621328
908 | 3707750316920
909 | 6630565026245
910 | 4065351910496
911 | 8189784404188
912 | 4190660599144
913 | 4340699258499
914 | 8803323487927
915 | 4588082826724
916 | 4683673045640
917 | 4797503152157
918 | 7048217024245
919 | 9967591616650
920 | 5361089755477
921 | 4968001543821
922 | 5907363288579
923 | 6984726502901
924 | 5363010515561
925 | 15174510907089
926 | 8406051168995
927 | 6705315725189
928 | 6790357438687
929 | 8178580059987
930 | 8391423362560
931 | 7656779220472
932 | 8988163751301
933 | 10821225625389
934 | 9024372304139
935 | 8531359857643
936 | 8778743425868
937 | 8874333644784
938 | 8928782085223
939 | 9271755872364
940 | 11782229655058
941 | 9765504695978
942 | 10158592907634
943 | 12347737018462
944 | 10331012059382
945 | 16184236140950
946 | 14237344160345
947 | 11270373804140
948 | 14351174266862
949 | 14447136659159
950 | 13495673163876
951 | 15096739087749
952 | 14883895785176
953 | 17415795666699
954 | 28531973159412
955 | 17519523608944
956 | 16585561305695
957 | 17405693502427
958 | 17803115730007
959 | 17555732161782
960 | 32439627946958
961 | 17653077070652
962 | 20144707448924
963 | 20542129676504
964 | 32652471249531
965 | 24649400481154
966 | 19924097603612
967 | 20489604967016
968 | 21601385863522
969 | 23826685223258
970 | 24766046968016
971 | 48476085704412
972 | 25621548071002
973 | 27846847430738
974 | 31966660268103
975 | 28379568949052
976 | 29980634872925
977 | 34001356972394
978 | 33991254808122
979 | 44910754416940
980 | 61838102238860
981 | 37127690982199
982 | 34961425664209
983 | 41525483467134
984 | 35208809232434
985 | 48336452397754
986 | 37577174674264
987 | 40068805052536
988 | 53568046131625
989 | 40413702570628
990 | 47222933934524
991 | 68448374001588
992 | 42090990830538
993 | 45428071086780
994 | 54746681840941
995 | 50387595039018
996 | 53468395501740
997 | 54001117020054
998 | 56226416379790
999 | 58360203821977
1000 | 62380925921446
1001 |
--------------------------------------------------------------------------------