From 6f06e85e0b1e11ae0315a4e97b42a32cf599dc9b Mon Sep 17 00:00:00 2001
From: shreya-ahujaa <89224064+shreya-ahujaa@users.noreply.github.com>
Date: Fri, 19 Aug 2022 04:42:47 +0000
Subject: [PATCH] setup repo
---
.github/ISSUE_TEMPLATE/bug.md | 20 -
.github/ISSUE_TEMPLATE/feature_request.md | 20 -
.github/workflows/chatops.yaml | 198 ---
.github/workflows/docker.yaml | 33 -
.github/workflows/issue_reminder.yaml | 29 -
.github/workflows/setup.yaml | 112 --
CNAME | 1 -
README.md | 572 +------
_action_files/settings.ini | 3 +-
_config.yml | 8 +-
_fastpages_docs/_setup_pr_template.md | 12 +-
.../2020-02-21-introducing-fastpages.ipynb | 573 -------
_notebooks/2020-09-01-fastcore.ipynb | 1366 -----------------
_notebooks/2020-11-17-linkcheck.ipynb | 470 ------
_notebooks/fastcore_imgs/bwtm.jpg | Bin 16710 -> 0 bytes
_notebooks/fastcore_imgs/td.png | Bin 148691 -> 0 bytes
.../fastlinkcheck_images/fastlinkcheck.png | Bin 55088 -> 0 bytes
_posts/2020-03-06-fastpages-actions.md | 282 ----
_posts/2020-12-10-codespaces.md | 114 --
...020-01-01-Microsoft-Word-Example-Post.docx | Bin 407563 -> 0 bytes
action.yml | 17 -
.../fastpages_posts/actions/actions_logo.png | Bin 17486 -> 0 bytes
images/fastpages_posts/actions/pr_1.png | Bin 367199 -> 0 bytes
images/fastpages_posts/actions/pr_2.png | Bin 249181 -> 0 bytes
.../fastpages_posts/codespaces/codespaces.png | Bin 47373 -> 0 bytes
25 files changed, 27 insertions(+), 3803 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/bug.md
delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
delete mode 100755 .github/workflows/chatops.yaml
delete mode 100755 .github/workflows/docker.yaml
delete mode 100644 .github/workflows/issue_reminder.yaml
delete mode 100755 .github/workflows/setup.yaml
delete mode 100644 CNAME
delete mode 100644 _notebooks/2020-02-21-introducing-fastpages.ipynb
delete mode 100755 _notebooks/2020-09-01-fastcore.ipynb
delete mode 100755 _notebooks/2020-11-17-linkcheck.ipynb
delete mode 100644 _notebooks/fastcore_imgs/bwtm.jpg
delete mode 100644 _notebooks/fastcore_imgs/td.png
delete mode 100755 _notebooks/fastlinkcheck_images/fastlinkcheck.png
delete mode 100755 _posts/2020-03-06-fastpages-actions.md
delete mode 100755 _posts/2020-12-10-codespaces.md
delete mode 100644 _word/2020-01-01-Microsoft-Word-Example-Post.docx
delete mode 100644 action.yml
delete mode 100755 images/fastpages_posts/actions/actions_logo.png
delete mode 100755 images/fastpages_posts/actions/pr_1.png
delete mode 100755 images/fastpages_posts/actions/pr_2.png
delete mode 100755 images/fastpages_posts/codespaces/codespaces.png
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
deleted file mode 100644
index cacde65..0000000
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Bug
-about: Use this template for filing bugs
-title: ""
-labels: bug
-assignees: ''
-
----
-
-## Required Prerequisites for filing a bug
-
-### You must follow ALL the steps in the [troubleshooting guide](https://github.com/fastai/fastpages/blob/master/_fastpages_docs/TROUBLESHOOTING.md). Not doing so may result in automatic closure of the issue.
-
-
-## Required information
-
-1. Steps to reproduce the problem
-2. A link to the notebook or markdown file where the error is occurring
-3. If the error is happening in GitHub Actions, a link to the specific error along with how you are able to reproduce this error. You must provide this **in addition to the link to the notebook or markdown file**.
-4. A screenshot / dump of relevant logs or error messages you are receiving from your local development environment. Instructions of running a local development server is provided in the [development guide](https://github.com/fastai/fastpages/blob/master/_fastpages_docs/DEVELOPMENT.md).
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 11fc491..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/chatops.yaml b/.github/workflows/chatops.yaml
deleted file mode 100755
index 6bdfbd5..0000000
--- a/.github/workflows/chatops.yaml
+++ /dev/null
@@ -1,198 +0,0 @@
-name: Chatops
-on: [issue_comment]
-
-permissions:
- actions: write
- pull-requests: write
- contents: write
-
-jobs:
- trigger-chatops:
- if: (github.event.issue.pull_request != null) && contains(github.event.comment.body, '/preview') && (github.repository == 'fastai/fastpages')
- env:
- NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
- NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- CHECK_RUN_NAME: "Draft-Site-Build"
- runs-on: ubuntu-latest
- steps:
- - name: see payload
- run: |
- echo "FULL PAYLOAD:\n${PAYLOAD}\n"
- echo "PR_PAYLOAD PAYLOAD:\n${PR_PAYLOAD}"
- env:
- PAYLOAD: ${{ toJSON(github.event) }}
- PR_PAYLOAD: ${{ github.event.pull_request }}
-
- - name: verify env exists
- id: get_status
- run: |
- if [ -z ${NETLIFY_AUTH_TOKEN} ]; then echo "::set-output name=status::public"; else echo "::set-output name=status::private"; fi
-
- - name: make comment on PR if env does not exist
- if: steps.get_status.outputs.status == 'public'
- run: |
- ./_action_files/pr_comment.sh "Was not able to generate site preview due to absent credentials."
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ISSUE_NUMBER: ${{ github.event.issue.number }}
-
- - name: Fetch context about the PR that has been commented on
- id: chatops
- uses: machine-learning-apps/actions-chatops@master
- with:
- TRIGGER_PHRASE: "/preview"
- env: # you must supply GITHUB_TOKEN
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Set up Python
- uses: actions/setup-python@v1
- with:
- python-version: 3.6
-
- - name: install requests
- run: pip3 install requests
-
- - name: add check run
- id: create_check
- if: steps.get_status.outputs.status == 'private'
- shell: python
- run: |
- import os, requests
-
- sha = os.getenv('SHA')
- token = os.getenv('GITHUB_TOKEN')
- nwo = os.getenv('GITHUB_REPOSITORY')
- name = os.getenv('CHECK_RUN_NAME')
-
- url = f'https://api.github.com/repos/{nwo}/check-runs'
-
- headers = {'authorization': f'token {token}',
- 'accept': 'application/vnd.github.antiope-preview+json'}
-
- payload = {
- 'name': f'{name}',
- 'head_sha': f'{sha}',
- 'status': 'in_progress',
- 'output':{
- 'title': f'Building preview of site for {sha}.',
- 'summary': ' ',
- 'text': ' '
- },
- }
- response = requests.post(url=url, headers=headers, json=payload)
- print(response)
- id = response.json()['id']
- print(f"::set-output name=id::{id}")
- env:
- SHA: ${{ steps.chatops.outputs.SHA }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: add label
- if: steps.get_status.outputs.status == 'private'
- run: |
- import os, requests
- nwo = os.getenv('GITHUB_REPOSITORY')
- token = os.getenv('GITHUB_TOKEN')
- pr_num = os.getenv('PR_NUM')
- headers = {'Accept': 'application/vnd.github.symmetra-preview+json',
- 'Authorization': f'token {token}'}
- url = f"https://api.github.com/repos/{nwo}/issues/{pr_num}/labels"
- data = {"labels": ["draft build pending"]}
- result = requests.post(url=url, headers=headers, json=data)
- # assert response.status_code == 201, f"Received status code of {response.status_code}"
- print(result)
- shell: python
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- PR_NUM: ${{ steps.chatops.outputs.PULL_REQUEST_NUMBER }}
- GITHUB_REPOSITORY: $GITHUB_REPOSITORY
-
- - name: Copy The PR's Branch Repository Contents
- uses: actions/checkout@main
- if: steps.get_status.outputs.status == 'private'
- with:
- ref: ${{ steps.chatops.outputs.SHA }}
-
- - name: convert notebooks and word docs to posts
- uses: ./ # use the code in this repo to instead of fastai/fastpages@master
-
- - name: setup directories for Jekyll build
- if: steps.get_status.outputs.status == 'private'
- run: |
- rm -rf _site
- sudo chmod -R 777 .
-
- - name: Jekyll build with baseurl as root for netifly
- if: steps.get_status.outputs.status == 'private'
- uses: docker://fastai/fastpages-jekyll
- with:
- args: bash -c "jekyll build"
-
- - name: deploy to netlify
- if: steps.get_status.outputs.status == 'private'
- id: py
- run: |
- sudo npm install -g --unsafe-perm=true netlify-cli
- netlify deploy --dir _site | tee _netlify_logs.txt
- cat _netlify_logs.txt | python _action_files/parse_netlify.py
-
- - name: make comment on PR
- if: steps.get_status.outputs.status == 'private'
- run: |
- MSG="A preview build of this branch has been generated for SHA: $SHA and can be viewed **live** at: ${URL}\n\nThe current fastpages site built from master can be viewed for comparison [here](https://fastpages.fast.ai/)"
- echo "$MSG"
- ./_action_files/pr_comment.sh "${MSG}"
- env:
- URL: ${{ steps.py.outputs.draft_url }}
- SHA: ${{ steps.chatops.outputs.SHA }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ISSUE_NUMBER: ${{ github.event.issue.number }}
-
- - name: remove label
- if: always()
- run: |
- import os, requests
- nwo = os.getenv('GITHUB_REPOSITORY')
- token = os.getenv('GITHUB_TOKEN')
- pr_num = os.getenv('PR_NUM')
- headers = {'Accept': 'application/vnd.github.symmetra-preview+json',
- 'Authorization': f'token {token}'}
- url = f"https://api.github.com/repos/{nwo}/issues/{pr_num}/labels/draft%20build%20pending"
- result = requests.delete(url=url, headers=headers)
- print(result)
- shell: python
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- PR_NUM: ${{ steps.chatops.outputs.PULL_REQUEST_NUMBER }}
- GITHUB_REPOSITORY: $GITHUB_REPOSITORY
-
- # defensively clear check run each time
- - name: clear check run
- if: always()
- continue-on-error: true
- shell: python
- run: |
- import os, requests
-
- sha = os.getenv('SHA')
- conclusion = os.getenv('WORKFLOW_CONCLUSION').lower()
- token = os.getenv('GITHUB_TOKEN')
- nwo = os.getenv('GITHUB_REPOSITORY')
- check_run_id = os.getenv('CHECK_RUN_ID')
- if not check_run_id:
- quit()
-
- url = f'https://api.github.com/repos/{nwo}/check-runs/{check_run_id}'
- headers = {'authorization': f'token {token}',
- 'accept': 'application/vnd.github.antiope-preview+json'}
-
- data = {
- 'conclusion': f'{conclusion}',
- }
- response = requests.patch(url=url, headers=headers, json=data)
- print(response)
- env:
- SHA: ${{ steps.chatops.outputs.SHA }}
- WORKFLOW_CONCLUSION: ${{ job.status }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- CHECK_RUN_ID: ${{ steps.create_check.outputs.id }}
diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml
deleted file mode 100755
index a2b2075..0000000
--- a/.github/workflows/docker.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Build-Docker
-on:
- push:
- paths:
- - Gemfile*
- branches:
- - master
- pull_request:
- paths:
- - Gemfile*
-
-jobs:
- jekyll-fastpages:
- if: github.repository == 'fastai/fastpages'
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@main
-
- - name: setup directories for Jekyll build
- run: sudo chmod -R 777 .
-
- - name: build container
- run: |
- docker build -t fastai/fastpages-jekyll -f _action_files/fastpages-jekyll.Dockerfile .
-
- - name: push container
- if: github.event == 'push'
- run: |
- echo ${PASSWORD} | docker login -u $USERNAME --password-stdin
- docker push fastai/fastpages-jekyll
- env:
- USERNAME: ${{ secrets.DOCKER_USERNAME }}
- PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
diff --git a/.github/workflows/issue_reminder.yaml b/.github/workflows/issue_reminder.yaml
deleted file mode 100644
index 1e6634a..0000000
--- a/.github/workflows/issue_reminder.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Issue Reminder
-on:
- issues:
- types: [opened]
-
-permissions:
- actions: write
- pull-requests: write
- contents: write
-
-jobs:
- issue_comment:
- if: |
- (github.repository == 'fastai/fastpages')
- runs-on: ubuntu-latest
- steps:
- - name: Comment on issue
- uses: actions/github-script@0.6.0
- with:
- github-token: ${{secrets.GITHUB_TOKEN}}
- script: |
- var url = 'https://github.com/fastai/fastpages/blob/master/_fastpages_docs/TROUBLESHOOTING.md'
- var msg = `Thank you for opening an issue. If this issue is related to a bug, please follow the steps and provide the information outlined in the [Troubleshooting Guide](${url}). Failure to follow these instructions may result in automatic closing of this issue.`
- github.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: msg
- })
diff --git a/.github/workflows/setup.yaml b/.github/workflows/setup.yaml
deleted file mode 100755
index 17eaf5d..0000000
--- a/.github/workflows/setup.yaml
+++ /dev/null
@@ -1,112 +0,0 @@
-name: Setup
-on: push
-
-permissions:
- actions: write
- pull-requests: write
- contents: write
- deployments: write
- pages: write
- statuses: write
-
-jobs:
- setup:
- if: (github.event.commits[0].message == 'Initial commit') && (github.run_number == 1)
- runs-on: ubuntu-latest
- steps:
- - name: Set up Python
- uses: actions/setup-python@v1
- with:
- python-version: 3.6
-
- - name: Copy Repository Contents
- uses: actions/checkout@v2
-
- - name: modify files
- run: |
- import re, os
- from pathlib import Path
- from configparser import ConfigParser
- config = ConfigParser()
-
- nwo = os.getenv('GITHUB_REPOSITORY')
- username, repo_name = nwo.split('/')
- readme_template_path = Path('_fastpages_docs/README_TEMPLATE.md')
- readme_path = Path('README.md')
- config_path = Path('_config.yml')
- pr_msg_path = Path('_fastpages_docs/_setup_pr_template.md')
- settings = Path('_action_files/settings.ini')
-
- assert readme_template_path.exists(), 'Did not find _fastpages_docs/README_TEMPLATE.md in the current directory!'
- assert readme_path.exists(), 'Did not find README.md in the current directory!'
- assert config_path.exists(), 'Did not find _config.yml in the current directory!'
- assert pr_msg_path.exists(), 'Did not find _fastpages_docs/_setup_pr_template.md in the current directory!'
- assert settings.exists(), 'Did not find _action_files/settings.ini in the current directory!'
-
- # edit settings.ini file to inject baseurl
- config.read(settings)
- config['DEFAULT']['baseurl'] = f'/{repo_name}'
- with open('_action_files/settings.ini', 'w') as configfile:
- config.write(configfile)
-
- # replace content of README with template
- readme = readme_template_path.read_text().replace('{_username_}', username).replace('{_repo_name_}', repo_name)
- readme_path.write_text(readme)
-
- # update _config.yml
- cfg = config_path.read_text()
- cfg = re.sub(r'^(github_username: )(fastai)', fr'\g<1>{username}', cfg, flags=re.MULTILINE)
- cfg = re.sub(r'^(baseurl: )("")', r'\1"/{}"'.format(repo_name), cfg, flags=re.MULTILINE)
- cfg = re.sub(r'^(github_repo: ")(fastpages)', r'\1{}'.format(repo_name), cfg, flags=re.MULTILINE)
- cfg = re.sub(r'^(url: "https://)(fastpages.fast.ai)(")', fr'\g<1>{username}.github.io\3', cfg, flags=re.MULTILINE)
- cfg = re.sub('UA-57531313-5', '', cfg, flags=re.MULTILINE)
- config_path.write_text(cfg)
-
- # prepare the pr message
- pr = pr_msg_path.read_text().replace('{_username_}', username).replace('{_repo_name_}', repo_name)
- pr_msg_path.write_text(pr)
- shell: python
-
- - name: commit changes
- run: |
- git config --global user.email "${GH_EMAIL}"
- git config --global user.name "${GH_USERNAME}"
- git checkout -B fastpages-automated-setup
- git rm CNAME action.yml
- git rm _notebooks/2020-02-21-introducing-fastpages.ipynb
- git rm _notebooks/2020-09-01-fastcore.ipynb || true
- git rm _notebooks/2020-11-17-linkcheck.ipynb || true
- git rm -rf _notebooks/fastcore_imgs
- git rm -rf _notebooks/fastlinkcheck_images
- git rm _posts/2020-03-06-fastpages-actions.md
- git rm _posts/*codespaces.md || true
- git rm -rf images/fastpages_posts
- git rm .github/workflows/chatops.yaml
- git rm .github/workflows/docker.yaml
- git rm .github/workflows/issue_reminder.yaml
- git rm .github/workflows/setup.yaml
- git rm .github/ISSUE_TEMPLATE/bug.md
- git rm .github/ISSUE_TEMPLATE/feature_request.md
- git rm _word/*.docx
- git add _config.yml README.md _fastpages_docs/ _action_files/settings.ini
- git commit -m'setup repo'
- git push -f --set-upstream origin fastpages-automated-setup
- env:
- GH_EMAIL: ${{ github.event.commits[0].author.email }}
- GH_USERNAME: ${{ github.event.commits[0].author.username }}
-
- - name: Open a PR
- uses: actions/github-script@0.5.0
- with:
- github-token: ${{secrets.GITHUB_TOKEN}}
- script: |
- var fs = require('fs');
- var contents = fs.readFileSync('_fastpages_docs/_setup_pr_template.md', 'utf8');
- github.pulls.create({
- owner: context.repo.owner,
- repo: context.repo.repo,
- title: 'Initial Setup',
- head: 'fastpages-automated-setup',
- base: 'master',
- body: `${contents}`
- })
diff --git a/CNAME b/CNAME
deleted file mode 100644
index 18a648f..0000000
--- a/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-fastpages.fast.ai
diff --git a/README.md b/README.md
index 6b38105..727f1ee 100755
--- a/README.md
+++ b/README.md
@@ -1,571 +1,29 @@
-[//]: # (BADGES SECTION: change `fastai` with your GitHub username and `fastpages` with the name of your repo)
+[//]: # (This template replaces README.md when someone creates a new repo with the fastpages template.)
-![](https://github.com/fastai/fastpages/workflows/CI/badge.svg)
-![](https://github.com/fastai/fastpages/workflows/GH-Pages%20Status/badge.svg)
-[![](https://img.shields.io/static/v1?label=fastai&message=nbdev&color=57aeac&labelColor=black&style=flat&logo=data:image/png;base64,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)](https://github.com/fastai/nbdev)
-[![](https://img.shields.io/static/v1?label=View%20Demo%20Site&message=link&labelColor=2f363d&color=blue&style=flat&logo=github&logoColor=959da5)](https://fastpages.fast.ai/)
+![](https://github.com/shreya-ahujaa/fastpages/workflows/CI/badge.svg)
+![](https://github.com/shreya-ahujaa/fastpages/workflows/GH-Pages%20Status/badge.svg)
+[![](https://img.shields.io/static/v1?label=fastai&message=fastpages&color=57aeac&labelColor=black&style=flat&logo=data:image/png;base64,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)](https://github.com/fastai/fastpages)
-[//]: # (END OF BADGES SECTION)
+https://shreya-ahujaa.github.io/fastpages/
-# Welcome To `fastpages`
+# My Blog
-> An easy to use blogging platform, with support for Jupyter notebooks, Word docs, and Markdown.
-![](images/diagram.png)
+_powered by [fastpages](https://github.com/fastai/fastpages)_
-`fastpages` uses [GitHub Actions](https://github.com/features/actions) to simplify the process of creating [Jekyll blog posts](https://jekyllrb.com/) on [GitHub Pages](https://pages.github.com/) from a variety of input formats.
-### `fastpages` provides the following features:
+## What To Do Next?
-- Create posts containing code, outputs of code (which can be interactive), formatted text, etc directly from [Jupyter Notebooks](https://jupyter.org/); Notebook posts support features such as:
- - Interactive visualizations made with [Altair](https://altair-viz.github.io/) remain interactive.
- - Hide or show cell input and output.
- - Collapsable code cells that are either open or closed by default.
- - Define the Title, Summary and other metadata via a special markdown cells
- - Ability to add links to [Colab](https://colab.research.google.com/), [Deepnote](https://deepnote.com/) and GitHub automatically.
-- Support for comments, supported natively through GitHub Issues.
-- Built-in search.
-- Support for customizing the styling of your site.
-- Embed Twitter cards and YouTube videos.
-- Categorization of blog posts by user-supplied tags for discoverability.
-- Create and edit [Markdown](https://guides.github.com/features/mastering-markdown/) posts.
-- Create posts, including formatting and images, directly from Microsoft Word documents.
-- Write posts on your local machine and [preview them with live reload](#running-the-blog-on-your-local-machine).
+Great! You have setup your repo. Now its time to start writing content. Some helpful links:
-See below for a more detailed list of features.
+- [Writing Blogs With Jupyter](https://github.com/fastai/fastpages#writing-blog-posts-with-jupyter)
+- [Writing Blogs With Markdown](https://github.com/fastai/fastpages#writing-blog-posts-with-markdown)
-**[See the demo site](https://fastpages.fast.ai/)**
+- [Writing Blog Posts With Word](https://github.com/fastai/fastpages#writing-blog-posts-with-microsoft-word)
----
+- [(Optional) Preview Your Blog Locally](_fastpages_docs/DEVELOPMENT.md)
-
+Note: you may want to remove example blog posts from the `_posts`, `_notebooks` or `_word` folders (but leave them empty, don't delete these folders) if you don't want these blog posts to appear on your site.
-- [Welcome To `fastpages`](#welcome-to-fastpages)
- - [`fastpages` provides the following features:](#fastpages-provides-the-following-features)
- - [Setup Instructions](#setup-instructions)
- - [Customizing Blog Posts With Front Matter](#customizing-blog-posts-with-front-matter)
- - [Configure Title & Summary](#configure-title--summary)
- - [Table of Contents](#table-of-contents)
- - [Colab, Binder, Deepnote and GitHub Badges](#colab-binder-deepnote-and-github-badges)
- - [Categories](#categories)
- - [Enabling Comments](#enabling-comments)
- - [Setting an Image For Social Media](#setting-an-image-for-social-media)
- - [Hiding A Blog Post](#hiding-a-blog-post)
- - [Pinning A Blog Post](#pinning-a-blog-post)
- - [Toggle Search Visibility](#toggle-search-visibility)
- - [Site Wide Configuration Options](#site-wide-configuration-options)
- - [Adjusting Page Width](#adjusting-page-width)
- - [Annotations and Highlighting With hypothes.is](#annotations-and-highlighting-with-hypothesis)
- - [Subscribing with RSS](#subscribing-with-rss)
- - [Syntax Highlighting](#syntax-highlighting)
- - [Dark Mode](#dark-mode)
- - [Adding Citations via BibTeX](#adding-citations-via-bibtex)
- - [Writing Blog Posts With Jupyter](#writing-blog-posts-with-jupyter)
- - [Hide Input/Output Cells](#hide-inputoutput-cells)
- - [Collapsable Code Cells](#collapsable-code-cells)
- - [Embedded Twitter and YouTube Content](#embedded-twitter-and-youtube-content)
- - [Adding Footnotes](#adding-footnotes)
- - [Automatically Convert Notebooks To Blog Posts](#automatically-convert-notebooks-to-blog-posts)
- - [Writing Blog Posts With Markdown](#writing-blog-posts-with-markdown)
- - [Writing Blog Posts With Microsoft Word](#writing-blog-posts-with-microsoft-word)
- - [Specifying front-matter for Word documents](#specifying-front-matter-for-word-documents)
-- [Running the blog on your local machine](#running-the-blog-on-your-local-machine)
-- [Using The GitHub Action & Your Own Custom Blog](#using-the-github-action--your-own-custom-blog)
- - [Optional Inputs](#optional-inputs)
-- [Contributing To Fastpages](#contributing-to-fastpages)
-- [Upgrading Fastpages](#upgrading-fastpages)
-- [FAQ](#faq)
-- [Customizing Fastpages](#customizing-fastpages)
-- [Troubleshooting fastpages](#troubleshooting-fastpages)
-
-
-
-
-## Setup Instructions
-
-1. Generate a copy of this repo by clicking [on this link](https://github.com/fastai/fastpages/generate). Make sure to sign in to your account, or you will see a 404 error. Name your repo anything you like **except** {your-username}.github.io.
-
-2. **GitHub Actions will automatically open a PR** on your new repository ~ 30 seconds after the copy is created. Follow the instructions in that PR to continue.
-
->If you are not seeing a PR, please make sure you have third party actions enabled in your organization: **Settings -> Actions -> Actions Permissions -> Enable local and third party Actions for this repository**
-
-For a live walk-through of the setup steps (with some additional tips) see this [video tutorial of setting up a fastpages blog](https://youtu.be/L0boq3zqazI) by Abdul Majed.
-
-
-3. In some cases because of permissions step 2 may fail to create a Pull Request. If this occurs, go to your repository settings and in the Actions section, grant `Read and Write` permissions and check `Allow GitHub Actions to create and approve pull requests`.
-
-![](2022-05-15-07-21-16.png)
-
-Once you have granted permissions, go to the `Actions` tab at the top of your repository home page, where you will be presented with a list of Actions runs. First click on the failed run (the item with the red X):
-
-![](2022-05-15-07-25-15.png)
-
-You will be taken to a screen where there will be a button on the upper right hand side allowing you to re-run jobs.
-
-![](2022-05-15-07-24-25.png)
-
-After doing this, a pull request should appear.
-
-4. To create your first post, add content in the `_posts`, `_notebooks` or `_word` directories. You can follow examples of content in those folders in this repo of how to structure the content. The most important thing to pay attention to is the front matter, which is discussed in more detail below. Furthermore, you can add additional pages that will appear on your blog's navbar in the `_pages` directory. Note that content in the `_word` directory does not support front matter.
-
-## Customizing Blog Posts With Front Matter
-
-[Front matter](https://jekyllrb.com/docs/front-matter/) allows you to toggle various options on/off for each blog post, as well as pass metadata to various features of fastpages.
-
-In a notebook, front matter is defined as a markdown cell at the beginning of the notebook with the following contents:
-
- ```markdown
- # "Title"
- > "Awesome summary"
-
- - toc: false
- - branch: master
- - badges: true
- - comments: true
- - categories: [fastpages, jupyter]
- - image: images/some_folder/your_image.png
- - hide: false
- - search_exclude: true
- - metadata_key1: metadata_value1
- - metadata_key2: metadata_value2
- ```
-
-Similarly, in a markdown document the same front matter would be defined like this at the beginning of the document:
-
- ```yaml
- ---
- title: "My Title"
- description: "Awesome description"
- layout: post
- toc: false
- comments: true
- image: images/some_folder/your_image.png
- hide: false
- search_exclude: true
- categories: [fastpages, jupyter]
- metadata_key1: metadata_value1
- metadata_key2: metadata_value2
- ---
- ```
-
-Additional metadata is optional and allows you to set custom [front matter](https://jekyllrb.com/docs/front-matter/).
-
-Note that anything defined in front matter must be valid YAML. **Failure to provide valid YAML could result in your page not rendering** in your blog. For example, if you want a colon in your title you must escape it with double quotes like this:
-
-` - title: "Deep learning: A tutorial"`
-
-See this [tutorial on YAML](https://rollout.io/blog/yaml-tutorial-everything-you-need-get-started/) for more information.
-
-### Configure Title & Summary
- - Replace `Title`, with your desired title, and `Awesome summary` with your desired summary.
-
-**Note:** It is recommended to enclose these values in double quotes, so that you can escape colons and other characters that may break the YAML parser.
-
-### Table of Contents
- - `fast_template` will automatically generate a table of contents for you based on [markdown headers](https://guides.github.com/features/mastering-markdown/)! You can toggle this feature on or off by setting `toc:` to either `true` or `false`.
-
-### Colab, Binder, Deepnote and GitHub Badges
-
-This option works for **notebooks only**
-
- - The `branch` field is used to optionally render a link your notebook to Colab and GitHub in your blog post. It'll default to `master` if you don't specify it in the notebook.
- - If you do not want to show Colab / GitHub badges on your blog post (perhaps because your repo is private and the links would be broken) set `badges` to `false`. This defaults to `true`
- - By default, when you omit this parameter from your front matter, or you set `badges: true`, **all four badges (GitHub, Binder, Deepnote, Colab)** will appear by default. You can adjust these defaults in with the `default_badges` parameter in [Site Wide Configuration Options](#site-wide-configuration-options).
- - If only want to hide a badge on an individual post, you can set the front matter `hide_{github,colab,binder,deepnote}_badge: true`. For example, if you wanted to hide the Binder badge for an individual notebook but you want the other badges to show up, you can set this in your front matter:
-
- ```yaml
- - badges: true
- - hide_binder_badge: true
- ```
- - **Note about Binder**: Binder allows you to customize the dependencies and other aspects of the Jupyter Notebook environment for your readers. The easiest way is to add a `requirements.txt` file with common packages you use for all your notebooks at the root of your repository, you can learn more [on the official Binder docs](https://mybinder.readthedocs.io/en/latest/introduction.html).
-
-### Categories
- - You can have a comma seperated list inside square brackets of categories for a blog post, which will make the post visible on the tags page of your blog's site. For example:
-
- In a notebook:
-
- ```
- # "My Title"
- - categories: [fastpages, jupyter]
- ```
-
- In a markdown document:
-
- ```
- ---
- title: "My Title"
- categories: [fastpages, jupyter]
- ---
- ```
-
- You can see a preview of what this looks like [here](https://fastpages.fast.ai/categories/).
-
-
- - You can toggle the display of tags on/off by setting `show_tags` to `true` or `false` in `_config.yml`:
-
-```yaml
-# Set this to true to display tags on each post
-show_tags: true
-```
-
-### Enabling Comments
-
-Commenting on blog posts is powered by [Utterances](https://github.com/utterance/utterances), an open-source and ad-free way of implementing comments. All comments are stored in issues on your blog's GitHub repo. You can turn this on setting `comments` to `true`. This defaults to `false`.
-
-To enable comments with [Utterances](https://github.com/utterance/utterances) you will need to do the following:
-
- - Make sure the repo is public, otherwise your readers will not be able to view the issues/comments.
- - Make sure the [utterances app](https://github.com/apps/utterances) is installed on the repo, otherwise users will not be able to post comments.
- - If your repo is a fork, navigate to it's settings tab and confirm the issues feature is turned on.
-
-### Setting an Image For Social Media
-
-On social media sites like Twitter, an image preview can be automatically shown with your URL. Specifying the front matter `image` provides this metadata to social media sites to render this image for you. You can set this value as follows:
-
-`- image: images/diagram.png`
-
-Note: for this setting **you can only reference image files and folders in the `/images` folder of your repo.**
-
-### Hiding A Blog Post
-
-You may want to prevent a blog post from being listed on the home page, but still have a public url that you can preview or share discreetly. You can hide a blog post from the home page by setting the front matter `hide` to `true`. This is set to `false` by default.
-
-It is recommended that you use [permalinks](https://jekyllrb.com/docs/permalinks/) in order to generate a predictable url for hidden blog posts. You can also set the front matter `search_exclude` to `true` if you don't want users to find your hidden post in a search.
-
-### Pinning A Blog Post
-
-By default, posts are sorted by date on your homepage. However, you may want one or more blog posts to always appear at the very top of your homepage. In other words, you may want certain posts to be "pinned" or "sticky". To accomplish this, specify the `sticky_rank` front matter in the order you would like your sticky posts to appear. Blog posts that do not set this parameter are sorted in the default way by date after the sticky posts.
-
-For example, consider these three markdown posts (also works for notebooks).
-
-`2020-01-01-Post-One.md`
-```yaml
----
-title: Post One
-sticky_rank: 1
----
-```
-
-`2020-02-01-Post-Two.md`
-```yaml
----
-title: Post Two
-sticky_rank: 2
----
-```
-
-`2020-04-01-Post-Three.md`
-```yaml
----
-title: Post Three
----
-```
-
-However, since `sticky_rank` is specified, blog posts will **first be sorted by sticky_rank in ascending order, then by date in descending order**, so the order of these posts will appear like so:
-
-- Post One
-- Post Two
-- Post Three
-
-_Without `sticky_rank` the above posts would actually be sorted in reverse order due to the dates associated with each post._
-
-_Note: pinning also works for notebooks:_
-
-```
-# "My cool blog post"
-> "Description of blog post"
-
-- sticky_rank: 2
-```
-
-### Toggle Search Visibility
-
-fastpages comes with built in keyword search powered by [lunr.js](https://lunrjs.com/). You can prevent a blog post or page from appearing in search results by setting the front matter `search_exclude` to `false`. This is set to `true` by default.
-
-
-## Site Wide Configuration Options
-
-**It is recommended that everyone personalizes their blogging site by setting site-wide configration options**. These options can be found in `/_config.yml`. Below is a description of various options that are available.
-
-- `title`: this is the title that appears on the upper left hand corner on the header of all your pages.
-- `description`: this description will show up in various places when a preview for your site is generated (for example, on social media).
-- `github_username`: this allows your site to display a link to your GitHub page in the footer.
-- `github_repo`: this allows your site to render links back to your repository for various features such as links to GitHub, Colab and Deepnote for notebooks.
-- `url`: This does not need to be changed unless you have a custom domain. **Note: leave out the trailing / from this value.**
-- `baseurl`: See the comments in `/_config.yml` for instructions ( "Special Instructions for baseurl" on setting this value properly. If you do not have a custom domain, then you can likely ignore this option.
-- `email`: this is currently unused. Ignore.
-- `twitter_username`: creates a link in your footer to your twitter page.
-- `use_math`: Set this to `true` to get LaTeX math equation support. This is off by default as it otherwhise loads javascript into each page that may not be used.
-- `show_description`: This shows a description under the title of your blog posts on your homepage that contains a list of your blog posts. Set to `true` by default.
-- `google_analytics`: Optionally use a [Google Analytics](http://www.google.com/analytics/) ID for tracking if desired.
-- `show_image`: If set to true, this uses the `image` parameter in the front matter of your blog posts to render a preview of your blogs as shown below. This is set to `false` by default.
- When show_image is set to `true` your homepage will look like this:
-
- ![home page](/_fastpages_docs/_show_image_true.png)
-
-- `show_tags`: You can toggle the display of tags on your blog posts on or off by setting this value to `false`. This is set to `true` by default, which which renders the following links for tags on your blog posts like this:
-
- ![tags](_fastpages_docs/_post_tags.png)
-
-- `pagination`: This is the maximum number of posts to show on each page of your home page. Any posts exceeding this amount will be paginated onto another page. This is set to `15` by default. When this is triggered, you will see pagination at the bottom of your home page appear like this:
-
- ![paginate](_fastpages_docs/_paginate.png)
-
- Note: if you are using an older version of fastpages, **you cannot use the automated upgrade process** to get pagination. Instead you must follow these steps:
-
- 1. Rename your index.md file to index.html
- > mv index.md index.html
- 2. Replace the `Gemfile` and `Gemfile.lock` in the root of your repo with the files in this repo.
- 3. Edit your `_config.yml` as follows (look at [_config.yml](_config.yml) for an example):
- ```yaml
- gems:
- - jekyll-paginate
-
- paginate: 10
- paginate_path: /page:num/
- ```
-
- _Alternatively, you can copy all of your posts over to a newly created repository created from the fastpages template._
-
-- `default_badges`: By default GitHub, Binder, Deepnote, and Colab badges will show up on notebook blog posts. You can adjust these defaults by setting the appropriate value in `default_badges` to false. For example, if you wanted to turn Binder badges off by default, you would change `default_badges` to this:
-
- ```yaml
- default_badges:
- github: true
- binder: false
- deepnote: false
- colab: true
- ```
-
-- `html_escape`: this allows you to toggle escaping of HTML in various components of blog posts on or off. At this moment, you can only toggle this for the `description` field in your posts.
-This is set to `false` by default.
-
-## Adjusting Page Width
-
-You can adjust the page width of fastpages on various devices by editing [/_sass/minima/custom-variables.scss](_sass/minima/custom-variables.scss).
-
-These are the default values, which can be adjusted to suit your preferences:
-
-```scss
-// width of the content area
-// can be set as "px" or "%"
-$content-width: 1000px;
-$on-palm: 800px;
-$on-laptop: 1000px;
-$on-medium: 1000px;
-$on-large: 1200px;
-```
-
-## Annotations and Highlighting With hypothes.is
-
-[hypothes.is](https://web.hypothes.is/) is an open platform that provides a way to annotate and higlight pages, which can be either public or private. When this feature is enabled, readers of your blog will be presented with the following tooltip when highlighting text:
-
-![annotation](_fastpages_docs/annotate.png)
-
-**This is disabled by default in fastpages.** You can enable or disable this in your [_config.yml](_config.yml) file by setting `annotations` to `true` or `false`:
-
-```yaml
-# Set this to true to turn on annotations with hypothes.is
-annotations: false
-```
-
-> You can customize hypothes.is by reading [these configuration options](http://h.readthedocs.io/projects/client/en/latest/publishers/config/). It is also a good idea to read [these docs](https://web.hypothes.is/for-publishers/#embedding) if you want to do more with hypothes.is. However, before trying to customize this feature you should read the [customizing fastpages](#customizing-fastpages) section for important caveats.
-
-## Subscribing with RSS
-
-You can direct your readers to subscribe with [RSS feeds](https://en.wikipedia.org/wiki/RSS). There are many RSS subscription services available on the internet. Some examples include:
-
-1. [Feedrabbit](https://feedrabbit.com/)
-2. [Blogtrottr](https://blogtrottr.com/)
-
-## Syntax Highlighting
-
-`fastpages` overrides the default syntax highlighting of minima with the [Dracula theme](https://draculatheme.com/).
-
-- The default highlighting in fastpages looks like this:
-
- ![default-highlighting](_fastpages_docs/highlight_dracula.png)
-
-- However, you can make the syntax highlighting to look like this, if you choose:
-
- ![default-highlighting](_fastpages_docs/highlight_original.png)
-
- If you wish to revert to the light theme above, you can remove the below line in [_sass/minima/custom-styles.scss](_sass/minima/custom-styles.scss)
-
- ```scss
- @import "minima/fastpages-dracula-highlight";
- ```
-- If you don't like either of these themes, you can add your own CSS in [`_sass/minima/custom-styles.scss`](_sass/minima/custom-styles.scss). See [customizing fastpages](#customizing-fastpages) for more details.
-
-## Dark Mode
-
-[This blog post](https://prudhvirampey.com/blog/colours/jekyll/css/fastpages/2020/10/30/hello-dark-mode.html) describes how to enable Dark Mode for fastpages.
-
-## Adding Citations via BibTeX
-
-Users who prefer to use the citation system BibTeX may do so; it requires enabling the [jekyll-scholar](https://github.com/inukshuk/jekyll-scholar) plugin. Please see [Citations in Fastpages via BibTeX and jekyll-scholar](https://drscotthawley.github.io/devblog4/2020/07/01/Citations-Via-Bibtex.html) for instructions on implementing this.
-
-## Writing Blog Posts With Jupyter
-
-### Hide Input/Output Cells
-
-Place the comment `#hide` at the beginning of a code cell and it wil **hide both the input and the output** of that cell.
-
-A `#hide_input` comment at the top of any cell will **only hide the input**.
-
-Furthermore, the `hide input` [Jupyter Extension](https://jupyter-contrib-nbextensions.readthedocs.io/en/latest/nbextensions/hide_input/readme.html) can be used to hide cell inputs or outputs, which will be respected by fastpages.
-
-### Collapsable Code Cells
-
-You may want some code to be hidden in a collapsed element that the user can expand, rather than completely hiding the code from the reader.
-
-- To include code in a collapsable cell that **is collapsed by default**, place the comment `#collapse` at the top of the code cell.
-- To include code in a collapsable cell that **is open by default**, place the comment `#collapse_show` or `#collapse-show` at the top of the code cell.
-- To include the output under a collapsable element that is closed by default, place the comment `#collapse_output` or `#collapse-output` at the top of the code cell.
-
-### Embedded Twitter and YouTube Content
-In a markdown cell in your notebook, use the following markdown shortcuts to embed Twitter cards and YouTube Videos.
-
-
- ```markdown
- > youtube: https://youtu.be/your-link
- > twitter: https://twitter.com/some-link
- ```
-### Adding Footnotes
-
-Adding footnotes in notebooks is a bit different than markdown. Please see the [Detailed Guide To Footnotes in Notebooks](https://github.com/fastai/fastpages/blob/master/_fastpages_docs/NOTEBOOK_FOOTNOTES.md).
-
-### Automatically Convert Notebooks To Blog Posts
-
-1. Save your notebook with the naming convention `YYYY-MM-DD-*.` into the `/_notebooks` or `/_word` folder of this repo, respectively. For example `2020-01-28-My-First-Post.ipynb`. This [naming convention is required by Jekyll](https://jekyllrb.com/docs/posts/) to render your blog post.
- - Be careful to name your file correctly! It is easy to forget the last dash in `YYYY-MM-DD-`. Furthermore, the character immediately following the dash should only be an alphabetical letter. Examples of valid filenames are:
-
- ```shell
- 2020-01-28-My-First-Post.ipynb
- 2012-09-12-how-to-write-a-blog.ipynb
- ```
-
- - If you fail to name your file correctly, `fastpages` will automatically attempt to fix the problem by prepending the last modified date of your file to your generated blog post, however, it is recommended that you name your files properly yourself for more transparency.
-
-
-2. [Commit and push](https://help.github.com/en/github/managing-files-in-a-repository/adding-a-file-to-a-repository-using-the-command-line) your file(s) to GitHub in your repository's master branch.
-
-3. GitHub will automatically convert your files to blog posts. **It will take ~5 minutes for the conversion process to take place**. You can click on the Actions tab of your repo to view the logs of this process. There will be two workflows that are triggered with each push you make to your master branch: (1) "CI" and (2) "GH Pages Status". Both workflows must complete with a green checkmark for your latest commit before your site is updated.
-
-4. If you wish, you can preview how your blog will look locally before commiting to GitHub. See [this section](#running-the-blog-on-your-local-machine) for a detailed guide on running the preview locally.
-
-
-## Writing Blog Posts With Markdown
-
-If you are writing your blog post in markdown, save your `.md` file into the `/_posts` folder with the same naming convention (`YYYY-MM-DD-*.md`) specified for notebooks.
-
-## Writing Blog Posts With Microsoft Word
-
-Save your Microsoft Word documents into the `/_word` folder with the same naming convention (`YYYY-MM-DD-*.docx`) specified for notebooks.
-
-_Note:_ [alt text](https://support.office.com/en-us/article/add-alternative-text-to-a-shape-picture-chart-smartart-graphic-or-other-object-44989b2a-903c-4d9a-b742-6a75b451c669) in Word documents are not yet supported by fastpages, and will break links to images.
-
-### Specifying front-matter for Word documents
-
-`fastpages` does not have a robust way to specify [front matter](https://jekyllrb.com/docs/front-matter/) for Word documents. At the moment, you can only specify front matter globally for all Word documents by editing [_action_files/word_front_matter.txt](_action_files/word_front_matter.txt).
-
-To specify unique front matter per Word document, you will need to convert Word to markdown files manually. You can follow the steps in this [blog post](https://www.fast.ai/2020/01/18/gitblog/), which walk you through how to use [pandoc](https://pandoc.org/installing.html) to do the conversion. Note: If you wish to customize your Word generated blog post in markdown, make sure you delete your Word document from the _word directory so your markdown file doesn’t get overwritten!
-
-_If your primary method of writing blog posts is Word documents, and you plan on always manually editing markdown files converted from Word, you are probably better off using [fast_template](https://github.com/fastai/fast_template) instead of fastpages._
-
-# Running the blog on your local machine
-
-See the [development guide](_fastpages_docs/DEVELOPMENT.md).
-
-
-# Using The GitHub Action & Your Own Custom Blog
-
-The `fastpages` action allows you to convert notebooks from `/_notebooks` and word documents from `/_word` directories in your repo into [Jekyll](https://jekyllrb.com/) compliant blog post markdown files located in `/_posts`. **Note: This directory structure is currently inflexible** for this Action, as it is designed to be used with Jekyll.
-
-If you already have sufficient familiarity with [Jekyll](https://jekyllrb.com/) and wish to use this automation in your own theme, you can use this GitHub Action by referencing `fastai/fastpages@master` as follows:
-
-```yaml
-...
-
-uses: fastai/fastpages@master
-
-...
-```
-An illustrative example of what a complete workflow may look like:
-
-
-
-```yaml
-jobs:
- build-site:
- runs-on: ubuntu-latest
- ...
-
- - name: convert notebooks and word docs to posts
- uses: fastai/fastpages@master
-
- ...
-
- - name: Jekyll build
- uses: docker://jekyll/jekyll
- with:
- args: jekyll build
-
- - name: Deploy
- uses: peaceiris/actions-gh-pages@v3
- if: github.event_name == 'push'
- with:
- deploy_key: ${{ secrets.SSH_DEPLOY_KEY }}
- publish_branch: gh-pages
- publish_dir: ./_site
-```
-
-Note that this Action **does not have any required inputs, and has no output variables**.
-
-### Optional Inputs
-
- - `BOOL_SAVE_MARKDOWN`: Either 'true' or 'false'. Whether or not to commit converted markdown files from notebooks and word documents into the _posts directory in your repo. This is useful for debugging. _default: false_
- - `SSH_DEPLOY_KEY`: a ssh deploy key is required if BOOL_SAVE_MARKDOWN = 'true'
-
-See the API spec for this action in [action.yml](action.yml)
-
-Detailed instructions on how to customize this blog are beyond the scope of this README. ( We invite someone from the community to contribute a blog post on how to do this in this repo! )
-
-# Contributing To Fastpages
-
-Please see the [contributing guide](_fastpages_docs/CONTRIBUTING.md).
-
-# Upgrading Fastpages
-
-Please see the [upgrading guide](_fastpages_docs/UPGRADE.md).
-
-# FAQ
-
-- **Q:** Where are the markdown files in `_posts/` that are generated from my Jupyter notebooks or word documents? **A:** The GitHub Actions workflow in this repo converts your notebook and word documents to markdown on the fly before building your site, but never commits these intermediate markdown files to this repo. This is in order to save you from the annoyance of your local environment being constantly out of sync with your repository. You can optionally see these intermediate markdown files by setting the `BOOL_SAVE_MARKDOWN` and `SSH_DEPLOY_KEY` inputs to the fastpages action in your `.github/workflows/ci.yaml` file as follows:
-
-```yaml
- ...
-
- - name: convert notebooks and word docs to posts
- uses: fastai/fastpages@master
- with:
- BOOL_SAVE_MARKDOWN: true
- SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
-
- ...
-```
-
-- **Q:** Can I use `fastpages` for Jekyll docs sites or for things that are not Jekyll blog posts? **A:** At the moment, `fastpages` is a highly opinionated solution that works only for Jekyll blog posts. If you want to write documentation for your module or library with Jupyter notebooks, we suggest you use [fastai/nbdev](https://github.com/fastai/nbdev) which is expressly built for this purpose.
-
-- **Q:** What is the difference between [fast_template](https://github.com/fastai/fast_template) and fastpages? Which one should I use? **A:** Because `fastpages` is more flexible and extensible, we recommend using it where possible. `fast_template` may be a better option for getting folks blogging who have no technical expertise at all, and will only be creating posts using Github's integrated online editor.
-
-# Customizing Fastpages
-
-fastpages builds upon the [minima theme](https://github.com/jekyll/minima). If you want to customize the styling or layout of fastpages, you can find instructions [in minima's README](https://github.com/jekyll/minima/blob/master/README.md). It is a good idea to read the full contents of the README to understand the directory structure. Furthermore, it is a good idea to have a basic understanding of Jekyll before customizing your theme. For those new to Jekyll, [the official docs](https://jekyllrb.com/docs/) are a good place to start. Concretely, you can override css in fastpages in `_sass/minima/custom-styles.scss`. *NOTE that minima's "skins" feature is currently incompatible with fastpages' css settings.*
-
-**If you choose to make customizations to fastpages** It is possible that customizations you make could collide with current or future versions of fastpages and we recommend doing so only if you feel sufficiently comfortable with HTML and CSS.
-
-# Troubleshooting fastpages
-
-Please see the [troubleshooting guide](https://github.com/fastai/fastpages/blob/master/_fastpages_docs/TROUBLESHOOTING.md).
+Please use the [nbdev & blogging channel](https://forums.fast.ai/c/fastai-users/nbdev/48) in the fastai forums for any questions or feature requests.
diff --git a/_action_files/settings.ini b/_action_files/settings.ini
index 415570d..a4c105e 100644
--- a/_action_files/settings.ini
+++ b/_action_files/settings.ini
@@ -7,7 +7,7 @@ description = Writing a library entirely in notebooks
keywords = jupyter notebook
author = Sylvain Gugger and Jeremy Howard
author_email = info@fast.ai
-baseurl =
+baseurl = /fastpages
title = nbdev
copyright = fast.ai
license = apache2
@@ -41,3 +41,4 @@ custom_sidebar = False
cell_spacing = 1
monospace_docstrings = False
jekyll_styles = note,warning,tip,important,youtube,twitter
+
diff --git a/_config.yml b/_config.yml
index dfb5bf9..0e3b588 100644
--- a/_config.yml
+++ b/_config.yml
@@ -8,13 +8,13 @@
title: fastpages
description: An easy to use blogging platform with support for Jupyter Notebooks.
-github_username: fastai
+github_username: shreya-ahujaa
# you can comment the below line out if your repo name is not different than your baseurl
github_repo: "fastpages"
# OPTIONAL: override baseurl and url if using a custom domain
# Note: leave out the trailing / from this value.
-url: "https://fastpages.fast.ai" # the base hostname & protocol for your site, e.g. http://example.com
+url: "https://shreya-ahujaa.github.io" # the base hostname & protocol for your site, e.g. http://example.com
###########################################################
######### Special Instructions for baseurl ###############
@@ -34,7 +34,7 @@ url: "https://fastpages.fast.ai" # the base hostname & protocol for your site, e
#
# 3. You must replace the parameter `baseurl` in _action_files/settings.ini with the same value as you set here but WITHOUT QUOTES.
#
-baseurl: "" # the subpath of your site, e.g. "/blog".
+baseurl: "/fastpages" # the subpath of your site, e.g. "/blog".
# Github and twitter are optional:
minima:
@@ -58,7 +58,7 @@ annotations: false
show_tags: true
# Add your Google Analytics ID here if you have one and want to use it
-google_analytics: UA-57531313-5
+google_analytics:
exclude:
- docker-compose.yml
diff --git a/_fastpages_docs/_setup_pr_template.md b/_fastpages_docs/_setup_pr_template.md
index 7cffc74..8160a5f 100644
--- a/_fastpages_docs/_setup_pr_template.md
+++ b/_fastpages_docs/_setup_pr_template.md
@@ -1,25 +1,25 @@
-Hello :wave: @{_username_}! Thank you for using fastpages!
+Hello :wave: @shreya-ahujaa! Thank you for using fastpages!
## Before you merge this PR
1. Create an ssh key-pair. Open this utility. Select: `RSA` and `4096` and leave `Passphrase` blank. Click the blue button `Generate-SSH-Keys`.
-2. Navigate to this link and click `New repository secret`. Copy and paste the **Private Key** into the `Value` field. This includes the "---BEGIN RSA PRIVATE KEY---" and "--END RSA PRIVATE KEY---" portions. **In the `Name` field, name the secret `SSH_DEPLOY_KEY`.**
+2. Navigate to this link and click `New repository secret`. Copy and paste the **Private Key** into the `Value` field. This includes the "---BEGIN RSA PRIVATE KEY---" and "--END RSA PRIVATE KEY---" portions. **In the `Name` field, name the secret `SSH_DEPLOY_KEY`.**
-3. Navigate to this link and click the `Add deploy key` button. Paste your **Public Key** from step 1 into the `Key` box. In the `Title`, name the key anything you want, for example `fastpages-key`. Finally, **make sure you click the checkbox next to `Allow write access`** (pictured below), and click `Add key` to save the key.
+3. Navigate to this link and click the `Add deploy key` button. Paste your **Public Key** from step 1 into the `Key` box. In the `Title`, name the key anything you want, for example `fastpages-key`. Finally, **make sure you click the checkbox next to `Allow write access`** (pictured below), and click `Add key` to save the key.
![](https://raw.githubusercontent.com/fastai/fastpages/master/_fastpages_docs/_checkbox.png)
### What to Expect After Merging This PR
-- GitHub Actions will build your site, which will take 2-3 minutes to complete. **This will happen anytime you push changes to the master branch of your repository.** You can monitor the logs of this if you like on the [Actions tab of your repo](https://github.com/{_username_}/{_repo_name_}/actions).
+- GitHub Actions will build your site, which will take 2-3 minutes to complete. **This will happen anytime you push changes to the master branch of your repository.** You can monitor the logs of this if you like on the [Actions tab of your repo](https://github.com/shreya-ahujaa/fastpages/actions).
- Your GH-Pages Status badge on your README will eventually appear and be green, indicating your first successful build.
-- You can monitor the status of your site in the GitHub Pages section of your [repository settings](https://github.com/{_username_}/{_repo_name_}/settings).
+- You can monitor the status of your site in the GitHub Pages section of your [repository settings](https://github.com/shreya-ahujaa/fastpages/settings).
If you are not using a custom domain, your website will appear at:
-#### https://{_username_}.github.io/{_repo_name_}
+#### https://shreya-ahujaa.github.io/fastpages
## Optional: Using a Custom Domain
diff --git a/_notebooks/2020-02-21-introducing-fastpages.ipynb b/_notebooks/2020-02-21-introducing-fastpages.ipynb
deleted file mode 100644
index 71823b1..0000000
--- a/_notebooks/2020-02-21-introducing-fastpages.ipynb
+++ /dev/null
@@ -1,573 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Introducing fastpages\n",
- "> An easy to use blogging platform with extra features for Jupyter Notebooks.\n",
- "\n",
- "- toc: true \n",
- "- badges: true\n",
- "- comments: true\n",
- "- sticky_rank: 1\n",
- "- author: Jeremy Howard & Hamel Husain\n",
- "- image: images/diagram.png\n",
- "- categories: [fastpages, jupyter]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "![](https://github.com/fastai/fastpages/raw/master/images/diagram.png \"https://github.com/fastai/fastpages\")\n",
- "\n",
- "We are very pleased to announce the immediate availability of [fastpages](https://github.com/fastai/fastpages). `fastpages` is a platform which allows you to create and host a blog for free, with no ads and many useful features, such as:\n",
- "\n",
- "- Create posts containing code, outputs of code (which can be interactive), formatted text, etc directly from [Jupyter Notebooks](https://jupyter.org/); for instance see this great [example post](https://drscotthawley.github.io/devblog3/2019/02/08/My-1st-NN-Part-3-Multi-Layer-and-Backprop.html) from Scott Hawley. Notebook posts support features such as:\n",
- " - Interactive visualizations made with [Altair](https://altair-viz.github.io/) remain interactive.\n",
- " - Hide or show cell input and output.\n",
- " - Collapsable code cells that are either open or closed by default.\n",
- " - Define the Title, Summary and other metadata via a special markdown cells\n",
- " - Ability to add links to [Colab](https://colab.research.google.com/) and GitHub automatically.\n",
- "- Create posts, including formatting and images, directly from Microsoft Word documents.\n",
- "- Create and edit [Markdown](https://guides.github.com/features/mastering-markdown/) posts entirely online using GitHub's built-in markdown editor.\n",
- "- Embed Twitter cards and YouTube videos.\n",
- "- Categorization of blog posts by user-supplied tags for discoverability.\n",
- "- ... and [much more](https://github.com/fastai/fastpages)\n",
- "\n",
- "[fastpages](https://github.com/fastai/fastpages) relies on Github pages for hosting, and [Github Actions](https://github.com/features/actions) to automate the creation of your blog. The setup takes around three minutes, and does not require any technical knowledge or expertise. Due to built-in automation of fastpages, you don't have to fuss with conversion scripts. All you have to do is save your Jupyter notebook, Word document or markdown file into a specified directory and the rest happens automatically. Infact, this blog post is written in a Jupyter notebook, which you can see with the \"View on GitHub\" link above.\n",
- "\n",
- "[fast.ai](https://www.fast.ai/) have previously released a similar project called [fast_template](https://www.fast.ai/2020/01/16/fast_template/), which is even easier to set up, but does not support automatic creation of posts from Microsoft Word or Jupyter notebooks, including many of the features outlined above.\n",
- "\n",
- "**Because `fastpages` is more flexible and extensible, we recommend using it where possible.** `fast_template` may be a better option for getting folks blogging who have no technical expertise at all, and will only be creating posts using Github's integrated online editor."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Setting Up Fastpages\n",
- "\n",
- "[The setup process](https://github.com/fastai/fastpages#setup-instructions) of fastpages is automated with GitHub Actions, too! Upon creating a repo from the fastpages template, a pull request will automatically be opened (after ~ 30 seconds) configuring your blog so it can start working. The automated pull request will greet you with instructions like this:\n",
- "\n",
- "![Imgur](https://i.imgur.com/JhkIip8.png)\n"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "All you have to do is follow these instructions (in the PR you receive) and your new blogging site will be up and running!"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Jupyter Notebooks & Fastpages\n",
- "\n",
- "In this post, we will cover special features that fastpages provides for Jupyter notebooks. You can also write your blog posts with Word documents or markdown in fastpages, which contain many, but not all the same features. "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Options via FrontMatter\n",
- "\n",
- "The first cell in your Jupyter Notebook or markdown blog post contains front matter. Front matter is metadata that can turn on/off options in your Notebook. It is formatted like this:\n",
- "\n",
- "```\n",
- "# Title\n",
- "> Awesome summary\n",
- "\n",
- "- toc: true\n",
- "- branch: master\n",
- "- badges: true\n",
- "- comments: true\n",
- "- author: Hamel Husain & Jeremy Howard\n",
- "- categories: [fastpages, jupyter]\n",
- "```\n",
- "\n",
- "**All of the above settings are enabled in this post, so you can see what they look like!**\n",
- "\n",
- "- the summary field (preceeded by `>`) will be displayed under your title, and will also be used by social media to display as the description of your page.\n",
- "- `toc`: setting this to `true` will automatically generate a table of contents\n",
- "- `badges`: setting this to `true` will display Google Colab and GitHub links on your blog post.\n",
- "- `comments`: setting this to `true` will enable comments. See [these instructions](https://github.com/fastai/fastpages#enabling-comments) for more details.\n",
- "- `author` this will display the authors names. \n",
- "- `categories` will allow your post to be categorized on a \"Tags\" page, where readers can browse your post by categories.\n",
- "\n",
- "\n",
- "_Markdown front matter is formatted similarly to notebooks. The differences between the two can be [viewed on the fastpages README](https://github.com/fastai/fastpages#front-matter-related-options)._"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Code Folding"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "put a `#collapse-hide` flag at the top of any cell if you want to **hide** that cell by default, but give the reader the option to show it:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "#hide\n",
- "!pip install pandas altair"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "#collapse-hide\n",
- "import pandas as pd\n",
- "import altair as alt"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "put a `#collapse-show` flag at the top of any cell if you want to **show** that cell by default, but give the reader the option to hide it:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "#collapse-show\n",
- "cars = 'https://vega.github.io/vega-datasets/data/cars.json'\n",
- "movies = 'https://vega.github.io/vega-datasets/data/movies.json'\n",
- "sp500 = 'https://vega.github.io/vega-datasets/data/sp500.csv'\n",
- "stocks = 'https://vega.github.io/vega-datasets/data/stocks.csv'\n",
- "flights = 'https://vega.github.io/vega-datasets/data/flights-5k.json'"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If you want to completely hide cells (not just collapse them), [read these instructions](https://github.com/fastai/fastpages#hide-inputoutput-cells)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "# hide\n",
- "df = pd.read_json(movies) # load movies data\n",
- "df.columns = [x.replace(' ', '_') for x in df.columns.values]\n",
- "genres = df['Major_Genre'].unique() # get unique field values\n",
- "genres = list(filter(lambda d: d is not None, genres)) # filter out None values\n",
- "genres.sort() # sort alphabetically"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Interactive Charts With Altair\n",
- "\n",
- "Interactive visualizations made with [Altair](https://altair-viz.github.io/) remain interactive! \n",
- "\n",
- "We leave this below cell unhidden so you can enjoy a preview of syntax highlighting in fastpages, which uses the [Dracula theme](https://draculatheme.com/)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "
\n",
- ""
- ],
- "text/plain": [
- "alt.LayerChart(...)"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# select a point for which to provide details-on-demand\n",
- "label = alt.selection_single(\n",
- " encodings=['x'], # limit selection to x-axis value\n",
- " on='mouseover', # select on mouseover events\n",
- " nearest=True, # select data point nearest the cursor\n",
- " empty='none' # empty selection includes no data points\n",
- ")\n",
- "\n",
- "# define our base line chart of stock prices\n",
- "base = alt.Chart().mark_line().encode(\n",
- " alt.X('date:T'),\n",
- " alt.Y('price:Q', scale=alt.Scale(type='log')),\n",
- " alt.Color('symbol:N')\n",
- ")\n",
- "\n",
- "alt.layer(\n",
- " base, # base line chart\n",
- " \n",
- " # add a rule mark to serve as a guide line\n",
- " alt.Chart().mark_rule(color='#aaa').encode(\n",
- " x='date:T'\n",
- " ).transform_filter(label),\n",
- " \n",
- " # add circle marks for selected time points, hide unselected points\n",
- " base.mark_circle().encode(\n",
- " opacity=alt.condition(label, alt.value(1), alt.value(0))\n",
- " ).add_selection(label),\n",
- "\n",
- " # add white stroked text to provide a legible background for labels\n",
- " base.mark_text(align='left', dx=5, dy=-5, stroke='white', strokeWidth=2).encode(\n",
- " text='price:Q'\n",
- " ).transform_filter(label),\n",
- "\n",
- " # add text labels for stock prices\n",
- " base.mark_text(align='left', dx=5, dy=-5).encode(\n",
- " text='price:Q'\n",
- " ).transform_filter(label),\n",
- " \n",
- " data=stocks\n",
- ").properties(\n",
- " width=500,\n",
- " height=400\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Data Tables\n",
- "\n",
- "You can display tables per the usual way in your blog:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "scrolled": true
- },
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " Title | \n",
- " Worldwide_Gross | \n",
- " Production_Budget | \n",
- " IMDB_Rating | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " 0 | \n",
- " The Land Girls | \n",
- " 146083.0 | \n",
- " 8000000.0 | \n",
- " 6.1 | \n",
- "
\n",
- " \n",
- " 1 | \n",
- " First Love, Last Rites | \n",
- " 10876.0 | \n",
- " 300000.0 | \n",
- " 6.9 | \n",
- "
\n",
- " \n",
- " 2 | \n",
- " I Married a Strange Person | \n",
- " 203134.0 | \n",
- " 250000.0 | \n",
- " 6.8 | \n",
- "
\n",
- " \n",
- " 3 | \n",
- " Let's Talk About Sex | \n",
- " 373615.0 | \n",
- " 300000.0 | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " 4 | \n",
- " Slam | \n",
- " 1087521.0 | \n",
- " 1000000.0 | \n",
- " 3.4 | \n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " Title Worldwide_Gross Production_Budget IMDB_Rating\n",
- "0 The Land Girls 146083.0 8000000.0 6.1\n",
- "1 First Love, Last Rites 10876.0 300000.0 6.9\n",
- "2 I Married a Strange Person 203134.0 250000.0 6.8\n",
- "3 Let's Talk About Sex 373615.0 300000.0 NaN\n",
- "4 Slam 1087521.0 1000000.0 3.4"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# display table with pandas\n",
- "df[['Title', 'Worldwide_Gross', \n",
- " 'Production_Budget', 'IMDB_Rating']].head()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Other Features"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### GitHub Flavored Emojis\n",
- "\n",
- "Typing `I give this post two :+1:!` will render this:\n",
- "\n",
- "I give this post two :+1:!"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Images w/Captions\n",
- "\n",
- "You can include markdown images with captions like this:\n",
- "\n",
- "```\n",
- "![](https://www.fast.ai/images/fastai_paper/show_batch.png \"Credit: https://www.fast.ai/2020/02/13/fastai-A-Layered-API-for-Deep-Learning/\")\n",
- "```\n",
- "\n",
- "\n",
- "![](https://www.fast.ai/images/fastai_paper/show_batch.png \"Credit: https://www.fast.ai/2020/02/13/fastai-A-Layered-API-for-Deep-Learning/\")\n",
- "\n",
- "Of course, the caption is optional."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Tweetcards\n",
- "\n",
- "Typing `> twitter: https://twitter.com/jakevdp/status/1204765621767901185?s=20` will render this:\n",
- "\n",
- "> twitter: https://twitter.com/jakevdp/status/1204765621767901185?s=20"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Youtube Videos\n",
- "\n",
- "Typing `> youtube: https://youtu.be/XfoYk_Z5AkI` will render this:\n",
- "\n",
- "\n",
- "> youtube: https://youtu.be/XfoYk_Z5AkI"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Boxes / Callouts \n",
- "\n",
- "Typing `> Warning: There will be no second warning!` will render this:\n",
- "\n",
- "\n",
- "> Warning: There will be no second warning!\n",
- "\n",
- "\n",
- "\n",
- "Typing `> Important: Pay attention! It's important.` will render this:\n",
- "\n",
- "> Important: Pay attention! It's important.\n",
- "\n",
- "\n",
- "\n",
- "Typing `> Tip: This is my tip.` will render this:\n",
- "\n",
- "> Tip: This is my tip.\n",
- "\n",
- "\n",
- "\n",
- "Typing `> Note: Take note of this.` will render this:\n",
- "\n",
- "> Note: Take note of this.\n",
- "\n",
- "\n",
- "\n",
- "Typing `> Note: A doc link to [an example website: fast.ai](https://www.fast.ai/) should also work fine.` will render in the docs:\n",
- "\n",
- "> Note: A doc link to [an example website: fast.ai](https://www.fast.ai/) should also work fine."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## More Examples\n",
- "\n",
- "This [tutorial](https://fastpages.fast.ai/jupyter/2020/02/20/test.html) contains more examples of what you can do with notebooks. "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## How fastpages Converts Notebooks to Blog Posts"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "fastpages uses [nbdev](https://nbdev.fast.ai/index.html) to power the conversion process of Jupyter Notebooks to blog posts. When you save a notebook into the `/_notebooks` folder of your repository, GitHub Actions applies `nbdev` against those notebooks automatically. The same process occurs when you save Word documents or markdown files into the `_word` or `_posts` directory, respectively.\n",
- "\n",
- "We will discuss how GitHub Actions work in a follow up blog post."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Resources & Next Steps"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We highly encourage you to start blogging with `fastpages`! Some resources that may be helpful:\n",
- "\n",
- "- [fastpages repo](https://github.com/fastai/fastpages) - this is where you can go to create your own fastpages blog!\n",
- "- Fastai forums - [nbdev & blogging category](https://forums.fast.ai/c/fastai-users/nbdev/). You can ask questions about fastpages here, as well as suggest new features.\n",
- "- [nbdev](https://github.com/fastai/nbdev): this project powers the conversion of Jupyter notebooks to blog posts.\n",
- "\n",
- "If you end up writing a blog post using fastpages, please let us know on Twitter: [@jeremyphoward](https://twitter.com/jeremyphoward), [@HamelHusain](https://twitter.com/hamelhusain)."
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.3"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/_notebooks/2020-09-01-fastcore.ipynb b/_notebooks/2020-09-01-fastcore.ipynb
deleted file mode 100755
index 06d246b..0000000
--- a/_notebooks/2020-09-01-fastcore.ipynb
+++ /dev/null
@@ -1,1366 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# \"fastcore: An Underrated Python Library\"\n",
- "\n",
- "> A unique python library that extends the python programming language and provides utilities that enhance productivity.\n",
- "- author: \"Hamel Husain\"\n",
- "- toc: false\n",
- "- image: images/copied_from_nb/fastcore_imgs/td.png\n",
- "- comments: true\n",
- "- categories: [fastcore, fastai]\n",
- "- permalink: /fastcore/\n",
- "- badges: true"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "![screenshot with code](fastcore_imgs/td.png)\n",
- "\n",
- "# Background\n",
- "\n",
- "I recently embarked on a journey to sharpen my python skills: I wanted to learn advanced patterns, idioms, and techniques. I started with reading books on advanced Python, however, the information didn't seem to stick without having somewhere to apply it. I also wanted the ability to ask questions from an expert while I was learning -- which is an arrangement that is hard to find! That's when it occurred to me: What if I could find an open source project that has fairly advanced python code and write documentation and tests? I made a bet that if I did this it would force me to learn everything very deeply, and the maintainers would be appreciative of my work and be willing to answer my questions. \n",
- "\n",
- "And that's exactly what I did over the past month! I'm pleased to report that it has been the most efficient learning experience I've ever experienced. I've discovered that writing documentation forced me to deeply understand not just what the code does but also _why the code works the way it does_, and to explore edge cases while writing tests. Most importantly, I was able to ask questions when I was stuck, and maintainers were willing to devote extra time knowing that their mentorship was in service of making their code more accessible! It turns out the library I choose, [fastcore](https://fastcore.fast.ai/) is some of the most fascinating Python I have ever encountered as its purpose and goals are fairly unique.\n",
- "\n",
- "For the uninitiated, [fastcore](https://fastcore.fast.ai/) is a library on top of which many [fast.ai](https://github.com/fastai) projects are built on. Most importantly, [fastcore](https://fastcore.fast.ai/) extends the python programming language and strives to eliminate boilerplate and add useful functionality for common tasks. In this blog post, I'm going to highlight some of my favorite tools that fastcore provides, rather than sharing what I learned about python. My goal is to pique your interest in this library, and hopefully motivate you to check out the documentation after you are done to learn more!\n",
- "\n",
- "# Why fastcore is interesting\n",
- "\n",
- "1. **Get exposed to ideas from other languages without leaving python:** I’ve always heard that it is beneficial to learn other languages in order to become a better programmer. From a pragmatic point of view, I’ve found it difficult to learn other languages because I could never use them at work. Fastcore extends python to include patterns found in languages as diverse as Julia, Ruby and Haskell. Now that I understand these tools I am motivated to learn other languages.\n",
- "2. **You get a new set of pragmatic tools**: fastcore includes utilities that will allow you to write more concise expressive code, and perhaps solve new problems.\n",
- "3. **Learn more about the Python programming language:** Because fastcore extends the python programming language, many advanced concepts are exposed during the process. For the motivated, this is a great way to see how many of the internals of python work. \n",
- " \n",
- "\n",
- "# A whirlwind tour through fastcore\n",
- "\n",
- "Here are some things you can do with fastcore that immediately caught my attention."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Collecting git+git://github.com/fastai/fastcore@master\n",
- " Cloning git://github.com/fastai/fastcore (to revision master) to /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-req-build-fph52w2h\n",
- " Running command git clone -q git://github.com/fastai/fastcore /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-req-build-fph52w2h\n",
- "Requirement already satisfied, skipping upgrade: pip in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from fastcore==1.0.12) (20.1.1)\n",
- "Requirement already satisfied, skipping upgrade: packaging in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from fastcore==1.0.12) (20.4)\n",
- "Requirement already satisfied, skipping upgrade: six in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from packaging->fastcore==1.0.12) (1.15.0)\n",
- "Requirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from packaging->fastcore==1.0.12) (2.4.7)\n",
- "Building wheels for collected packages: fastcore\n",
- " Building wheel for fastcore (setup.py) ... \u001b[?25ldone\n",
- "\u001b[?25h Created wheel for fastcore: filename=fastcore-1.0.12-py3-none-any.whl size=40633 sha256=8275b4eaa351c9c867e9c1f83105bc6ec25f251caf1efcf247a8e9ecc0f16f76\n",
- " Stored in directory: /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-ephem-wheel-cache-x8fbj38b/wheels/9b/c8/80/1e03649fe9e96f2b8231a1f38d4e20389036c7cb204afd8563\n",
- "Successfully built fastcore\n",
- "Installing collected packages: fastcore\n",
- " Attempting uninstall: fastcore\n",
- " Found existing installation: fastcore 1.0.12\n",
- " Uninstalling fastcore-1.0.12:\n",
- " Successfully uninstalled fastcore-1.0.12\n",
- "Successfully installed fastcore-1.0.12\n",
- "Collecting git+git://github.com/fastai/nbdev@master\n",
- " Cloning git://github.com/fastai/nbdev (to revision master) to /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-req-build-whf785xv\n",
- " Running command git clone -q git://github.com/fastai/nbdev /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-req-build-whf785xv\n",
- "Requirement already satisfied, skipping upgrade: pip in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (20.1.1)\n",
- "Requirement already satisfied, skipping upgrade: packaging in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (20.4)\n",
- "Requirement already satisfied, skipping upgrade: fastcore>=1.0.10 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (1.0.12)\n",
- "Requirement already satisfied, skipping upgrade: nbformat>=4.4.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (5.0.7)\n",
- "Requirement already satisfied, skipping upgrade: nbconvert<6 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (5.6.1)\n",
- "Requirement already satisfied, skipping upgrade: pyyaml in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (5.3.1)\n",
- "Requirement already satisfied, skipping upgrade: jupyter_client in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (6.1.6)\n",
- "Requirement already satisfied, skipping upgrade: ipykernel in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbdev==1.0.19) (5.3.2)\n",
- "Requirement already satisfied, skipping upgrade: six in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from packaging->nbdev==1.0.19) (1.15.0)\n",
- "Requirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from packaging->nbdev==1.0.19) (2.4.7)\n",
- "Requirement already satisfied, skipping upgrade: ipython-genutils in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbformat>=4.4.0->nbdev==1.0.19) (0.2.0)\n",
- "Requirement already satisfied, skipping upgrade: jsonschema!=2.5.0,>=2.4 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbformat>=4.4.0->nbdev==1.0.19) (3.0.2)\n",
- "Requirement already satisfied, skipping upgrade: traitlets>=4.1 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbformat>=4.4.0->nbdev==1.0.19) (4.3.3)\n",
- "Requirement already satisfied, skipping upgrade: jupyter-core in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbformat>=4.4.0->nbdev==1.0.19) (4.6.3)\n",
- "Requirement already satisfied, skipping upgrade: pandocfilters>=1.4.1 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (1.4.2)\n",
- "Requirement already satisfied, skipping upgrade: entrypoints>=0.2.2 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (0.3)\n",
- "Requirement already satisfied, skipping upgrade: bleach in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (3.1.5)\n",
- "Requirement already satisfied, skipping upgrade: testpath in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (0.4.4)\n",
- "Requirement already satisfied, skipping upgrade: defusedxml in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (0.6.0)\n",
- "Requirement already satisfied, skipping upgrade: jinja2>=2.4 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (2.11.2)\n",
- "Requirement already satisfied, skipping upgrade: mistune<2,>=0.8.1 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (0.8.4)\n",
- "Requirement already satisfied, skipping upgrade: pygments in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from nbconvert<6->nbdev==1.0.19) (2.6.1)\n",
- "Requirement already satisfied, skipping upgrade: tornado>=4.1 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jupyter_client->nbdev==1.0.19) (6.0.4)\n",
- "Requirement already satisfied, skipping upgrade: python-dateutil>=2.1 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jupyter_client->nbdev==1.0.19) (2.8.1)\n",
- "Requirement already satisfied, skipping upgrade: pyzmq>=13 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jupyter_client->nbdev==1.0.19) (19.0.1)\n",
- "Requirement already satisfied, skipping upgrade: appnope; platform_system == \"Darwin\" in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipykernel->nbdev==1.0.19) (0.1.0)\n",
- "Requirement already satisfied, skipping upgrade: ipython>=5.0.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipykernel->nbdev==1.0.19) (7.16.1)\n",
- "Requirement already satisfied, skipping upgrade: setuptools in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.4.0->nbdev==1.0.19) (49.2.0.post20200714)\n",
- "Requirement already satisfied, skipping upgrade: attrs>=17.4.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.4.0->nbdev==1.0.19) (19.3.0)\n",
- "Requirement already satisfied, skipping upgrade: pyrsistent>=0.14.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.4.0->nbdev==1.0.19) (0.16.0)\n",
- "Requirement already satisfied, skipping upgrade: decorator in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from traitlets>=4.1->nbformat>=4.4.0->nbdev==1.0.19) (4.4.2)\n",
- "Requirement already satisfied, skipping upgrade: webencodings in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from bleach->nbconvert<6->nbdev==1.0.19) (0.5.1)\n",
- "Requirement already satisfied, skipping upgrade: MarkupSafe>=0.23 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jinja2>=2.4->nbconvert<6->nbdev==1.0.19) (1.1.1)\n",
- "Requirement already satisfied, skipping upgrade: backcall in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.2.0)\n",
- "Requirement already satisfied, skipping upgrade: jedi>=0.10 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.17.1)\n",
- "Requirement already satisfied, skipping upgrade: pickleshare in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.7.5)\n",
- "Requirement already satisfied, skipping upgrade: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipython>=5.0.0->ipykernel->nbdev==1.0.19) (3.0.5)\n",
- "Requirement already satisfied, skipping upgrade: pexpect; sys_platform != \"win32\" in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from ipython>=5.0.0->ipykernel->nbdev==1.0.19) (4.8.0)\n",
- "Requirement already satisfied, skipping upgrade: parso<0.8.0,>=0.7.0 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from jedi>=0.10->ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.7.0)\n",
- "Requirement already satisfied, skipping upgrade: wcwidth in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.2.5)\n",
- "Requirement already satisfied, skipping upgrade: ptyprocess>=0.5 in /Users/hamelsmu/anaconda3/lib/python3.8/site-packages (from pexpect; sys_platform != \"win32\"->ipython>=5.0.0->ipykernel->nbdev==1.0.19) (0.6.0)\n",
- "Building wheels for collected packages: nbdev\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " Building wheel for nbdev (setup.py) ... \u001b[?25ldone\n",
- "\u001b[?25h Created wheel for nbdev: filename=nbdev-1.0.19-py3-none-any.whl size=51832 sha256=69a997325e38de84de9410724f59a24deeab6514bc4bea80bdfc90d12acfcff8\n",
- " Stored in directory: /private/var/folders/88/9mddczp92wg04x0ykmw940q00000gn/T/pip-ephem-wheel-cache-r2gv8q50/wheels/28/83/ee/f8ff336622886142e3bc00cfc9ba627f277f30f2ad3d7030f0\n",
- "Successfully built nbdev\n",
- "Installing collected packages: nbdev\n",
- " Attempting uninstall: nbdev\n",
- " Found existing installation: nbdev 1.0.19\n",
- " Uninstalling nbdev-1.0.19:\n",
- " Successfully uninstalled nbdev-1.0.19\n",
- "Successfully installed nbdev-1.0.19\n",
- "Collecting numpy\n",
- " Downloading numpy-1.19.2-cp38-cp38-macosx_10_9_x86_64.whl (15.3 MB)\n",
- "\u001b[K |████████████████████████████████| 15.3 MB 4.7 MB/s eta 0:00:01\n",
- "\u001b[?25hInstalling collected packages: numpy\n",
- " Attempting uninstall: numpy\n",
- " Found existing installation: numpy 1.18.5\n",
- " Uninstalling numpy-1.18.5:\n",
- " Successfully uninstalled numpy-1.18.5\n",
- "Successfully installed numpy-1.19.2\n"
- ]
- }
- ],
- "source": [
- "#hide\n",
- "! pip install -U git+git://github.com/fastai/fastcore@master\n",
- "! pip install -U git+git://github.com/fastai/nbdev@master\n",
- "! pip install -U numpy\n",
- "from fastcore.foundation import *\n",
- "from fastcore.meta import *\n",
- "from fastcore.utils import *\n",
- "from fastcore.test import *\n",
- "from nbdev.showdoc import *\n",
- "from fastcore.dispatch import typedispatch\n",
- "from functools import partial\n",
- "import numpy as np\n",
- "import inspect"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## Making **kwargs transparent\n",
- "\n",
- "Whenever I see a function that has the argument **kwargs, I cringe a little. This is because it means the API is obfuscated and I have to read the source code to figure out what valid parameters might be. Consider the below example:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "def baz(a, b=2, c=3, d=4): return a + b + c\n",
- "\n",
- "def foo(c, a, **kwargs):\n",
- " return c + baz(a, **kwargs)\n",
- "\n",
- "inspect.signature(foo)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Without reading the source code, it might be hard for me to know that `foo` also accepts and additional parameters `b` and `d`. We can fix this with [`delegates`](https://fastcore.fast.ai/foundation.html#delegates):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "def baz(a, b=2, c=3, d=4): return a + b + c\n",
- "\n",
- "@delegates(baz) # this decorator will pass down keyword arguments from baz\n",
- "def foo(c, a, **kwargs):\n",
- " return c + baz(a, **kwargs)\n",
- "\n",
- "inspect.signature(foo)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can customize the behavior of this decorator. For example, you can have your cake and eat it too by passing down your arguments and also keeping `**kwargs`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "@delegates(baz, keep=True)\n",
- "def foo(c, a, **kwargs):\n",
- " return c + baz(a, **kwargs)\n",
- "\n",
- "inspect.signature(foo)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can also exclude arguments. For example, we exclude argument `d` from delegation:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "def basefoo(a, b=2, c=3, d=4): pass\n",
- "\n",
- "@delegates(basefoo, but=['d']) # exclude `d`\n",
- "def foo(c, a, **kwargs): pass\n",
- "\n",
- "inspect.signature(foo)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can also delegate between classes:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "class BaseFoo:\n",
- " def __init__(self, e, c=2): pass\n",
- "\n",
- "@delegates()# since no argument was passsed here we delegate to the superclass\n",
- "class Foo(BaseFoo):\n",
- " def __init__(self, a, b=1, **kwargs): super().__init__(**kwargs)\n",
- " \n",
- "inspect.signature(Foo)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For more information, read the [docs on delegates](https://fastcore.fast.ai/foundation.html#delegates).\n",
- "\n",
- "___"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Avoid boilerplate when setting instance attributes\n",
- "\n",
- "Have you ever wondered if it was possible to avoid the boilerplate involved with setting attributes in `__init__`?"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "class Test:\n",
- " def __init__(self, a, b ,c): \n",
- " self.a, self.b, self.c = a, b, c"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Ouch! That was painful. Look at all the repeated variable names. Do I really have to repeat myself like this when defining a class? Not Anymore! Checkout [store_attr](https://fastcore.fast.ai/basics.html#store_attr):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "class Test:\n",
- " def __init__(self, a, b, c): \n",
- " store_attr()\n",
- " \n",
- "t = Test(5,4,3)\n",
- "assert t.b == 4"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can also exclude certain attributes:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "class Test:\n",
- " def __init__(self, a, b, c): \n",
- " store_attr(but=['c'])\n",
- " \n",
- "t = Test(5,4,3)\n",
- "assert t.b == 4\n",
- "assert not hasattr(t, 'c')"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "There are many more ways of customizing and using `store_attr` than I highlighted here. Check out [the docs](https://fastcore.fast.ai/basics.html#store_attr) for more detail.\n",
- "\n",
- "P.S. you might be thinking that Python [dataclasses](https://docs.python.org/3/library/dataclasses.html) also allow you to avoid this boilerplate. While true in some cases, `store_attr` is more flexible.{% fn 1 %}\n",
- "\n",
- "{{ \"For example, store_attr does not rely on inheritance, which means you won't get stuck using multiple inheritance when using this with your own classes. Also, unlike dataclasses, store_attr does not require python 3.7 or higher. Furthermore, you can use store_attr anytime in the object lifecycle, and in any location in your class to customize the behavior of how and when variables are stored.\" | fndetail: 1 }}"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Avoiding subclassing boilerplate\n",
- "\n",
- "One thing I hate about python is the `__super__().__init__()` boilerplate associated with subclassing. For example:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "class ParentClass:\n",
- " def __init__(self): self.some_attr = 'hello'\n",
- " \n",
- "class ChildClass(ParentClass):\n",
- " def __init__(self):\n",
- " super().__init__()\n",
- "\n",
- "cc = ChildClass()\n",
- "assert cc.some_attr == 'hello' # only accessible b/c you used super"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can avoid this boilerplate by using the metaclass [PrePostInitMeta](https://fastcore.fast.ai/foundation.html#PrePostInitMeta). We define a new class called `NewParent` that is a wrapper around the `ParentClass`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "class NewParent(ParentClass, metaclass=PrePostInitMeta):\n",
- " def __pre_init__(self, *args, **kwargs): super().__init__()\n",
- "\n",
- "class ChildClass(NewParent):\n",
- " def __init__(self):pass\n",
- " \n",
- "sc = ChildClass()\n",
- "assert sc.some_attr == 'hello' "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## Type Dispatch\n",
- "\n",
- "Type dispatch, or [Multiple dispatch](https://en.wikipedia.org/wiki/Multiple_dispatch#Julia), allows you to change the way a function behaves based upon the input types it receives. This is a prominent feature in some programming languages like Julia. For example, this is a [conceptual example](https://en.wikipedia.org/wiki/Multiple_dispatch#Julia) of how multiple dispatch works in Julia, returning different values depending on the input types of x and y:\n",
- "\n",
- "```julia\n",
- "collide_with(x::Asteroid, y::Asteroid) = ... \n",
- "# deal with asteroid hitting asteroid\n",
- "\n",
- "collide_with(x::Asteroid, y::Spaceship) = ... \n",
- "# deal with asteroid hitting spaceship\n",
- "\n",
- "collide_with(x::Spaceship, y::Asteroid) = ... \n",
- "# deal with spaceship hitting asteroid\n",
- "\n",
- "collide_with(x::Spaceship, y::Spaceship) = ... \n",
- "# deal with spaceship hitting spaceship\n",
- "```\n",
- "\n",
- "Type dispatch can be especially useful in data science, where you might allow different input types (i.e. Numpy arrays and Pandas dataframes) to a function that processes data. Type dispatch allows you to have a common API for functions that do similar tasks.\n",
- "\n",
- "Unfortunately, Python does not support this out-of-the box. Fortunately, there is the [@typedispatch](https://fastcore.fast.ai/dispatch.html#typedispatch-Decorator) decorator to the rescue. This decorator relies upon type hints in order to route inputs the correct version of the function:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [],
- "source": [
- "@typedispatch\n",
- "def f(x:str, y:str): return f'{x}{y}'\n",
- "\n",
- "@typedispatch\n",
- "def f(x:np.ndarray): return x.sum()\n",
- "\n",
- "@typedispatch\n",
- "def f(x:int, y:int): return x+y"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Below is a demonstration of type dispatch at work for the function `f`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'Hello World!'"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "f('Hello ', 'World!')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "5"
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "f(2,3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "20"
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "f(np.array([5,5,5,5]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "There are limitations of this feature, as well as other ways of using this functionality that [you can read about here](https://fastcore.fast.ai/dispatch.html). In the process of learning about typed dispatch, I also found a python library called [multipledispatch](https://github.com/mrocklin/multipledispatch) made by [Mathhew Rocklin](https://github.com/mrocklin) (the creator of Dask). \n",
- "\n",
- "After using this feature, I am now motivated to learn languages like Julia to discover what other paradigms I might be missing.\n",
- "\n",
- "---"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## A better version of functools.partial\n",
- "\n",
- "`functools.partial` is a great utility that creates functions from other functions that lets you set default values. Lets take this function for example that filters a list to only contain values >= `val`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[3, 4, 5, 6]"
- ]
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "test_input = [1,2,3,4,5,6]\n",
- "def f(arr, val): \n",
- " \"Filter a list to remove any values that are less than val.\"\n",
- " return [x for x in arr if x >= val]\n",
- "\n",
- "f(test_input, 3)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can create a new function out of this function using `partial` that sets the default value to 5:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[5, 6]"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "filter5 = partial(f, val=5)\n",
- "filter5(test_input)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "One problem with `partial` is that it removes the original docstring and replaces it with a generic docstring:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'partial(func, *args, **keywords) - new function with partial application\\n of the given arguments and keywords.\\n'"
- ]
- },
- "execution_count": 18,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "filter5.__doc__"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "[fastcore.utils.partialler](https://fastcore.fast.ai/basics.html#partialler) fixes this, and makes sure the docstring is retained such that the new API is transparent:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'Filter a list to remove any values that are less than val.'"
- ]
- },
- "execution_count": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "filter5 = partialler(f, val=5)\n",
- "filter5.__doc__"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## Composition of functions\n",
- "\n",
- "A technique that is pervasive in functional programming languages is function composition, whereby you chain a bunch of functions together to achieve some kind of result. This is especially useful when applying various data transformations. Consider a toy example where I have three functions: (1) Removes elements of a list less than 5 (from the prior section) (2) adds 2 to each number (3) sums all the numbers:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "15"
- ]
- },
- "execution_count": 20,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "def add(arr, val): return [x + val for x in arr]\n",
- "def arrsum(arr): return sum(arr)\n",
- "\n",
- "# See the previous section on partialler\n",
- "add2 = partialler(add, val=2)\n",
- "\n",
- "transform = compose(filter5, add2, arrsum)\n",
- "transform([1,2,3,4,5,6])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "But why is this useful? You might me thinking, I can accomplish the same thing with:\n",
- "\n",
- "```py\n",
- "arrsum(add2(filter5([1,2,3,4,5,6])))\n",
- "```\n",
- "You are not wrong! However, composition gives you a convenient interface in case you want to do something like the following:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[7.5, 7.5]"
- ]
- },
- "execution_count": 21,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "def fit(x, transforms:list):\n",
- " \"fit a model after performing transformations\"\n",
- " x = compose(*transforms)(x)\n",
- " y = [np.mean(x)] * len(x) # its a dumb model. Don't judge me\n",
- " return y\n",
- "\n",
- "# filters out elements < 5, adds 2, then predicts the mean\n",
- "fit(x=[1,2,3,4,5,6], transforms=[filter5, add2])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For more information about `compose`, read [the docs](https://fastcore.fast.ai/basics.html#compose).\n",
- "\n",
- "---"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## A more useful __repr__
\n",
- "\n",
- "In python, `__repr__` helps you get information about an object for logging and debugging. Below is what you get by default when you define a new class. (Note: we are using `store_attr`, which was discussed earlier)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "<__main__.Test at 0x7ffcd766cee0>"
- ]
- },
- "execution_count": 22,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "class Test:\n",
- " def __init__(self, a, b=2, c=3): store_attr() # `store_attr` was discussed previously\n",
- " \n",
- "Test(1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can use [basic_repr](https://fastcore.fast.ai/basics.html#basic_repr) to quickly give us a more sensible default:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "Test(a=2, b=2, c=3)"
- ]
- },
- "execution_count": 23,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "class Test:\n",
- " def __init__(self, a, b=2, c=3): store_attr() \n",
- " __repr__ = basic_repr('a,b,c')\n",
- " \n",
- "Test(2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## Monkey Patching With A Decorator\n",
- "\n",
- "It can be convenient to [monkey patch](https://www.geeksforgeeks.org/monkey-patching-in-python-dynamic-behavior/) with a decorator, which is especially helpful when you want to patch an external library you are importing. We can use the [decorator @patch](https://fastcore.fast.ai/foundation.html#patch) from `fastcore.foundation` along with type hints like so:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [],
- "source": [
- "class MyClass(int): pass \n",
- "\n",
- "@patch\n",
- "def func(self:MyClass, a): return self+a\n",
- "\n",
- "mc = MyClass(3)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Now, `MyClass` has an additional method named `func`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "13"
- ]
- },
- "execution_count": 25,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "mc.func(10)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Still not convinced? I'll show you another example of this kind of patching in the next section."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## A better pathlib.Path\n",
- "\n",
- "When you see [these extensions](https://fastcore.fast.ai/xtras.html#Extensions-to-Pathlib.Path) to pathlib.path you won't ever use vanilla pathlib again! A number of additional methods have been added to pathlib, such as:\n",
- "\n",
- "- `Path.readlines`: same as `with open('somefile', 'r') as f: f.readlines()`\n",
- "- `Path.read`: same as `with open('somefile', 'r') as f: f.read()`\n",
- "- `Path.save`: saves file as pickle\n",
- "- `Path.load`: loads pickle file\n",
- "- `Path.ls`: shows the contents of the path as a list. \n",
- "- etc.\n",
- "\n",
- "[Read more about this here](https://fastcore.fast.ai/xtras.html#Extensions-to-Pathlib.Path). Here is a demonstration of `ls`: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 27,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(#7) [Path('2020-09-01-fastcore.ipynb'),Path('README.md'),Path('fastcore_imgs'),Path('2020-02-20-test.ipynb'),Path('.ipynb_checkpoints'),Path('2020-02-21-introducing-fastpages.ipynb'),Path('my_icons')]"
- ]
- },
- "execution_count": 27,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from fastcore.utils import *\n",
- "from pathlib import Path\n",
- "p = Path('.')\n",
- "p.ls() # you don't get this with vanilla Pathlib.Path!!"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Wait! What's going on here? We just imported `pathlib.Path` - why are we getting this new functionality? Thats because we imported the `fastcore.utils` module, which patches this module via the `@patch` decorator discussed earlier. Just to drive the point home on why the `@patch` decorator is useful, I'll go ahead and add another method to `Path` right now:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 28,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'This is fun!'"
- ]
- },
- "execution_count": 28,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "@patch\n",
- "def fun(self:Path): return \"This is fun!\"\n",
- "\n",
- "p.fun()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "That is magical, right? I know! That's why I'm writing about it!"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## An Even More Concise Way To Create Lambdas\n",
- "\n",
- "\n",
- "`Self`, with an uppercase S, is an even more concise way to create lambdas that are calling methods on an object. For example, let's create a lambda for taking the sum of a Numpy array:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 29,
- "metadata": {},
- "outputs": [],
- "source": [
- "arr=np.array([5,4,3,2,1])\n",
- "f = lambda a: a.sum()\n",
- "assert f(arr) == 15"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can use `Self` in the same way:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 30,
- "metadata": {},
- "outputs": [],
- "source": [
- "f = Self.sum()\n",
- "assert f(arr) == 15"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Let's create a lambda that does a groupby and max of a Pandas dataframe:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 31,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " Another Column | \n",
- "
\n",
- " \n",
- " Some Column | \n",
- " | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " a | \n",
- " 6 | \n",
- "
\n",
- " \n",
- " b | \n",
- " 60 | \n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " Another Column\n",
- "Some Column \n",
- "a 6\n",
- "b 60"
- ]
- },
- "execution_count": 31,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import pandas as pd\n",
- "df=pd.DataFrame({'Some Column': ['a', 'a', 'b', 'b', ], \n",
- " 'Another Column': [5, 7, 50, 70]})\n",
- "\n",
- "f = Self.groupby('Some Column').mean()\n",
- "f(df)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Read more about `Self` in [the docs](https://fastcore.fast.ai/basics.html#Self-(with-an-uppercase-S))."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## Notebook Functions\n",
- "\n",
- "These are simple but handy, and allow you to know whether or not code is executing in a Jupyter Notebook, Colab, or an Ipython Shell:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 32,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(True, False, True)"
- ]
- },
- "execution_count": 32,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from fastcore.imports import in_notebook, in_colab, in_ipython\n",
- "in_notebook(), in_colab(), in_ipython()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This is useful if you are displaying certain types of visualizations, progress bars or animations in your code that you may want to modify or toggle depending on the environment."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "---\n",
- "\n",
- "## A Drop-In Replacement For List\n",
- "\n",
- "You might be pretty happy with Python's `list`. This is one of those situations that you don't know you needed a better list until someone showed one to you. Enter `L`, a list like object with many extra goodies. \n",
- "\n",
- "The best way I can describe `L` is to pretend that `list` and `numpy` had a pretty baby:"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "define a list (check out the nice `__repr__` that shows the length of the list!)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 33,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(#3) [1,2,3]"
- ]
- },
- "execution_count": 33,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "L(1,2,3)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Shuffle a list:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 34,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(#20) [8,7,5,12,14,16,2,15,19,6...]"
- ]
- },
- "execution_count": 34,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "p = L.range(20).shuffle()\n",
- "p"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Index into a list:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 35,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(#3) [5,14,2]"
- ]
- },
- "execution_count": 35,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "p[2,4,6]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "L has sensible defaults, for example appending an element to a list:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 36,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(#4) [1,2,3,4]"
- ]
- },
- "execution_count": 36,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "1 + L(2,3,4)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "There is much more `L` has to offer. Read [the docs](https://fastcore.fast.ai/foundation.html#Class-L-Methods) to learn more."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# But Wait ... There's More!\n",
- "\n",
- "![](fastcore_imgs/bwtm.jpg)\n",
- "\n",
- "There are more things I would like to show you about fastcore, but there is no way they would reasonably fit into a blog post. Here is a list of some of my favorite things that I didn't demo in this blog post:\n",
- "\n",
- "## Utilities\n",
- "\n",
- "The [Basics](https://fastcore.fast.ai/basics.html) section contain many shortcuts to perform common tasks or provide an additional interface to what standard python provides. \n",
- "\n",
- "- [mk_class](https://fastcore.fast.ai/basics.html#mk_class): quickly add a bunch of attributes to a class\n",
- "- [wrap_class](https://fastcore.fast.ai/basics.html#wrap_class): add new methods to a class with a simple decorator\n",
- "- [groupby](https://fastcore.fast.ai/basics.html#groupby): similar to Scala's groupby\n",
- "- [merge](https://fastcore.fast.ai/basics.html#merge): merge dicts\n",
- "- [fasttuple](https://fastcore.fast.ai/basics.html#fastuple): a tuple on steroids\n",
- "- [Infinite Lists](https://fastcore.fast.ai/basics.html#Infinite-Lists): useful for padding and testing\n",
- "- [chunked](https://fastcore.fast.ai/basics.html#chunked): for batching and organizing stuff\n",
- "\n",
- "## Multiprocessing\n",
- "\n",
- "The [Multiprocessing section](http://fastcore.fast.ai/xtras.html#Multiprocessing) extends python's multiprocessing library by offering features like:\n",
- "\n",
- "- progress bars\n",
- "- ability to pause to mitigate race conditions with external services\n",
- "- processing things in batches on each worker, ex: if you have a vectorized operation to perform in chunks\n",
- "\n",
- "## Functional Programming\n",
- "\n",
- "The [functional programming section](https://fastcore.fast.ai/basics.html#Functions-on-Functions) is my favorite part of this library. \n",
- "\n",
- "- [maps](https://fastcore.fast.ai/basics.html#maps): a map that also composes functions\n",
- "- [mapped](https://fastcore.fast.ai/xtras.html#mapped): A more robust `map` \n",
- "- [using_attr](https://fastcore.fast.ai/basics.html#using_attr): compose a function that operates on an attribute\n",
- "\n",
- "## Transforms\n",
- "\n",
- "[Transforms](https://fastcore.fast.ai/transform.html) is a collection of utilities for creating data transformations and associated pipelines. These transformation utilities build upon many of the building blocks discussed in this blog post.\n",
- "\n",
- "\n",
- "## Further Reading\n",
- "\n",
- "**It should be noted that you should read the [main page of the docs](https://fastcore.fast.ai/) first, followed by the section on [tests](https://fastcore.fast.ai/) to fully understand the documentation.**\n",
- "\n",
- "- The [fastcore documentation site](https://fastcore.fast.ai/).\n",
- "- The [fastcore GitHub repo](https://github.com/fastai/fastcore).\n",
- "- Blog post on [delegation](https://www.fast.ai/2019/08/06/delegation/)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Shameless plug: fastpages\n",
- "\n",
- "This blog post was written entirely in a Jupyter Notebook, which GitHub automatically converted into to a blog post! Sound interesting? [Check out fastpages](https://github.com/fastai/fastpages)."
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "fastai",
- "language": "python",
- "name": "fastai"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.3"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/_notebooks/2020-11-17-linkcheck.ipynb b/_notebooks/2020-11-17-linkcheck.ipynb
deleted file mode 100755
index 2caa934..0000000
--- a/_notebooks/2020-11-17-linkcheck.ipynb
+++ /dev/null
@@ -1,470 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# \"Introducing fastlinkcheck\"\n",
- "\n",
- "> Say goodbye broken links on your static sites. Platform independent, fast, and built in python.\n",
- "- author: \"Jeremy Howard and Hamel Husain\"\n",
- "- toc: false\n",
- "- image: images/copied_from_nb/fastlinkcheck_images/fastlinkcheck.png\n",
- "- comments: true\n",
- "- categories: [nbdev, fastlinkcheck]\n",
- "- permalink: /fastlinkcheck/\n",
- "- badges: true"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "![diagram](fastlinkcheck_images/fastlinkcheck.png)\n",
- "\n",
- "# Motivation\n",
- "\n",
- "Recently, fastai has been hard at work improving and overhauling [nbdev](https://nbdev.fast.ai/), a literate programming environment for python. A key feature of nbdev is automated generation of documentation from Jupyter notebooks. This documentation system adds many niceties, such as the following types of hyperlinks automatically:\n",
- "\n",
- " - Links to source code on GitHub.\n",
- " - Links to both internal and external documentation by introspecting variable names in backticks.\n",
- "\n",
- "Because documentation is so easy to create and maintain in nbdev, we find ourselves and others creating much more of it! In addition to automatic hyperlinks, we often include our own links to relevant websites, blogs and videos when documenting code. For example, one of the largest nbdev generated sites, [docs.fast.ai](https://docs.fast.ai/), has more than 300 external and internal links at the time of this writing. \n",
- "\n",
- "\n",
- "# The Solution\n",
- "\n",
- "Due to the continued popularity of [fastai](https://github.com/fastai/fastai) and the growth of new nbdev projects, grooming these links manually became quite tedious. We investigated solutions that could verify links for us automatically, but were not satisfied with any existing solutions. These are the features we desired:\n",
- "\n",
- "- A platform independent solution that is not tied to a specific static site generator like Jekyll or Hugo.\n",
- "- Intelligent introspection of external links that are actually internal links. For example, if we are building the site docs.fast.ai, a link to `https://docs.fast.ai/tutorial` should not result in a web request, but rather introspection of the local file system for the presence of `tutorial.html` in the right location.\n",
- "- Verification of any links to assets like CSS, data, javascript or other files. \n",
- "- Logs that are well organized that allow us to see each broken link or reference to a non-existent path, and the pages these are found in.\n",
- "- Parallelism to verify links as fast as possible. \n",
- "- Lightweight, easy to install with minimal dependencies.\n",
- "\n",
- "We tried tools such as [linkchecker](https://github.com/wummel/linkchecker) and [pylinkvalidator](https://github.com/bartdag/pylinkvalidator), but these required your site to be first be hosted. Since we wanted to check links on a static site, hosting is overhead we wanted to avoid.\n",
- "\n",
- "This is what led us to create [fastlinkcheck](https://fastlinkcheck.fast.ai/), which we discuss below.\n",
- "\n",
- "> Note: For Ruby users, [htmlproofer](https://github.com/gjtorikian/html-proofer) apperas to provide overlapping functionality. We have not tried this library. "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# A tour of fastlinkcheck\n",
- "\n",
- "For this tour we will be referring to the files in the [fastlinkcheck repo](https://github.com/fastai/fastlinkcheck). You should clone this repo in the current directory in order to follow along:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Cloning into 'fastlinkcheck'...\n",
- "remote: Enumerating objects: 135, done.\u001b[K\n",
- "remote: Counting objects: 100% (135/135), done.\u001b[K\n",
- "remote: Compressing objects: 100% (98/98), done.\u001b[K\n",
- "remote: Total 608 (delta 69), reused 76 (delta 34), pack-reused 473\u001b[K\n",
- "Receiving objects: 100% (608/608), 1.12 MiB | 10.47 MiB/s, done.\n",
- "Resolving deltas: 100% (302/302), done.\n"
- ]
- }
- ],
- "source": [
- "git clone https://github.com/fastai/fastlinkcheck.git\n",
- "cd fastlinkcheck"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Installation\n",
- "\n",
- "You can install `fastlinkcheck` with pip:"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`pip install fastlinkcheck`"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Usage"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "After installing `fastlinkcheck`, the cli command `link_check` is available from the command line. We can see various options with the `--help` flag."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "usage: link_check [-h] [--host HOST] [--config_file CONFIG_FILE] [--pdb]\n",
- " [--xtra XTRA]\n",
- " path\n",
- "\n",
- "Check for broken links recursively in `path`.\n",
- "\n",
- "positional arguments:\n",
- " path Root directory searched recursively for HTML files\n",
- "\n",
- "optional arguments:\n",
- " -h, --help show this help message and exit\n",
- " --host HOST Host and path (without protocol) of web server\n",
- " --config_file CONFIG_FILE\n",
- " Location of file with urls to ignore\n",
- " --pdb Run in pdb debugger (default: False)\n",
- " --xtra XTRA Parse for additional args (default: '')\n"
- ]
- }
- ],
- "source": [
- "link_check --help"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "From the root of [fastlinkcheck repo](https://github.com/fastai/fastlinkcheck), We can search the directory `_example/broken_links` recursively for broken links like this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " \n",
- "ERROR: The Following Broken Links or Paths were found:\n",
- "\n",
- "- 'http://fastlinkcheck.com/test.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`\n",
- "\n",
- "- 'http://somecdn.com/doesntexist.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`\n",
- "\n",
- "- Path('/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.js') was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`"
- ]
- },
- {
- "ename": "",
- "evalue": "1",
- "output_type": "error",
- "traceback": []
- }
- ],
- "source": [
- "link_check _example/broken_links "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Specifying the `--host` parameter allows you detect links that are internal by identifying links with that host name. External links are verified by making a request to the appropriate website. On the other hand, internal links are verified by inspecting the presence and content of local files. \n",
- "\n",
- "We must be careful when using the `--host` argument to only pass the host (and path, if necessary) **without** the protocol. For example, this is how we specify the hostname if your site's url is `http://fastlinkcheck.com/test.html`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " \n",
- "ERROR: The Following Broken Links or Paths were found:\n",
- "\n",
- "- 'http://somecdn.com/doesntexist.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`\n",
- "\n",
- "- Path('/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.js') was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`"
- ]
- },
- {
- "ename": "",
- "evalue": "1",
- "output_type": "error",
- "traceback": []
- }
- ],
- "source": [
- "link_check _example/broken_links --host fastlinkcheck.com"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We now have one less broken link as there is indeed a file named `test.html` in the root of the path we are searching. However, if we add a path to the end of `--host` , such as `fastlinkcheck.com/mysite` the link would again be listed as broken because `_example/broken_links/mysite/test.html` does not exist:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " \n",
- "ERROR: The Following Broken Links or Paths were found:\n",
- "\n",
- "- 'http://fastlinkcheck.com/test.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`\n",
- "\n",
- "- 'http://somecdn.com/doesntexist.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`\n",
- "\n",
- "- Path('/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.js') was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`"
- ]
- },
- {
- "ename": "",
- "evalue": "1",
- "output_type": "error",
- "traceback": []
- }
- ],
- "source": [
- "link_check _example/broken_links --host fastlinkcheck.com/mysite"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can ignore links by creating a text file that contains a list of urls and paths to ignore. For example, the file `_example/broken_links/linkcheck.rc` contains:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "test.js\n",
- "https://www.google.com\n"
- ]
- }
- ],
- "source": [
- "cat _example/broken_links/linkcheck.rc"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can use this file to ignore urls and paths with the `--config_file` argument. This will filter out references to the broken link `/test.js` from our earlier results:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " \n",
- "ERROR: The Following Broken Links or Paths were found:\n",
- "\n",
- "- 'http://somecdn.com/doesntexist.html' was found in the following pages:\n",
- " - `/Users/hamelsmu/github/fastlinkcheck/_example/broken_links/test.html`"
- ]
- },
- {
- "ename": "",
- "evalue": "1",
- "output_type": "error",
- "traceback": []
- }
- ],
- "source": [
- "link_check _example/broken_links --host fastlinkcheck.com --config_file _example/broken_links/linkcheck.rc"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, if there are no broken links, `link_check` will not return anything. The directory `_example/no_broken_links/` does not contain any HTML files with broken links:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "█\r",
- "\r",
- " |--------------------| 0.00% [0/2 00:00<00:00]\r",
- "\r",
- " |██████████----------| 50.00% [1/2 00:00<00:00]\r",
- "\r",
- " |████████████████████| 100.00% [2/2 00:00<00:00]\r",
- "\r",
- " \r",
- "No broken links found!\n"
- ]
- }
- ],
- "source": [
- "link_check _example/no_broken_links"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Python"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can also use these utilities from python instead of the terminal. Please see [these docs](https://fastlinkcheck.fast.ai/linkcheck.html/) for more information."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Using `link_check` in GitHub Actions\n",
- "\n",
- "\n",
- "The `link_check` CLI utility that is installed with `fastlinkcheck` can be very useful in continuous integration systems like [GitHub Actions](https://github.com/features/actions). Here is an example GitHub Actions workflow that uses `link_check`:\n",
- "\n",
- "\n",
- "```yaml\n",
- "name: Check Links\n",
- "on: [workflow_dispatch, push]\n",
- "\n",
- "jobs:\n",
- " check-links:\n",
- " runs-on: ubuntu-latest\n",
- " steps:\n",
- " - uses: actions/checkout@v2\n",
- " - uses: actions/setup-python@v2\n",
- " - name: check for broken links\n",
- " run: |\n",
- " pip install fastlinkcheck\n",
- " link_check _example \n",
- "```\n",
- "\n",
- "We can a few more lines of code to open an issue instead when a broken link is found, using the [gh cli](https://github.com/cli/cli):\n",
- "\n",
- "```yaml\n",
- "...\n",
- " - name: check for broken links\n",
- " run: |\n",
- " pip install fastlinkcheck\n",
- " link_check _example 2> err || true\n",
- " export GITHUB_TOKEN=\"YOUR_TOKEN\"\n",
- " [[ -s err ]] && gh issue create -t \"Broken links found\" -b \"$(< err)\" -R \"yourusername/yourrepo\"\n",
- "```\n",
- "\n",
- "We can extend this even further to only open an issue when another issue with a specific label isn't already open:\n",
- "\n",
- "```yaml\n",
- "...\n",
- " - name: check for broken links\n",
- " run: |\n",
- " pip install fastlinkcheck\n",
- " link_check \"docs/_site\" --host \"docs.fast.ai\" 2> err || true\n",
- " export GITHUB_TOKEN=\"YOUR_TOKEN\"\n",
- " if [[ -z $(gh issue list -l \"broken-link\")) && (-s err) ]]; then\n",
- " gh issue create -t \"Broken links found\" -b \"$(< err)\" -l \"broken-link\" -R \"yourusername/yourrepo\"\n",
- " fi\n",
- "```\n",
- "\n",
- "\n",
- "See the [GitHub Actions docs](https://docs.github.com/en/free-pro-team@latest/actions) for more information."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Resources\n",
- "\n",
- "The following resources are relevant for those interested in learning more about `fastlinkcheck`:\n",
- "\n",
- "- The fastlinkcheck [GitHub repo](https://github.com/fastai/fastlinkcheck)\n",
- "- The fastlinkcheck [docs](https://fastlinkcheck.fast.ai/)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.2"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/_notebooks/fastcore_imgs/bwtm.jpg b/_notebooks/fastcore_imgs/bwtm.jpg
deleted file mode 100644
index 2fd6f3fa665f5c2157d99a6cf7dfb82a9336daa6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 16710
zcmb8VbyS;8w>KPIi(4rW+zUmE2iM}>qD6`pcM0yrg1fszDNeECMN|K>pk03vMxsQ>19k9hvm5G(&P
z``=HL0;K<0u>ko$+(@(qDF59z`Dfa5KY$Pu$pncO1&JPjOo)U+i1a)N03y~xL;6?y
zhY8V8kWrD)0O%N)SlBoSh5-Tq5(?rs6jXFn40KdXbT=eq016>05gi&2F+BmglqN5U
zxeEhEFl~}FX`vQhBjd+6WPPqPGRgcQm>b%XOcvw
z3TGIL+*_+=U5}E~f$;M=dC#Ct1wHE)EbNz*tZeK;!Xk=F%K8R|??2ht+Ie~V_(nuV
zMaLwjrDtSj6_l2hS5#Itd~N;K*52`baOlVI$mrPgJoMMX@5QC{t?ixNz5RoW%d6{~
z+q?UJP$G2nUmy|R|3di>2voHHK}iTeMn>R7K}JDCMngtLjYLA|2!()%4waTiiWuz;
zJ+CH-Bsw31xiqPZ7Jsk?V^X0^BN@g=0qxTnCbK@-4c9aB5DP(PW;vZ?mZDjN@+kg=
z<1GS+yaED>uHHXjEUm2n!Q#Z6JZ#wKQ^B%@^g|J|OK0Jtds
zQXe5=b6u%^b^IS{kLkLY68gy1-w_scxf;32TwkKJ-t$LhvaxmPf2Yc)fTK1fDY7lH
zU7wG&vInacD&CVN5@9T_=l8N5Km4y`3WC1u=X;=N*xgr+InpiBll{W|c9E|vFMMYe
zvN+T__6r1q&2!?q
zqLKPALKT&1Bf0X2Z!^YyVfOBOmFkqgK7*t$`>vEv-cEOwBZ-k#*(Q
z33@#^x-Q%OFQg9*$H(e#*#nFz*c*j?E@RJQPV>n6P3h!tiWgc8bXhg`-CwjD7yG%a
z_y48ITWJw6w~TRxxtj@8imG`ekHpdjZ0k1Ftitz!<91P5qV991Ez4&YC-v}svQ?S6
zi@Y^DpZ`m8b>kge>QYEg@aud5zN!aiW@>dMqlij0lTU@0&j8dL2TEAeMGC`&<6kF{
zdAqrSchx#^GkQJ2TiqrYP0MDU|JoQ|10vJ1b3Qj7)0R2(Z-oAuq)rWYG-OPM(jQm2
zajt&Qg{|%n0hC;CNLvGJiG?dOV`g}?QdNB|^3-c!j;&+}OuA07p8j0H)#v)QCU`w7
z-{Zn5pk!a6j!jt_aWMs+8?AEUZ^`|Bjx^bwG_u(6J=l%oxw6|Y3Ao6zREu&epR23x
za<~4@ZLR$#ZlbAY^BZJr1&K(AKzUEs)nZnu^C**663S%PDT&>aUQy83kxUnWBh07A
zXWX!OC=fv~3iZt7ZiG#6TS4`@99yAXn=|nFKl09V9RoECMctDJLf@!el2}+j_N{+xBqqW6&2G!Z^uFk7~|py-q3A*-Q4+q>4h#gQ6cdIo~f;Z__;%
zfHAFaYYwVSEPB8<&w$)Kr&+hOrBEqI!K<|GqIZ>buCr~K*?hm+%K5A%QEh{B!2aufLJgI{#lS^!J;MUQp1AUv}69iq#sM)A5MB$2C*#9Bt<)N<$>
zbLGBot%I+&xEVJ~#NFnpbZosHA!}K1`Z77BAS0Cjel{-3?z_9$P1n}_6W0{e)_omY
zY^3h4S-C?_%jKkl60ak}T@|u(n)>+I-^iZJz1N4lY;g9%-CoZt1)IdXT?!(di~h^rnj%a*
zCc=>-p&>u{`fP@XP7#NVf})(Z-Hy|nm2A7$K2$rc9o4;8)OZHyIlU_R;O>>KZK6Ev
z%zk~;?}z1BE;k4|sGU6%6x1gkb>TyT_2UfaFjU0X7CY;$2?+oX@+pi`S6fP>#$~OF
zM4Hi~<(r0M+4fH#N86Wsp%V1<`xPH2hd-mpwb``biPFwE#OYebWLt_pyoucKNj1Gv
z+u-gpU25#(;+=hu!`VJ$@!RGt_)4}~nyBg%PTXa2n1xQuP0kF>OEs_Fg9I|gfODOX
zju4G6*vc|7@giPa@Y%KgN{OSViZciB4@=>q<;BGGZK`pZubrcHzF1yzv=5K{6SHnL
zo;G)$po0XWp}arZA+H0XW=UY*u$8{@#{gn0&6E>6S({YD6Z{qKMoDImoQjh(Jz3ljf%Ae4q{-Z8zIYr@H!OVBJ7UXwYH5qa9?xFOvuUVs7c}_&j@2h_(V|OMAWiSpFFG?3_
zhpr5mc82;Fw55GjtSy@QbNCE^zI`aIg>+}E7%^^z>Qt>bYSK9h<|;>Hy45q-x*gx7
zEod6CJgR$mke2vG+=v}Z`mu^NQI-yi?h1_Q9UignJYI!CWxbjU`#LIwxaqPVmB3)q
zBChS^V=LxbsU-R237CN(2MSjhI#Dt&*vP^8E&}NhBj9Lxft-fVXx$I@G;x8u}NV;ai?Aqnycg
z9n2-~SbIl-CyXkI8fWTF3HT%7#$P%_hOp`Vf=kp^C<;y8Bh3S=Jy0~^zmD2*6g>E2
z6FK%GDrK^lpKdU|(z*?4(!^+aD6#5|267)xy_nI7;7PY~rlJ;2ytaqHp+{qmj_LGU
zsS1J^uk{{@d^ilrAKJuA#q79fi(_BTxnM~xaqF7RfPQWesy@|LBu$X}$Al2Q-2X9o`BdAkRxu({+?F^VH1f*uJyW;enOCB~WJ=Z59f
zcokU~_e2Ms)c_rmk(_stJfrF#+fh!OyaM;lN~S5!-)W_YX*GmKrxnV1#K>IgMRM5Z
z`Z;4An@|hx)t=>#xPEKhCv0a=t?vz=_Hw4
zNT_mQJdnwSW8JgB58xAcCm!_B-HUN{+_t^Vu5r0G)8ywM86S&NYx1v)o_qUF!)o2q
zgZ_+#CU>u_zSm@}6c5W@CxNH0v2(c+}heLvg%vY6uid~FPt&=Ep_DO|GV7!CMP1
zp$u&tR}!>uAZ#)&%zhPyGs3ui>gTX}X6{_``e*JBFi;)5YY+v4}2~D{%1x3mU%JMo`-oql;6=4^7Y)-WF3Eiqm
z#*g}alQ*JO05uX0GZe>GN^j?&AHqU-#Lg##yxRkWwodW*(F@86_|y1b4^vJbjLynl
z(FPz*f3R`&@kFa>qu;4wJyoVuHTtFap{+6J)re(W-w~~5nX-Z-ZrRAs94LK~lZZ|x
z=Ki7v**BP$+Lq4WdH}0Vss|qb$KTp31Y3>Ox;eoQHML~pDqE~fn6Cu~2<_6c6+>l}
zl+?=NJV&SEMu%~tbY*NWHL7#PyH?)Dw#Q>xYL)7aIg3(OFaH3PUGqU;m8tSykomEk
z?aIINQqyobt@KCpBp1mN3{dh{=&;vUmVISY&O2m|Vf8T5VQtx^=Q*JpMlH3M7PdD@
zJy;};F^xIGy=HYeV-c2bf`$v}79{OlOjnTWL$W@RZ4+7L$#S|0yz5}rsoY9DS9vM&
zdQ>>*SU*I?o$8&o{88Dr8kLX2X_H-r(xmd0>&cxTZHcv{As&RS9SOf9msGUX2}~Rm
zFZ{R-ZW(`r4HituA@oV^VB3{lpa%kXm)EHRoRb;+pH#?f6@s
z+LfX=yQ=SJ-!N
z9ame_ChD~3NSP?SO-+89>!;qlqWxKIn~F!Yu1qPE%f;zV@YUVcJ}~KIT%%$O2@Uip
zwr{;3_&Q7kU53qCFsf>f8dC*&=GvXSmf!IV5EUc*qW}}H5*6^m2MXf{hq8)R
zj+9ExS5nP3kT$`WG!hN|MSv1*VHZ;a%GrVK^aV6RCBhd^eQgQAM*QC)ehdkop$ES9
z$M~bd>cLMDy|u}&d?@wJ@15geJLzR1QUX_!tqeA|3Spj^j)
z=bUR1rGGF_k(8wmLN6cSW*zkGu&=kWJAJ!r%of8qkh+P)z6qZW{WAT_
zy8y!NgfGlK=E?Dyk@Z$|XFv0@5`Tg`%U@)-e57$t@xoTDMNf&>?iXd+@=RXN0xeDR
zoK>C@xG{-*GZJ
z2>HoRI4y-`zA0N#dKSbBUsIkVc#<};Ycl|i^5X`uC4ri{4c@Iuu?$DT4w5l%!PQ_p
z4?k9GmGD&Hyu|5tMMm{}$Q+}5rT%@b8~6AkO=*>3iq2P;ho#e_q><(7Wks|5XFydF
zK%A$n#9#f-?e+Q<{^4Oxa7_TI1o)u33Nfm`y0IKOilX51*_)*XTveWao#uz%Q!a!N
z=P$8#r9R8XhB5!uqQ4`c??%UXqGdfX3$db^LK+otpsn&@{7yLaLFE~svpl{XjSClb
z-+L_eUy%~JZ>+8^@MRjS4^4n^JXMZm6-s`+F2sv2U)n2Sj?)aAxeB4SU{}J^xsRj-
zSn@#Dwy|))G#8f
zzEA`~{gc@%)$*}D-%H>X>#M(gFK&tw%gYgb?%ywBp&F?0s86J@Ei)HxNUdH3lB3-jGV?HEJlJ@qsUcj_~N7LQVfBt#ON!;U(`JN0}^`R?#6JyO%qQD7)^
zZz9<*P-X^hKvRCa6(V&jVLUT^YI*_HtCkoGFiiGHWxb(Ja61QMjHbZI5A$Q8$^lq*
z67C)r3nyVpHK6YYLg2UKF)=w$Tety<)9P@Q6NHMZ!b?eD1mlzlHj}B|K6tArxDwLL{PoCuDArEE;16
zIB`B37|;DH5XN|+08GE2nh&VoxfAk;s5TTT*747vDXn-0@VBX_72ic$gHmiSJYZ_2
z3!|a^JpobY+(4dUYRF#THcp>OpLt*%6VNh?EFy4yV^`9De9W?ljU=9by{sr@ZgI4h
zWn`|){=63d0`sf-HS|#}_lr1WP~!d555wEPOLu(JEQxoUMO~@-j3Yo&Jt50k{PG9Pg!ue<&0#Y8kH4rC$;an+^P-
z!t_`ZFhg&U=yT>R5->I_EZxhio?YKXi&2%*bf(xx6WZX*_qjeR@G=H|u&3^?-?w*W
z`rF{K@cVt&fHoe#Z}mxqZzFu2A+~;(X8NJE@@dARwJvq$zC(b{w9_=d(D(k$eDij}
z(?`>whv57UKlIdi8V5Ep{68%~iA(JY*ggyF(hi6orpDu|~9>3Z$$HeXH
zJdWodY0jN2T&o({spnsyOh(eot75*ZOP&8(+aH7FdGf770myiH}I3olsc{>faN
z;qhcHvjLxf21snu-5_hQ7Z-RJ#deqy?~RpeYNb|k#Yf{+O^YzMT)FCN%BQeCQcjAF
z1hO3OT^$$h!zVUEw-=Ql`UxINY(Jz$IJPcsIw0`$bTM$qUZ$pkVw~xQxVGte{;}RX
zHi?A!o`L-lQGural`NnG9lpX`F3vO30KuR}n6)I+Zd
zHt97FRbanP0f^i+KwEvd+i(Ad|K6-_V0`2F^Uw
zMy_%%r2NWqodWRfril(5uSzPOo`wg)hKrSZGl0nF;#Fdu{>JKd4KjoU9Ne4=EoVBh
z%Fh7HG~DV$#=T4Z0}GSZFvY5c#UqD=Xl|1~z^32}t|k{Tnyx^6-EKePgEP>Cec%3C
zc}eqJ`sh`m(%p4&ft_H7;@7ZL{Y4c$En3p2gI@f%l&JnQ6!&sIrRr!dxbw5|O1eYh
z4Bzwt!3lpB#*aN*KE=+M#-0bNk1o(HSIXDNg?M4wnf@dUVp0I10Sa
z@-2P_IKGxrpvMR5NgRj&U34An78ie6y^sK5Z#AfdrOQRXx$Cw3d$3nT(vmRtBUGWT
z2Cju~ITrsW>oK=_dFu%{5%$Dg!HOr25?o4=B|xX7e|UehSv_C6*V2=Uw-kCUV1MM}
zxj=iB3Znl>Oj|zpwqD~2YN|}CP@)WXOBd{cKht&A?@C-FzLaN_d`)nv3$Ui
z6`Bv)0k9c(>%eRiBd%*q5koS=aLoRaLuN-TPm${OQFHjzoOxBF)R`jJn1nTubD@`f
zxF>(o?(Yq&*dLq6lwde4WEQn$A2Pw4nXJiu+5)7&LEsj#u{
zbcSH#jP{MBhM99vVnM_A>Ggky1V|vdXTU}Fi|e5Y!gu-7kH(D?oK0pPDRL;WSsfXm;@kY|7b^gUC5V9>!Z99=tSbBIQNV+*n)X27=(Ley?&FBgZ?
z)@vF{LFexU8gkk%4+bK7_1#^4jwdEeBAZtjgovL3`=;v)I51Y#^e0@xJUz0(R@2Fk
z`9)QUnFVIQ9b0By-4HC2*B|oEd(i^8XE^BMAc^4Dj%u;8g
z0DMZpxw*w%*pRcPA%P1xqMkZsewLuIPEw+7sZu~wQi(gw0fV2?idFayOyM08x)TjQ
zigu80%#cxRRJ@eYX)OcU<6M>n>8>SK0>Jk=<)Qn}fP~I3`=K*4x5a;6s#OWu^I98N
z4CXnQJs5=M1K(z^^i*z(N~k{r6zu|=zpk@A12}<;3sC7&!!*C*uK~F!1Uig4J{6%u
z$t*0MnN$04YDgy{e+Q;;u8j|~W=3qxoB)9n$Rkt>qXD{$wcZ(u(HSb2yBO7CHpZs_K
z8@bx#4vn3e*FqAYO%>pU{f>pt?R^0jN8~eLoP>6V20yLPbtn7^H4{c<7YU!+yaZ`Cr^j_R112-n8Cx(fYes0CqOSel~0+P
z(_)W?vrT=!kc4gY>={6p(!Ze5g9Izg-RRykm8o1Yha?{Mg2uo^sRDB0$6wio>_57A
z2P59mQS&FXM;DW*yI6{N&RfIMomg&mYn^d!jFk;l`RUyRY~mLfu%;Bll%oq%C1H@;
z-zO~Moo@*7Lq+w3cfM66%cTZ@wVwf7LP;D)b2sL#`Xhge5BbwJB@!ZX^|O$2oae2J
zf3p|oeQ{|tP7@er$*YuvmH!FA`ccAduToB|0z9<}>p#T>@mN|LoR>goctiNHC}P~G
zQ}15YPZ~S}qF<5Ef#K0cYNi|TR;solRr0h*-nnd3rSch;E4v`p3f}WZPga}TV)pHw
z$nv56$mlA3RZnWL)D!oX`a{b~@g=oF%m5mt52a5atDz+g4^}>3-a)`FA)4+;L4Awy
ztRDVo!ZRRVcl_~9BVbdz*-nj&8=0E3!WjcH=^Xg7GP3FH=2L&dkUCms3@zf!X;HZR
zyUTgqDPF(~U@vyz@uj2~wsz6P+q>rS`CB`gdvHgXy*V|R4~dTxC0f$O;xhn72i!J!
z24pFxTnttXOXyo%)*KEf?RNe+dv|MTF`SJ}!#Uo=nqbBaHHif=y?UM7r4Pk^!ZQ#Z
z=7w&7he8~B*ndrkT2?;;FduKLnd<(K$?g|6nIj71r%mdhKDT_5>P%LOrJ3?@*&N#!
zQKL*~-Au&zVtTR1-=e^WZ7fg37;ttQ`&FB!u4tdx3m=_+-)y3O(8cPQI{!~Y&+avC
z;;ov&6oeK+B$al2$A@(p3mRm=;Up*II&Y{+beZjGiP89SaGSiw^#Va#f;A+}>&qMz
z+7bkv&w$dT`T50qI5m4h%-GP4E50BOZ<@(9JpTzJ1!27MkB9CHTr0B~vhj%nx78}6
zVUb_!C&g!<0Ts=3uoPkW3k~DIDp@Cv^*V&2L=B$-Vaeedi8$W2Na;Q5eLfsR2{Yef
zuP3G9828k*^YvfOJ)QyU=@-BXoYK|vs7@IJ-ty#NrFSbK+iDunRL$m(HgfwWPNhOB
zD;Z8;J%?w&Ky3^*s^xfnXnoebw@1SG%FD2CUQRJWgTU(88J7IAC}HnsK&3E~SnCh&
zEIC>yTl0@wu=LXF^TtW<^>Pe&D(h^Ub`@n
zS4-*nTwpl8wNsdr@-`#h*VkrL4=2L;+wl+wx>%-cGI+4E@;ro3eFxrrefqO74m!^^$+5>SjqE#w6biTf}`keR4E;F6g0eBWU1PYqr#q7ThJf)z)x{d
zQ2h;|P-MluC!4*@?`PU5IT{qwNl&gr7UuvHoOQC;80lxgH&*X8gjWhi!Y99`wRKO9
zlM(d&*yNB`&KZAzo^ei#rFCH#JUr9BJMw-^r?u8X_kv2(YjYt~x>VJmDqaubWhp
zr@`)#T;yUVM26qXM8yo+O;yNmc+@q!HQhBZ)Q6u=?j}>M4fUg8VX7F0+j;iH`I9X7
z9r)aM@6S7P7Ud))&*o{?PCZ`7qu*&%6=ho$8;^q7p5_CYx^md99JJiH%`v__de
zvkYa^_BSy4mD5-=R?rN}=5bV8vW;)UkAkp}f}Uj+rLJoenbm_=CJPkl~>i>M<1c
zBfjf*JdR6q5N?fym{=uIZ>)sr%C^2}%x7inZU?RY`p3)kXTS$c*Ct8|8}{w9VOW(!
zRrbp*D=K>?UB)o$7Js&aU&G%wLX+U>+>_{9<5PZ?d%Fq5--1gs&Zm_vuI>=V<3$E%
zj*HCL6#i@8OHYSm-;(WW4;|xsF(Y$~Ik^d*4e4MPgF=jzL2Z2}rNK=63zB$=3W6`@ACv*y%E3NRl@%QOj)+VaN
zmX`NK{@cofTp#g#?whsVxJ#Hku@;fgtNrE8pnm&1@fi@VGl7v0g2Gn5L2q3v#Xe@Q
zk{L9Dr-sf`UIIICy=%DCoTB8mVbSa28hd9{e}Z21OOUbD3tYY(6yuCjpUf)x0(@Zx
z$(nJUQK~^dF3IBrUE7W&DC=tc#mE0r1qncT&}~+U(~se9whGJ8`8GDN4%$FrqB|_}
zSGxRr^$ZYR{A&+A`V4yQ-JZurU5PihdZR8tU1Fp`9_7!;sKx~t`g1UEBVLy`8
zv+2b9Syj&xz+P5zE{XLQ;;GOxa|Bx!d{?sJM0#K!AGI>M86
zUJIcep1Rkesr0FmLkgobF%PrLLBsl^HEo*vw$2orTjKY7!PqA~o%~xKv}eGsFZeE((R;2wIngoh>{$FaOz*@oeKK{s6nGUA(n`s#Csl~Pk68;1hMGC?
z9~zW`c7QyHX)NXkEvu^fcliGUWUy{I!czFNC6tK{6LzhT@NHmGFUaV*sia~7=fUe8D-naad@AcQ*
z7roO)yaN-|T?H>kuX5M?bLRYeRNgw#P8YY_p^=^;$3hv@l_YRQ~SL#S)qTX
zpR^cH;JB1bQW(f9ebu*^&MG{MoE{M-u0_L5`DH0R?^X>>)_SNhs(-c9e9KU~%2*7v8lJOi#n2bkvg(B_Gj&7T2#
zLMKrKJA$Ldubu&`%(S9m&d-3G7m1rCES}srt;>jb&-J(ec-yM~T=5Lto@f2`6$$%a
z?sedkpBqm+79vzx^7U52EkoB4T$Wn
z^`SX?ICA4(dFwx?2?TJzoh{L4z@jDbKk9fRl(kY{Gw2Jx>}wQ>x%%iW47v~1>1e`7
zf6G*7S-3=jfygsf>EEcBa3_9kMr5-mlTA-tYQ~6&ThqGrH4EgGY~e2gE{Xs*daq}|
zP!89RO^C*RK3~Ntir9wipWasuR|Idu4nKH&vS@!n_1)R1^H%5?fICh*fFl8{ubql*
zT<`L@a6*Zo#JpX$UV!6?!x!h~6%^OoZ7w>aZ~c96F~Un-X&BVfJ|x1CsEFsH@bGsQ
zcfqFayo0+_<=<{z5zf`G8t^MNUVP0s{0nK%Eu7-=4gevoO~5(d+H2EzrX8M1Saj9l
z;62>ur>|>lC*FUS)1sZZi8QadBXa|)a4`ZE7*o7@cLMV8`7toALN9QB{3!9%8vazI
zz&NZ=9j{`+Y?$nP{?r;^IzDL1VA1maQH)ExQMj=j7bQV3t&-x90iR#9)fDit?d2BO
zHoMPXF@p6`D3c0P`}0-u7T{?@+nnNz+n(ZT^wrK;8*dVi_!*<;C%uxG)F6
zfuhNqg&!Hv(ZV7|hLrChICvoZ|1M4-UX+V=!NtK_v7Rp#v;-bLL^9hzxz7LwLZ9mj
z*QR&xG9+^{?dXJQBL_zU?IROZ&Jrq&zb8hY<{vQ-6Vg(ABg>j5rR^Vu#uOIBX53Cnf|_~
zjQf=}93+AVSTEoTWJh}IyLI1XZeqE6wz7leatMZM+}XM34IN)oqWq!G+6gBO$drke
zEc3$<6FvVFE9#7z*pJBKIhAqwKdl|4jid^0ywH!O3jP!}V#6qk7ke_`BCLk|X~^u2
zv-tdqNHcN2W^B~iDD<87)(fZj0Gb9kT{i-ZM$p0r{y`HV#G8&Ft%TOkc3*qPP6pNg
zLORpGDnOSrC0?lb6V;~=PluX>p{!Zs6_8-+EcM=JfRYAN|Bv;Hf&zcZt}tYYB{p#l
zF-0wsh0X|FWL)PPMIjpc_Q3lB){g}K3yRpnn4sW)a%$zq;x|I;`WXd@ol~5Ny}A^C
zVS}$-*)ThFWY@Ly7l$(G9u4DOHSZl?IcwimOyo*&CS;HxbQXFMqa9N;oTGOXAz?G}
z8+M?%Rf@K1)Ziw(4Q)?A59WL?p*0bt3zzg37N2I
z3E~Gq?d8va5)#|pOrAj2(jU=Vc3;Fq<^-2$Bv@@e#q*zu8(iF>(EEpDNAJcJNgFaq
z5UY0vp(>0F1Ih5P$nYDF6b<6qQnCVOnKH@8kiej)#NY4Nek6mK*aP27jYKQn=QjLg
zN%hGlKv_Xaa^?^3L!XfNy9q#LHps$_a)+(wDgHeeub`&piRy_rT|kHeI@f~$B(s5|
z2I{Z2jVX^h@NDYzqlT&pr3x~4>}ua-%I8TEH}CrgETXp^<1G
zsdLgi0mH#deHF(~isY@JM=lN>o~;IuRxNbeUxLF<>S9pGsEK_LY3=x~K__sxtn8^-eNm2Zf~NfA7H=e1Qs147lpw~!GevUTtTFG0t{n4BbD?n7OqH2;EE~$#
z0M@v+$b1Os5PZ-5Qf~4FdHTxdEyk^N_k5uxlYZ*)#wW_RiW#0hjd|+7R|0)wC@hjV
z87w{3#)!XbXS}ub&a@*<#d^&0I&xZ?DCd_0qJnkJ4hVY*IkM^2kuF%lOa=xwV3a9@
z;tRLcYa&O_do8YfvP+5+F%)`C4#C|1dT~4U{JwT?0=Y#D!7YXH=?ujxPEZO%zK3c2
z*GPz5q{NcC9?gBGD~Ge`$+||CXUYSc$ckRTbyRWHQ+0upW)9N)B&M>2H$&85}7UOiRzpf~Y_=pvZ&Q&p%HkD!=^xce)`YEW@vW
zEJgXR+2e>Qe{lJlem<#o$u{d&0sh+6hkAC>;fSya6g3#6Nj;nLBm^I}t|faF@QXb3
z>I)ykOZ-Xyh|TVUK@{D7F;UmidJi1JFJWk}WoVQiti`&kZv)xPXhZ3Jo&o2ZiCur;
z0k@*J<)wtlQx-#bLD4Wb4J;(#^2EtP2>y8u;?<|6wO;F6e||1
z^>7}Nax+W~H$MZ$_I%<$gf7h)3Ud-qpQ0_SKE2
z#W|I>?AG;+E5ieYi~2_(f_|$HfD*<5R&iq^T{NXsd{vBoFW0V;>pE}FpjqPErf=4+
zW8_;20|y0>L4kA*l^YUop8?#Yt~R^FI>`DV-&67*ETw~ag&xKp=Ss}jfim}v
znj{=q=a@5I0w(fKi8*gsvmlMfkaO8jLHQjzXVT=?y9eB{jn=v&8&qAvlwQgvGgQu^
zn2)WWoEyWF+)E4ln`$U};-)$hc{UK6Dda@$^~@
z=pMB~Z+>)PUNgw#@cEE`Rs^PkRQsIe=7i1itS
zXwIeFPb=g&Fn*T^-x=wmXYFgXYb|wHshK_>`E}#9UlBXyX(Q|`_Lb+X9e-t&<{1zZ
zHJQqnRVlNTil_s%b5%jkz3}2!9M;TT^S;%`W1INl%jGU7SWo5qV8Jz%g_BaQ3?;s~
zFv^_RdE?q6lIMXlNn-gBE+l@Qrcb3T7slZVEAda6vXtv}9|;x!_ezAF$*>d6=Qn7MPNR}7R;
zz9l}Ilo9ba432`AKV%aWyp*sbdImJ5^B?KpSM8NW)k$tG6^q6WAmvAaJs6M`B{LBv
z0*_&C)W#`MNd`0}!Yk07tGjam_&hNWJ^kz6evQA@_mSZBxC9*<@`m?`zWPdA9`V{8Yc~KTrH!g!jiVKX_1|P
znegsCh0WXJH0|;$O-kMB?|tcgsgaek2?17Ic-10g`4wO?sg5A8gG8kf8kA1dU169#
zz`Zv8w@>pD%{V(GEG*2sP!U&p5Z1>#3N1!WU>Q9bIB{*5IJD3x@PnJx$|3MCM^`mIZF8xP;GvI!4KHjJkAfwe~mHM_HX
zg2s?305)E@eix$^^O>y|Ymz!O>{C>h#lZ7v#0K=33beFvOdtjR&1P65MFnzjqhr1c
z)Ks1hsJ?$uM{OkOfyT@;xZW$iXcLLdERx%pHPEUfxtYr#!GUJYZ8t4C^=ok@qaXgn
z%D}Jx(!PX@7bu8jE14-N-U|&L{1R8?Dz-1X{^}>C67$3Ul|kqR4?|5;wgDx}_p^tR
zmcg7BpD(Ds*2VqK-{HBB^Ct9RQgTsiuUgy)qsG^2@HU0(tOkc(;L`Q|rE>5yh(<+y
z_o`I3u|zI|$W|oLq>=S*>h2O*W2`r`rWm6N;ObpXJlnzG3gHe(5}_3lBSA9W-fOT{
z`R-Rbn}bP{w}eFM#?g2@xn!X9P&wi}pAR*i8m&+Mp`#Bbv+rm0y--#tOv7k=3K%*d
z(-3`#h(AvvP|xGCvOQRWv)y9mtY9K3WwzKlPV&BOt>38N{+MqhE
zbr4Hh9TI>^<>aMHqO#3MnF$qS
zq@V&V~jJond*CxQyw1&p*5F4LV>PZtB3
ze*FBm_WQz~WHI5fQ%*g$ta3wCao(4=b>FaVZP;XgP()4*8M#Om#1zoR@og^wbI1wb
zO+>oQ=y1#49{ki06o>3yeY%N|I{Q8IeS@BL!uh01D8d25ls|0HYvs7WUTNV&4wiPW
zRUX55W3FCFkR+At{zI)47Am?d;fhjy+#zv)g@)H8pWv_v&(^NmlS5jO+PQLFH|JU<
ziP%RlNw8w`M}-$aqA9!HHMm(lH9O#`&|ftwSMM@X;xERmUv2RlnmgM`O~8Y{#y9|$
zghR}JR|lEP*TMD#?1_Dan*}c(*o2+_hzTZO#OV!b;~zzN*G^`51vPlV&!`xi%Ka&u
zW?UMR#E^&Xj)tl*=u%zVGVD0v?Bm6b2aLW>@FVC7snQ{u08qU$0??Fa=Q-?-u4t4o
z4UGuoEMW*rwb6-+7kyI-J-
z>^X7toLai!6&c0`D2wx5@nsV~H@RVC5rkK%zogZ#3Qv79Nqg%^M2He=oZuDoWBz
z;H0EEt-YU-TmZhFL8^?xqR38Pf%b?Vw#yGG^Yut6$)EMY`pGI$BL+d^`Y%|Mq!lC%
zn<2lfW^ZI+#i8s;2dP^o-^b5Xqnsh<<4kuArQ2pb-!Xo|wKG29f)WFlawO-|ia2{J
z6frQwqnECq0k_m&NAC9V6R0yayK?OUTtT*+3Rr~dbVO;Cbqz{0B2CQaEV<(^U;KRr
z*!>BGB_ghHrJP`_{$9$SXqVy4!>T7dj|r!S|M|%tUF6#-C4*YoGG>TMpl0iJzb)a@
z)Ks6^q)KE^@%^K)ZV>z%HyZ6G3gWKsDey^%*}~yKk~@QWbPk%4nV^D4Ankh3SzJCD
z6&5|NSw3$5Vy9V4s41R1qfkua)ewd*wH9q*m;;+yB!#_5CK01XGD%!lrADHxXc-+;
zcma(unDGfw8xacCro%c^1%5Q~zg}mS*O8;YxUY?!9M$o%87AFe4~t?A#b!7N58oMv
z+Za;BsP-8Np;~;IIyf~*T${B)LUP%9)WH21%Qz|g8p|g$cuz9#M5L%7*%O2~6IuK}
DF~B#i
diff --git a/_notebooks/fastcore_imgs/td.png b/_notebooks/fastcore_imgs/td.png
deleted file mode 100644
index 8f45e479972766069fa722231f1f56e21a1b2450..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 148691
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