diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..5a3dbcf9 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: e21ba9a26a1fa041e43d0d2e9e34e5b6 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/_images/add-file.png b/_images/add-file.png new file mode 100644 index 00000000..9683b2db Binary files /dev/null and b/_images/add-file.png differ diff --git a/_images/annotate.png b/_images/annotate.png new file mode 100644 index 00000000..8021920a Binary files /dev/null and b/_images/annotate.png differ diff --git a/_images/annotate1.png b/_images/annotate1.png new file mode 100644 index 00000000..93416b2a Binary files /dev/null and b/_images/annotate1.png differ diff --git a/_images/bare-repository.png b/_images/bare-repository.png new file mode 100644 index 00000000..45286f93 Binary files /dev/null and b/_images/bare-repository.png differ diff --git a/_images/browse-files.png b/_images/browse-files.png new file mode 100644 index 00000000..5fcc3528 Binary files /dev/null and b/_images/browse-files.png differ diff --git a/_images/cheat-sheet.jpg b/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/_images/cheat-sheet.jpg differ diff --git a/_images/code-portion.png b/_images/code-portion.png new file mode 100644 index 00000000..39356bd5 Binary files /dev/null and b/_images/code-portion.png differ diff --git a/_images/commit-and-tree.png b/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/_images/commit-and-tree.png differ diff --git a/_images/commit-changes.png b/_images/commit-changes.png new file mode 100644 index 00000000..4c0546c6 Binary files /dev/null and b/_images/commit-changes.png differ diff --git a/_images/commits-and-parents.png b/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/_images/commits-and-parents.png differ diff --git a/_images/commits.png b/_images/commits.png new file mode 100644 index 00000000..b154c666 Binary files /dev/null and b/_images/commits.png differ diff --git a/_images/create-repository-with-readme.png b/_images/create-repository-with-readme.png new file mode 100644 index 00000000..24118344 Binary files /dev/null and b/_images/create-repository-with-readme.png differ diff --git a/_images/create-repository.png b/_images/create-repository.png new file mode 100644 index 00000000..80fb99c2 Binary files /dev/null and b/_images/create-repository.png differ diff --git a/_images/edit-file.png b/_images/edit-file.png new file mode 100644 index 00000000..f7527bd0 Binary files /dev/null and b/_images/edit-file.png differ diff --git a/_images/file-history.png b/_images/file-history.png new file mode 100644 index 00000000..5e42fbe9 Binary files /dev/null and b/_images/file-history.png differ diff --git a/_images/fork.png b/_images/fork.png new file mode 100644 index 00000000..0c992d3d Binary files /dev/null and b/_images/fork.png differ diff --git a/_images/forking.png b/_images/forking.png new file mode 100644 index 00000000..73c4d71a Binary files /dev/null and b/_images/forking.png differ diff --git a/_images/git-annotate.png b/_images/git-annotate.png new file mode 100644 index 00000000..60c6f7c2 Binary files /dev/null and b/_images/git-annotate.png differ diff --git a/_images/git-branch-1.svg b/_images/git-branch-1.svg new file mode 100644 index 00000000..4b735e40 --- /dev/null +++ b/_images/git-branch-1.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + m2 + + + m3 + + + m1 + + + + + main + + + + + HEAD + + + diff --git a/_images/git-branch-2.svg b/_images/git-branch-2.svg new file mode 100644 index 00000000..dde628b6 --- /dev/null +++ b/_images/git-branch-2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l1 + + + e2 + + + e1 + + + m5 + + + m4 + + + m2 + + + m3 + + + m1 + + + + + less-salt + + + + + HEAD + + + + + experiment + + + + + main + + + diff --git a/_images/git-branch-3.svg b/_images/git-branch-3.svg new file mode 100644 index 00000000..19231579 --- /dev/null +++ b/_images/git-branch-3.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + e2 + + + m3 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + + + less-salt + + + + + experiment + + + diff --git a/_images/git-collaborative.svg b/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/_images/git-deleted-branches.svg b/_images/git-deleted-branches.svg new file mode 100644 index 00000000..d54c0032 --- /dev/null +++ b/_images/git-deleted-branches.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + m5 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + diff --git a/_images/git-log-github.png b/_images/git-log-github.png new file mode 100644 index 00000000..db44d29b Binary files /dev/null and b/_images/git-log-github.png differ diff --git a/_images/git-log-terminal.png b/_images/git-log-terminal.png new file mode 100644 index 00000000..56493e6e Binary files /dev/null and b/_images/git-log-terminal.png differ diff --git a/_images/git-merge-1.svg b/_images/git-merge-1.svg new file mode 100644 index 00000000..005301ab --- /dev/null +++ b/_images/git-merge-1.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + m3 + + + l1 + + + m7 + + + m4 + + + + + experiment + + + + + less-salt + + + + + main + + + + + HEAD + + + diff --git a/_images/git-merge-2.svg b/_images/git-merge-2.svg new file mode 100644 index 00000000..cb268ee7 --- /dev/null +++ b/_images/git-merge-2.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + l1 + + + m5 + + + m4 + + + + + experiment + + + + + main + + + + + HEAD + + + + + less-salt + + + diff --git a/_images/git-pre-ff.svg b/_images/git-pre-ff.svg new file mode 100644 index 00000000..e4d8bc5b --- /dev/null +++ b/_images/git-pre-ff.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e1 + + + e2 + + + m7 + + + m8 + + + n3 + + + n1 + + + m5 + + + l1 + + + m6 + + + m4 + + + n2 + + + m2 + + + m3 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + main + + + diff --git a/_images/git_stage_commit.svg b/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_images/github-branches-overview.png b/_images/github-branches-overview.png new file mode 100644 index 00000000..89e0058d Binary files /dev/null and b/_images/github-branches-overview.png differ diff --git a/_images/github-branches.png b/_images/github-branches.png new file mode 100644 index 00000000..3a6a8ff9 Binary files /dev/null and b/_images/github-branches.png differ diff --git a/_images/github-comparing-changes.png b/_images/github-comparing-changes.png new file mode 100644 index 00000000..735b990b Binary files /dev/null and b/_images/github-comparing-changes.png differ diff --git a/_images/github-contribute.png b/_images/github-contribute.png new file mode 100644 index 00000000..a149e9f3 Binary files /dev/null and b/_images/github-contribute.png differ diff --git a/_images/github-create-branch.png b/_images/github-create-branch.png new file mode 100644 index 00000000..e7958ff2 Binary files /dev/null and b/_images/github-create-branch.png differ diff --git a/_images/github-create-tag.png b/_images/github-create-tag.png new file mode 100644 index 00000000..f08f5878 Binary files /dev/null and b/_images/github-create-tag.png differ diff --git a/_images/github-merged.png b/_images/github-merged.png new file mode 100644 index 00000000..eea47d93 Binary files /dev/null and b/_images/github-merged.png differ diff --git a/_images/github-navigate-to-branch.png b/_images/github-navigate-to-branch.png new file mode 100644 index 00000000..42b0f753 Binary files /dev/null and b/_images/github-navigate-to-branch.png differ diff --git a/_images/gophers.png b/_images/gophers.png new file mode 100644 index 00000000..741406ba Binary files /dev/null and b/_images/gophers.png differ diff --git a/_images/history.png b/_images/history.png new file mode 100644 index 00000000..6384e302 Binary files /dev/null and b/_images/history.png differ diff --git a/_images/history1.png b/_images/history1.png new file mode 100644 index 00000000..06662c31 Binary files /dev/null and b/_images/history1.png differ diff --git a/_images/license.png b/_images/license.png new file mode 100644 index 00000000..f4cadf0d Binary files /dev/null and b/_images/license.png differ diff --git a/_images/meld.png b/_images/meld.png new file mode 100644 index 00000000..774f9cd1 Binary files /dev/null and b/_images/meld.png differ diff --git a/_images/mergetool.png b/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/_images/mergetool.png differ diff --git a/_images/network.png b/_images/network.png new file mode 100644 index 00000000..e0fcb2fb Binary files /dev/null and b/_images/network.png differ diff --git a/_images/new-repo-form.png b/_images/new-repo-form.png new file mode 100644 index 00000000..b808ee0b Binary files /dev/null and b/_images/new-repo-form.png differ diff --git a/_images/new-repo-plus.png b/_images/new-repo-plus.png new file mode 100644 index 00000000..e58ba5d8 Binary files /dev/null and b/_images/new-repo-plus.png differ diff --git a/_images/new-repository.png b/_images/new-repository.png new file mode 100644 index 00000000..aff76772 Binary files /dev/null and b/_images/new-repository.png differ diff --git a/_images/pen-symbol.png b/_images/pen-symbol.png new file mode 100644 index 00000000..044902a3 Binary files /dev/null and b/_images/pen-symbol.png differ diff --git a/_images/preview.png b/_images/preview.png new file mode 100644 index 00000000..8a602b66 Binary files /dev/null and b/_images/preview.png differ diff --git a/_images/search.png b/_images/search.png new file mode 100644 index 00000000..4462f71e Binary files /dev/null and b/_images/search.png differ diff --git a/_images/search1.png b/_images/search1.png new file mode 100644 index 00000000..89c0e25a Binary files /dev/null and b/_images/search1.png differ diff --git a/_images/show.png b/_images/show.png new file mode 100644 index 00000000..12d7915c Binary files /dev/null and b/_images/show.png differ diff --git a/_images/staging-basics.svg b/_images/staging-basics.svg new file mode 100644 index 00000000..13df8bf5 --- /dev/null +++ b/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + restore + add + commit + restore + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/_images/stranger.jpg b/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/_images/stranger.jpg differ diff --git a/_images/upload-files.png b/_images/upload-files.png new file mode 100644 index 00000000..fd3ef8cc Binary files /dev/null and b/_images/upload-files.png differ diff --git a/_images/vscode-add-and-commit.png b/_images/vscode-add-and-commit.png new file mode 100644 index 00000000..d9a09c46 Binary files /dev/null and b/_images/vscode-add-and-commit.png differ diff --git a/_images/vscode-authorize.png b/_images/vscode-authorize.png new file mode 100644 index 00000000..4d45dc2d Binary files /dev/null and b/_images/vscode-authorize.png differ diff --git a/_images/vscode-change-branch.png b/_images/vscode-change-branch.png new file mode 100644 index 00000000..c1a5f00a Binary files /dev/null and b/_images/vscode-change-branch.png differ diff --git a/_images/vscode-create-branch.png b/_images/vscode-create-branch.png new file mode 100644 index 00000000..71b275a9 Binary files /dev/null and b/_images/vscode-create-branch.png differ diff --git a/_images/vscode-merging.png b/_images/vscode-merging.png new file mode 100644 index 00000000..7e5880e7 Binary files /dev/null and b/_images/vscode-merging.png differ diff --git a/_images/vscode-open-terminal.png b/_images/vscode-open-terminal.png new file mode 100644 index 00000000..1be92267 Binary files /dev/null and b/_images/vscode-open-terminal.png differ diff --git a/_images/vscode-publish-to-github1.png b/_images/vscode-publish-to-github1.png new file mode 100644 index 00000000..883e756c Binary files /dev/null and b/_images/vscode-publish-to-github1.png differ diff --git a/_images/vscode-publish-to-github2.png b/_images/vscode-publish-to-github2.png new file mode 100644 index 00000000..d0055db4 Binary files /dev/null and b/_images/vscode-publish-to-github2.png differ diff --git a/_images/vscode-publish-to-github3.png b/_images/vscode-publish-to-github3.png new file mode 100644 index 00000000..0f68d0ee Binary files /dev/null and b/_images/vscode-publish-to-github3.png differ diff --git a/_images/vscode-start.png b/_images/vscode-start.png new file mode 100644 index 00000000..e7830807 Binary files /dev/null and b/_images/vscode-start.png differ diff --git a/_sources/aliases.md.txt b/_sources/aliases.md.txt new file mode 100644 index 00000000..a257a1b7 --- /dev/null +++ b/_sources/aliases.md.txt @@ -0,0 +1,156 @@ +(aliases)= + +# Aliases and configuration + +```{objectives} +- Learn to use aliases for most common commands. +``` + +Are you getting tired of typing so much? In Git you can define aliases (shortcuts): +- These are great because they can save you time typing. +- But it's easy to forget them, get confused, or be inconsistent with your colleagues. + +There is plenty of other configuration for Git, that can make it nicer. + + +## Aliases + +- Aliases offer a way to improve the usability of Git: for + example `git ci` instead of `git commit`. +- Aliases are based on simple string replacement in the command. +- Aliases can either be specific to a repository or global. + - Global aliases help you do the things you are used to across Git projects. + - Per-project aliases can also be created. +- Global aliases are stored in `~/.gitconfig`. + + +## Example alias: git graph + +A very useful shortcut which we use a lot in our workshops: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ cd your_git_repository +$ git graph +``` + + +## Using external commands + +It is possible to call external commands using the exclamation mark character "!". +In this example here we create a local alias which is +stored in `.git/config` and not synchronized with remotes: + +```console +$ cd your_git_repository +$ git config alias.hi '!echo hello' +$ git hi +``` + +```{discussion} Food for thought: When to alias? +- How many times should you wait before aliasing a command? +- Do you believe a list of generic two-letter acronyms for common commands will + save your time? +``` + + +## List of aliases the instructors use + +You are welcome to reuse, suggest, improve. +You can see your current aliases in `~/.gitconfig`. + +```console +$ git config --global alias.ap "add --patch" +$ git config --global alias.br branch +$ git config --global alias.ci "commit -v" +$ git config --global alias.cip "commit --patch -v" +$ git config --global alias.cl "clone --recursive" +$ git config --global alias.di diff +$ git config --global alias.dic "diff --staged --color-words" +$ git config --global alias.diw "diff --color-words" +$ git config --global alias.dis "!git --no-pager diff --stat" +$ git config --global alias.fe fetch +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ git config --global alias.rem remote +$ git config --global alias.st status +$ git config --global alias.su "submodule update --init --recursive" +``` + +Here is what they do: +- `ap`: add, selecting parts individually, interactively. +- `br`: branch (obvious) +- `ci`: commit (check in), with `-v` option for clarity +- `cip`: commit, selecting parts individually, interactively. +- `cl`: clone, init submodules (submodules are an advanced topic) +- `di`: diff (obvious) +- `dic`: diff of staging area vs last commit (what is about to be committed) +- `diw`: a word diff, color. Useful for small changes. +- `dis`: a "diffstat": what files are changed, not contents +- `fe`: fetch (obvious) +- `graph`: show whole git graph (so useful, some of us call it `l`) +- `rem`: remote (obvious) +- `st`: status (obvious) +- `su`: submodule update (advanced) + +A useful setting for the `p` aliases: +```console +$ git config --global interactive.singlekey true +``` + + +## Advanced aliases + +These are advanced aliases and configuration options. We won't explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages! + +```console +$ git config --global alias.cif "commit -v -p --fixup" +$ git config --global alias.rb "rebase --autosquash" +$ git config --global alias.rbi "rebase --interactive --autosquash" +$ git config --global alias.rbis "rebase --interactive --autosquash --autostash" +$ git config --global alias.rbs "rebase --autosquash --autostash" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard" +$ git config --global alias.new "log HEAD..HEAD@{upstream}" +$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}" +$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}" +$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all" +$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD" +$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat" +``` + +## Advanced Git configuration + +Besides aliases, you can do plenty of other configuration of `git`. +Here are some of the most common ones: + +```console +$ git config --global interactive.singlekey true +$ git config --global core.pager "less -RS" +$ git config --global core.excludesfile ~/.gitignore +$ git config --global merge.conflictstyle diff3 +$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]" +$ git config --global diff.mnemonicPrefix true +``` + +Do you get tired of typing and copying and pasting your remote names +all the time, like `git@github.com:myusername`? You can create remote +aliases like this: + +```console +$ git config --global url.git@github.com:.insteadOf gh: +$ git config --global url.git@github.com:/username/.insteadOf ghu: +``` + +Then, when you add a remote `ghu:recipe`, it will automatically be +translated to `git@github.com:/username/recipe` using a simple prefix +matching. + + +```{keypoints} +- If you are frustrated about remembering a command, you should create an alias. +``` diff --git a/_sources/archaeology.md.txt b/_sources/archaeology.md.txt new file mode 100644 index 00000000..c8fade0f --- /dev/null +++ b/_sources/archaeology.md.txt @@ -0,0 +1,488 @@ +# Inspecting history + +:::{objectives} +- Be able find a line of code, find out why it was introduced and when. +- Be able to quickly find the commit that changed a behavior. +::: + +:::{instructor-note} +- 30 min teaching/type-along +- 20 min exercise +::: + + +## Command line, GitHub, and VS Code + +As usual, we offer ways to do this with the command line, VS Code, and +GitHub. + +* **Command line** is most powerful and relatively easy with this. + You may also use it along with other things. If you haven't tried + it yet, we'd recommend you to give it a try. +* The **GitHub** web interface allows many things to be done, but not + everything. +* **VS Code** allows some of these, but for some it's easier to open + the VS Code terminal and run git there. + + +## Our toolbox for history inspection + +:::{instructor-note} +First the instructor demonstrates few commands on a real life example +repository (mentioned in the amazing site [The +Programming Historian](https://programminghistorian.org/)). +Later we will practice these in an archaeology exercise (below). +::: + + +### Warm-up: ["Git History" browser](https://githistory.xyz/) + +As a warm-up we can try the ["Git History" browser](https://githistory.xyz/) +on the README.rst file of the [networkx](https://github.com/networkx/networkx) repository: + +- Visit and browse (use left/right keys). +- You can try this on some of your GitHub repositories, too! + + +### Searching text patterns in the repository + +With `git grep` you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or +some error message printed. + +:::::{tabs} + ::::{group-tab} Command line + The Git command is as described above: + ```console + $ git grep TEXT + $ git grep "some text with spaces" + ``` + + In the [networkx](https://github.com/networkx/networkx) repository you can try: + + ```console + $ git clone https://github.com/networkx/networkx + $ cd networkx + $ git grep -i fixme + ``` + + While `git grep` searches the **current state** of the repository, + it is also possible to search through all changes with `git log -S sometext` + which can be useful to find where something got removed. + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/search.png + :alt: Searching for "fixme" in a GitHub repository + :width: 100% + :class: with-border + + Searching for "fixme" in a GitHub repository. + ``` + :::: + + ::::{group-tab} VS Code + Our example repository is . + From a new VS Code window, select "Clone Git repository" and enter + that URL. + + Searching with the magnifying glass from the left sidebar is + equivalent to `git grep`. + :::: +::::: + + +### Inspecting individual commits + +:::::{tabs} + ::::{group-tab} Command line + We have seen this one before already. Using `git show` we can inspect an individual commit if + we know its hash: + + ```console + $ git show HASH + ``` + + For instance: + ```console + $ git show 759d589bdfa61aff99e0535938f14f67b01c83f7 + ``` + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/show.png + :alt: Inspecting an individual commit on GitHub + :width: 100% + :class: with-border + + Inspecting an individual commit on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + We don't know of a built-in way to see every single Git commit in + order (extensions allow this). You can open the terminal and run + the command line option. + + But, if you open single files, a "Timeline" view under the + explorer shows changes to *that file*. You can click on a change + to see the details. + :::: +::::: + + +### Line-by-line code annotation with metadata + +With `git annotate` you can see line by line who and **when** the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility. + +:::::{tabs} + ::::{group-tab} Command line + ```console + $ git annotate FILE + ``` + + Example: + ```console + $ git annotate networkx/convert_matrix.py + ``` + + If you annotate in a terminal and the file is longer than the screen, Git by default uses the program `less` to + scroll the output. + Use `/sometext` `` to find "sometext" and you can cycle through the results with `n` (next) and `N` (last). + You can also use page up/down to scroll. You can quit with `q`. + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/annotate.png + :alt: Screenshot of file annotation on GitHub + :width: 100% + :class: with-border + + Screenshot of file annotation on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + It seems this needs an extension. We'd recommend trying the + command line method for now. + :::: +::::: + +:::{discussion} +Discuss how these relatively trivial changes affect the annotation: +- Wrapping long lines of text/code into shorter lines +- Auto-formatting tools such as `black` +- Editors that automatically remove trailing whitespace +::: + + +### Inspecting code in the past + +:::::{tabs} + ::::{group-tab} Command line + We can create branches pointing to a commit in the past. + This is the recommended mechanism to inspect old code: + + ```console + $ git switch --create BRANCHNAME HASH + ``` + + Example (lines starting with "#" are only comments): + + ```console + $ # create branch called "older-code" from hash 347e6292419b + $ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9 + + $ # now you can navigate and inspect the code as it was back then + $ # ... + + $ # after we are done we can switch back to "main" + $ git switch main + + $ # if we like we can delete the "older-code" branch + $ git branch -d older-code + ``` + + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + + ```console + $ git checkout -b BRANCHNAME SOMEHASH + ``` + :::: + + ::::{group-tab} GitHub + We now know how to visit a specific commit: + + + Once we are there we can "Browse files" at that point in history. + + ```{figure} img/archaeology/browse-files.png + :alt: Browsing code in the past on GitHub + :width: 100% + :class: with-border + + Browsing code in the past on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + Switch to "Source Control", then the "..." menu, then "Branch", then "Create new branch from..." and now you can type a commit identifier (hash). + + Make sure you change back to the main branch when you are done. + :::: +::::: + + +## Exercise + +This is described with the command line method, but by looking above +you can translate to the other options. + +:::::{exercise} Exercise: Explore basic archaeology commands (20 min) + Let us explore the value of these commands in an exercise. Future + exercises do not depend on this, so it is OK if you do not complete + it fully. + + Exercise steps: + - **Make sure you are not inside another Git repository** when running this + exercise. If you are, first step "outside" of it. + We want to avoid creating a Git repository inside another Git repository. + :::::{tabs} + ::::{group-tab} Command line + You can check if you are inside a Git repository with: + ```console + $ git status + + fatal: not a git repository (or any of the parent directories): .git + ``` + You want to see the above message which tells us that this is not a Git repository. + :::: + + ::::{group-tab} GitHub + This is not a problem in the GitHub web interface since we are not + creating a new local repository. + :::: + + ::::{group-tab} VS Code + "File" -> "New Window". + :::: + ::::: + + - Clone this repository: + . + :::::{tabs} + ::::{group-tab} Command line + ```console + $ git clone https://github.com/networkx/networkx.git + ``` + :::: + + ::::{group-tab} GitHub + Nothing to clone. We will try to inspect the repository directly on GitHub. + :::: + + ::::{group-tab} VS Code + From a new VS Code window, select "Clone Git repository" and enter + that URL. + :::: + ::::: + + - Then let us all **make sure we are working on a well-defined version** of the repository. + :::::{tabs} + ::::{group-tab} Command line + Step into the new directory and create an exercise branch from the + networkx-2.6.3 tag/release: + ```console + $ cd networkx + $ git switch --create exercise networkx-2.6.3 + ``` + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + ```console + $ git checkout -b exercise networkx-2.6.3 + ``` + :::: + + ::::{group-tab} GitHub + We can visit the version directly: + :::: + + ::::{group-tab} VS Code + Switch to "Source Control", then the "..." menu, then "Branch", then "Create new branch from..." and select "networkx-2.6.3". + :::: + ::::: + + Then using the above toolbox try to: + 1. Find the code line which contains `"Logic error in degree_correlation"`. + 1. Find out when this line was last modified or added. Find the actual commit which modified that line. + 1. Inspect that commit with `git show`. + 1. Create a branch pointing to the past when that commit was created to be + able to browse and use the code as it was back then. + 1. How would you bring the code to the version of the code right before that line was last modified? + + ::::{solution} + We provide here a solution for the command line but we also encourage you to + try to solve this in the browser. + + 1. We use `git grep`: + ```console + $ git grep "Logic error in degree_correlation" + ``` + This gives the output: + ``` + networkx/algorithms/threshold.py: print("Logic error in degree_correlation", i, rdi) + ``` + Maybe you also want to know the line number: + ```console + $ git grep -n "Logic error in degree_correlation" + ``` + 2. We use `git annotate`: + ```console + $ git annotate networkx/algorithms/threshold.py + ``` + Then search for "Logic error" by typing "/Logic error" followed by Enter. + The last commit that modified it was `90544b4fa` (unless that line changed since). + 3. We use `git show`: + ```console + $ git show 90544b4fa + ``` + 4. Create a branch pointing to that commit (here we called the branch "past-code"): + ```console + $ git branch past-code 90544b4fa + ``` + 5. This is a compact way to access the first parent of `90544b4fa` (here we + called the branch "just-before"): + ```console + $ git switch --create just-before 90544b4fa~1 + ``` + :::: +::::: + +--- + +## Finding out when something broke/changed with `git bisect` + +This only works with the command line. + +> *"But I am sure it used to work! Strange."* + +Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke. + +:::{discussion} How would you solve this? +Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now. + +- How would you find the commit which changed it? +- Why could it be useful to know the commit that changed it? +::: + +We will probably arrive at a solution which is similar to `git bisect`: + +- First find out a commit in past when it worked. + ```console + $ git bisect start + $ git bisect good f0ea950 # this is a commit that worked + $ git bisect bad main # last commit is broken + ``` +- Now compile and/or run and/or test and decide whether "good" or "bad". +- This is how you can tell Git that this was a working commit: + ```console + $ git bisect good + ``` +- And this is how you can tell Git that this was not a working commit: + ```console + $ git bisect bad + ``` +- Then bisect/iterate your way until you find the commit that broke it. +- If you want to go back to start, type `git bisect reset`. +- This can even be automatized with `git bisect run SCRIPT`. + For this you write a script that returns zero/non-zero (success/failure). + + +(exercise-bisect)= + +## Optional exercise: Git bisect + +This only works with the command line. + +::::{exercise} (optional) History-2: Use git bisect to find the bad commit + In this exercise, we use `git bisect` on an example repository. It + is OK if you do not complete this exercise fully. + + Begin by cloning [https://github.com/coderefinery/git-bisect-exercise](https://github.com/coderefinery/git-bisect-exercise). + + + **Motivation** + + The motivation for this exercise is to be able to do archaeology with Git on a + source code where the bug is difficult to see visually. **Finding the offending + commit is often more than half the debugging**. + + + **Background** + + The script `get_pi.py` approximates pi using terms of the Nilakantha series. It + should produce 3.14 but it does not. The script broke at some point and + produces 3.57 using the last commit: + + ```console + $ python get_pi.py + + 3.57 + ``` + + At some point within the 500 first commits, an error was introduced. The only + thing we know is that the first commit worked correctly. + + + **Your task** + + - Clone this repository and use `git bisect` to find the commit which + broke the computation + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + - Once you have found the offending commit, also practice navigating to the last good commit. + - Bonus exercise: + Write a script that checks for a correct result and use `git bisect run` to + find the offending commit automatically + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + + + **Hints** + + Finding the first commit: + + ```console + $ git log --oneline | tail -n 1 + ``` + + How to navigate to the parent of a commit with hash SOMEHASH: + ```console + $ git switch --create BRANCHNAME SOMEHASH~1 + ``` + + Instead of a tilde you can also use this: + ```console + $ git switch --create BRANCHNAME SOMEHASH^ + ``` +:::: + + +## Summary + +- git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project on the command line. +- `git switch --create NAME HASH` is the recommended mechanism to inspect old code on the command line. +- Most of these commands can be used in the GitHub web interface (except `git bisect`). diff --git a/_sources/basics.md.txt b/_sources/basics.md.txt new file mode 100644 index 00000000..fb56e9ca --- /dev/null +++ b/_sources/basics.md.txt @@ -0,0 +1,715 @@ +# Basics + +```{objectives} +- Learn to create Git repositories and make commits. +- Get a grasp of the structure of a repository. +- Learn how to inspect the project history. +- Learn how to write useful commit log messages. +``` + +```{instructor-note} +- 35 min teaching/type-along +- 40 min exercise +``` + + +## What is Git, and what is a Git repository? + +- Git is a version control system: can **record/save snapshots** and track the content of a folder as it changes over time. +- Every time we **commit** a snapshot, Git records a snapshot of the **entire project**, saves it, and assigns it a version. +- These snapshots are kept inside a sub-folder called `.git`. +- If we remove `.git`, we remove the repository and history (but keep the working directory!). +- The directory `.git` uses relative paths - you can move the whole repository somewhere else and it will still work. +- Git doesn't do anything unless you ask it to (it **does not record anything automatically**). +- Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces). + + +## Recording a snapshot with Git + +- Git takes snapshots only if we request it. +- We will record changes in two steps (we will later explain why this is a recommended practice). +- Example (we don't need to type yet): + + ```console + $ git add FILE.txt + $ git commit + + $ git add FILE.txt ANOTHERFILE.txt + $ git commit + ``` + +- We first focus (`git add`, we "stage" the change), then record (`git commit`): + +```{figure} img/git_stage_commit.svg +:alt: Git staging +:width: 100% + +Git staging and committing. +``` + +```{discussion} Question for the more advanced participants +What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end. +``` + + +## Configuring Git command line + +Before we start using Git on the command line, we need to configure Git. +This is also part of the +[installation instructions](https://coderefinery.github.io/installation/shell-and-git/#configuration) +but we need to make sure we all have +set name, email address, editor, and +default branch: +```console +$ git config --global user.name "Your Name" +$ git config --global user.email yourname@example.com +$ git config --global core.editor nano +$ git config --global init.defaultBranch main +``` + +Verify with: +```console +$ git config --list +``` + +```{instructor-note} +Instructors, give learners enough time to do the above configuration steps. +``` + + +## Type-along: Tracking a guacamole recipe with Git + +We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list) + +The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language. + +```{instructor-note} +Instructors, please encourage now that participants type along. +``` + +```{note} +It is possible to go through this lesson in the command line or in the browser +(on GitHub). + +- We recommend to start with the command line but later to also try in the browser. +- If you get really stuck in the command line, try following in the browser and + later you can try to return to the command line. +``` + + +## Creating a repository + +One of the basic principles of Git is that it is **easy to create repositories**: + +`````{tabs} + ````{group-tab} Command line + ```console + $ mkdir recipe + $ cd recipe + $ git init -b main + ``` + + That's it! With `git init -b main` have now created an empty Git repository + where `main` is the default branch (more about branches later). + + We will use `git status` a lot to check out what is going on: + + ```console + $ git status + + On branch main + + No commits yet + + nothing to commit (create/copy files and use "git add" to track) + ``` + + We will make sense of this information during this workshop. + ```` + + ````{group-tab} Browser (GitHub) + First log into GitHub, then follow the screenshots and descriptions below. + + ```{figure} img/basics/new-repo-plus.png + :alt: Screenshot on GitHub before a new repository form is opened + :width: 100% + :class: with-border + + Click on the "plus" symbol on top right, then on "New repository". + ``` + + Another way to create a new repository is to visit + directly. + + ```{figure} img/basics/new-repo-form.png + :alt: Screenshot on GitHub just before creating a new repository + :width: 100% + :class: with-border + + Choose a repository name, add a short description, **check "Add a + README file"**, finally "Create repository". + ``` + + After you have clicked "Create repository" you should see a repository overview + with one file (README.md) and one commit. + ```` +````` + + +## Adding files and committing changes + +Let us now **create two files**. + +One file is called `ingredients.txt` and contains: +```shell +* 2 avocados +* 1 chili +* 1 lime +* 2 tsp salt +``` + +The second file is called `instructions.txt` and contains: +```shell +* chop avocados +* chop onion +* chop chili +* squeeze lime +* add salt +* and mix well +``` + +`````{tabs} + ````{group-tab} Command line + As mentioned above, in Git you can always check the status of files in your repository using + `git status`. It is always a safe command to run and in general a good idea to + do when you are trying to figure out what to do next: + + ```console + $ git status + + On branch main + + No commits yet + + Untracked files: + (use "git add ..." to include in what will be committed) + ingredients.txt + instructions.txt + + nothing added to commit but untracked files present (use "git add" to track) + ``` + + The two files are untracked in the repository (directory). You want to **add the files** (focus the camera) + to the list of files tracked by Git. Git does not track + any files automatically and you need make a conscious decision to add a file. Let's do what + Git hints at, and add the files, one by one: + + ```console + $ git add ingredients.txt + $ git status + + On branch main + + No commits yet + + Changes to be committed: + (use "git rm --cached ..." to unstage) + new file: ingredients.txt + + Untracked files: + (use "git add ..." to include in what will be committed) + instructions.txt + ``` + + Now this change is *staged* and ready to be committed. + Let us now commit the change to the repository: + ```console + $ git commit -m "adding ingredients" + + [main (root-commit) f146d25] adding ingredients + 1 file changed, 4 insertions(+) + create mode 100644 ingredients.txt + ``` + + Right after we query the status to get this useful command into our muscle memory: + ```console + $ git status + ``` + + Now stage and commit also the other file: + ```console + $ git add instructions.txt + $ git commit -m "adding instructions" + ``` + + We will add a third file to the repository, `README.md`, containing: + ```markdown + # recipe + + This is an exercise repository. + ``` + + Now stage and commit also the `README.md` file: + ```console + $ git add README.md + $ git commit -m "adding README" + ``` + + What does the `-m` flag mean? Let us check the help page for that command: + ```console + $ git help commit + ``` + + You should see a very long help page as the tool is very versatile (press q to quit). + Do not worry about this now but keep in mind that you can always read the help files + when in doubt. Searching online can also be useful, but choosing search terms + to find relevant information takes some practice and discussions in some + online threads may be confusing. + Note that help pages also work when you don't have a network connection! + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/add-file.png + :alt: Screenshot on GitHub before a new file is created + :width: 100% + :class: with-border + + Click on "Add file", then "Create new file". + ``` + + ```{figure} img/basics/edit-file.png + :alt: Screenshot on GitHub when editing a file + :width: 100% + :class: with-border + + Edit the file and specify the file name. + ``` + + ```{figure} img/basics/commit-changes.png + :alt: Screenshot on GitHub when editing the commit message + :width: 100% + :class: with-border + + Before you commit the change, adjust the commit message. + ``` + + After you have added `ingredients.txt`, add also `instructions.txt` in a similar + way. + + We have added two files, each in one commit. However, we ended up with + three files and three commits since `README.md` was automatically committed + when we created the repository on GitHub. + ```` +````` + + +(exercise-record-changes)= + +## Exercise: Record changes + +``````{exercise} Basic-1: Record changes + Add 1/2 onion to `ingredients.txt` and also the instruction + to "enjoy!" to `instructions.txt`. + + `````{tabs} + ````{group-tab} Command line + After modifying the files, do not stage the changes yet (do not `git add` + yet). + + When you are done editing the files, try `git diff`: + ```console + $ git diff + ``` + + You will see (can you identify in there the two added lines?): + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index 4422a31..ba8854f 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -2,3 +2,4 @@ + * 1 chili + * 1 lime + * 2 tsp salt + +* 1/2 onion + diff --git a/instructions.txt b/instructions.txt + index 7811273..2b11074 100644 + --- a/instructions.txt + +++ b/instructions.txt + @@ -4,3 +4,4 @@ + * squeeze lime + * add salt + * and mix well + +* enjoy! + ``` + + Now first stage and commit each change separately (what happens when we leave out the `-m` flag?): + ```console + $ git add ingredients.txt + $ git commit -m "add half an onion" + $ git add instructions.txt + $ git commit # <-- we have left out -m "..." + ``` + + When you leave out the `-m` flag, Git should open an editor where you can edit + your commit message. This message will be associated and stored with the + changes you made. This message is your chance to explain what you've done and + convince others (and your future self) that the changes you made were + justified. Write a message and save and close the file. + + When you are done committing the changes, experiment with these commands: + ```console + $ git log + $ git log --stat + $ git log --oneline + ``` + ```` + + ````{group-tab} Browser (GitHub) + We can make modifications to a file by clicking on the file and then the + pen symbol: + ```{figure} img/basics/pen-symbol.png + :alt: Screenshot on GitHub before clicking on the pen symbol + :width: 100% + :class: with-border + + By clicking on the pen symbol we can switch to edit mode. + ``` + + ```{figure} img/basics/preview.png + :alt: Screenshot on GitHub when previewing file changes + :width: 100% + :class: with-border + + Before committing the change, click on "Preview". + ``` + + Our goal is to arrive at two new commits: + - "add half an onion" (modifying `ingredients.txt`) + - "don't forget to enjoy" (modifying `instructions.txt`) + + When you are done committing the changes, try to browse commit history + on GitHub. + ```` + ````` +`````` + + +## Git history and log + +`````{tabs} + ````{group-tab} Command line + If you haven't yet, please try now `git log`: + + ```console + $ git log + + commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main) + Author: Radovan Bast + Date: Sun Sep 17 19:12:47 2023 +0200 + + don't forget to enjoy + + commit 79161b6e67c62ad4688a58c1e54183334611a390 + Author: Radovan Bast + Date: Sun Sep 17 19:12:32 2023 +0200 + + add half an onion + + commit a3394e39535343c4dae3bb4f703741a31aa8b78a + Author: Radovan Bast + Date: Sun Sep 17 18:47:14 2023 +0200 + + adding README + + commit 369624674e63de48055a65bf63055bd59c985d22 + Author: Radovan Bast + Date: Sun Sep 17 18:46:58 2023 +0200 + + adding instructions + + commit f146d25b94569a15e94d7f0da6f15d7554f76c49 + Author: Radovan Bast + Date: Sun Sep 17 18:35:52 2023 +0200 + + adding ingredients + ``` + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/commits.png + :alt: Screenshot on GitHub before clicking on commit history + :width: 100% + :class: with-border + + Click on the history symbol with (here) 5 commits. + ``` + + ```{figure} img/basics/history.png + :alt: Screenshot of GitHub repository commit history + :width: 100% + :class: with-border + + In this overview you can browse each commit individually. + ``` + + On GitHub you can also compare arbitrary two commits (replace "USER", + "HASH1", and "HASH2"): + `https://github.com/USER/recipe/compare/HASH1..HASH2` + + Try it with two of your commits. + ```` +````` + +- We can browse the development and access each state that we have committed. +- The long hashes uniquely label a state of the code. +- They are not just integers counting 1, 2, 3, 4, ... (why?). +- Output is in reverse chronological order, i.e. **newest commits on top**. +- We will use them when comparing versions and when going back in time. +- `git log --oneline` only shows the first 7 characters of the commit hash and is good to get an overview. +- If the first characters of the hash are unique it is not necessary to type the entire hash. +- `git log --stat` is nice to show which files have been modified. + + +(exercise-diff-and-rename)= + +## Optional exercises: Comparing changes + +``````{exercise} (optional) Basic-2: Comparing and showing commits + `````{tabs} + ````{group-tab} Command line + 1. Have a look at specific commits with `git show HASH`. + 2. Inspect differences between commit hashes with `git diff HASH1 HASH2`. + ```` + + ````{group-tab} Browser (GitHub) + 1. Have a look at specific commits. + 2. Inspect differences between commits. + + Use the screenshots under "Git history and log". + ```` + ````` +`````` + +````{exercise} (optional) Basic-3: Visual diff tools + This exercise is only relevant for the command line. In the browser, + the preview is already side-by-side and "visual". + + - Make further modifications and experiment with `git difftool` (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + On Windows or Linux: + ```console + $ git difftool --tool=meld HASH + ``` + + On macOS: + ```console + $ git difftool --tool=opendiff HASH + ``` + + ```{figure} img/meld.png + :alt: Git difftool using meld + :width: 100% + + Git difftool using meld. + ``` + + You probably want to use the same visual diff tool every time and + you can configure Git for that: + ```console + $ git config --global diff.tool meld + ``` +```` + +```{exercise} (optional) Basic-4: Browser and command line +You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both. + +- If you have managed to do the above in the command line, try now in the browser. +- If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git. +``` + + +## Writing useful commit messages + +Using `git log --oneline` or browsing a repository on the web, we better +understand that the first line of the commit message is very important. + +Good example: +```text +increase threshold alpha to 2.0 + +the motivation for this change is +to enable ... +... +this is based on a discussion in #123 +``` + +Convention: **one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary**. + +- **Why something was changed is more important than what has changed.** +- Cross-reference to issues and discussions if possible/relevant. +- Bad commit messages: "fix", "oops", "save work" +- Bad examples: [http://whatthecommit.com](http://whatthecommit.com) +- Write commit messages in English that will be understood + 15 years from now by someone else than you. Or by your future you. +- Many projects start out as projects "just for me" and end up to be successful projects + that are developed by 50 people over decades. +- [Commits with multiple authors](https://help.github.com/articles/creating-a-commit-with-multiple-authors/) are possible. + +Good references: + +- ["My favourite Git commit"](https://fatbusinessman.com/2019/my-favourite-git-commit) +- ["On commit messages"](https://who-t.blogspot.com/2009/12/on-commit-messages.html) +- ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) + +```{note} +A great way to learn how to write commit messages and to get inspired by their +style choices: **browse repositories of codes that you use/like**: + +Some examples (but there are so many good examples): +- [SciPy](https://github.com/scipy/scipy/commits/main) +- [NumPy](https://github.com/numpy/numpy/commits/main) +- [Pandas](https://github.com/pandas-dev/pandas/commits/main) +- [Julia](https://github.com/JuliaLang/julia/commits/master) +- [ggplot2](https://github.com/tidyverse/ggplot2/commits/main), + compare with their [release + notes](https://github.com/tidyverse/ggplot2/releases) +- [Flask](https://github.com/pallets/flask/commits/main), + compare with their [release + notes](https://github.com/pallets/flask/blob/main/CHANGES.rst) + +When designing commit message styles consider also these: +- How will you easily generate a changelog or release notes? +- During code review, you can help each other improving commit messages. +``` + +But remember: it is better to make any commit, than no commit. Especially in small projects. +**Let not the perfect be the enemy of the good enough**. + + +## Ignoring files and paths with .gitignore + +```{discussion} +- Should we add and track all files in a project? +- How about generated files? +- Why is it considered a bad idea to commit compiled binaries to version control? +- What types of generated files do you know? +``` + +Compiled and generated files are not +committed to version control. There are many reasons for this: + +- These files can make it more difficult to run on different platforms. +- These files are automatically generated and thus do not contribute in any meaningful way. +- When tracking generated files you could see differences in the code although you haven't touched the code. + +For this we use `.gitignore` files. Example: +```shell +# ignore compiled python 2 files +*.pyc +# ignore compiled python 3 files +__pycache__ +``` + +An example taken from the [official Git documentation](https://git-scm.com/docs/gitignore): +```shell +# ignore objects and archives, anywhere in the tree. +*.[oa] +# ignore generated html files, +*.html +# except foo.html which is maintained by hand +!foo.html +# ignore everything under build directory +build/ +``` + +- `.gitignore` should be part of the repository because we want to make sure that all developers see the same behavior. +- **All files should be either tracked or ignored**. +- `.gitignore` uses something called a + [shell glob syntax](https://en.wikipedia.org/wiki/Glob_(programming)) for + determining file patterns to ignore. You can read more about the syntax in the + [documentation](https://git-scm.com/docs/gitignore). +- You can have `.gitignore` files in lower level directories and they affect the paths below. + + +## Graphical user interfaces + +We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI): + +- [GitHub Desktop](https://desktop.github.com) +- [SourceTree](https://www.sourcetreeapp.com) +- [List of third-party GUIs](https://git-scm.com/downloads/guis) + + +## Summary + +Now we know how to save snapshots: + +```console +$ git add FILE(S) +$ git commit +``` + +And this is what we do as we program. + +Every state is then saved and later we will learn how to go back to these "checkpoints" +and how to undo things. + +```console +$ git init -b main # initialize new repository (main is default branch) +$ git add # add files or stage file(s) +$ git commit # commit staged file(s) +$ git status # see what is going on +$ git log # see history +$ git diff # show unstaged/uncommitted modifications +$ git show # show the change for a specific commit +$ git mv # move/rename tracked files +$ git rm # remove tracked files +``` + +Git is not ideal for large binary files +(for this consider [git-annex](http://git-annex.branchable.com)). + +````{challenge} Basic-5: Test your understanding + Which command(s) below would save the changes of `myfile.txt` + to an existing local Git repository? + + 1. ```console + $ git commit -m "my recent changes" + ``` + 2. ```console + $ git init myfile.txt + $ git commit -m "my recent changes" + ``` + 3. ```console + $ git add myfile.txt + $ git commit -m "my recent changes" + ``` + 4. ```console + $ git commit -m myfile.txt "my recent changes" + ``` + ```{solution} + + 1. Would only create a commit if files have already been staged. + 2. Would try to create a new repository in a folder "myfile.txt". + 3. **Is correct: first add the file to the staging area, then commit.** + 4. Would try to commit a file "my recent changes" with the message myfile.txt. + ``` +```` + +```{keypoints} +- It takes only one command to initialize a Git repository: `git init -b main`. +- Commits should be used to tell a story. +- Git uses the .git folder to store the snapshots. +- Don't be afraid to stage and commit often. Better too often than not often enough. +``` diff --git a/_sources/branches.md.txt b/_sources/branches.md.txt new file mode 100644 index 00000000..418e4d67 --- /dev/null +++ b/_sources/branches.md.txt @@ -0,0 +1,624 @@ +# Branching and merging + +```{objectives} +- Be able to create and merge branches. +- Know the difference between a branch and a tag. +``` + +```{instructor-note} +- 30 min teaching/type-along +- 20 min exercise +``` + + +## Motivation for branches + +In the previous section we tracked a guacamole recipe with Git. + +Up until now our repository had only one branch with one commit coming +after the other: + +```{figure} img/gitink/git-branch-1.svg +:alt: Linear Git repository +:width: 40% + +Linear Git repository. +``` + +- Commits are depicted here as little boxes with abbreviated hashes. +- Here the branch `main` points to a commit. +- "HEAD" is the current position (remember the recording head of tape + recorders?). When we say `HEAD`, we mean those literal letters - + this isn't a placeholder for something else. +- When we talk about branches, we often mean all parent commits, not only the commit pointed to. + +**Now we want to do this:** + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +Software development is often not linear: + +- We typically need at least one version of the code to "work" (to compile, to give expected results, ...). +- At the same time we work on new features, often several features concurrently. + Often they are unfinished. +- We need to be able to separate different lines of work really well. + +The strength of version control is that it permits the researcher to **isolate +different tracks of work**, which can later be merged to create a composite +version that contains all changes: + +```{figure} img/gitink/git-collaborative.svg +:alt: Isolated tracks of work +:width: 100% + +Isolated tracks of work. +``` + +- We see branching points and merging points. +- Main line development is often called `main` or `master`. +- Other than this convention there is nothing special about `main` or `master`, it is a branch like any other. +- Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow). + +A group of commits that create a single narrative are called a **branch**. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. "fast sequence extraction" or "Python interface" or "fixing bug in +matrix inversion algorithm". + +````{admonition} **An important alias** +--- +class: important +--- + +We will now define an *alias* in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). **This is extensively used in the rest of this +and other lessons**: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` +```` + +```{instructor-note} +Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative. +``` + +Let us inspect the project history using the `git graph` alias: + +```console +$ git graph + +* e7cf023 (HEAD -> main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- We have a couple commits and only + one development line (branch) and this branch is called `main`. +- Commits are states characterized by a 40-character hash (checksum). +- `git graph` print abbreviations of these checksums. +- **Branches are pointers that point to a commit.** +- Branch `main` points to a commit (in this example it is `e7cf023efe382340e5284c278c6ae2c087dd3ff7` but on your computer + the hash will be different). +- `HEAD` is another pointer, it points to where we are right now (currently `main`) + +In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards. + + +## Creating and working with branches + +```{instructor-note} +We do the following part together. Encourage participants to type along. +``` + +```{admonition} It is possible to create and merge branches directly on GitHub +- However, we do not have screenshots for that in this episode +- But if you prefer to work in the browser, please try it +- Please contribute screenshots to this lesson +``` + +Let's create a branch called `experiment` where we add cilantro to `ingredients.txt` +(text after "#" are comments and not part of the command). + +```console +$ git branch experiment main # creates branch "experiment" from "main" +$ git switch experiment # switch to branch "experiment" +$ git branch # list all local branches and show on which branch we are +``` + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +- Verify that you are on the `experiment` branch (note that `git graph` also + makes it clear what branch you are on: `HEAD -> branchname`): + ```console + $ git branch + + * experiment + main + ``` + This command shows where we are, it does not create a branch. + +- Then add 2 tbsp cilantro **on top** of the `ingredients.txt`: + + ```{code-block} shell + --- + emphasize-lines: 1 + --- + * 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + * 2 tsp salt + * 1/2 onion + ``` + +- Stage this and commit it with the message "let us try with some cilantro". +- Then reduce the amount of cilantro to 1 tbsp, stage and commit again with "maybe little bit less cilantro". + +We have created **two new commits**: + +```{code-block} console +--- +emphasize-lines: 3-4 +--- +$ git graph + +* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro +* f6ec7b7 let us try with some cilantro +* e7cf023 (main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- The branch `experiment` is two commits ahead of `main`. +- We commit our changes to this branch. + + +(exercise-branches)= + +## Exercise: Create and commit to branches + +````{exercise} Branch-1: Create and commit to branches + In this exercise, you will create another new branch and few more commits. + We will use this in the next section, to practice + merging. **The goal of the exercise is to end up with 3 branches**. + + - Change to the branch `main`. + - Create another branch called `less-salt`. + - Note! makes sure you are on main branch when you create the `less-salt` branch. + - A safer way would be to explicitly mention to create from the main branch + as shown below: + ```console + $ git branch less-salt main + ``` + - Switch to the `less-salt` branch. + - On the `less-salt` branch reduce the amount of salt. + - Commit your changes to the `less-salt` branch. + + Use the same commands as we used above. + + We now have three branches (in this case `HEAD` points to `less-salt`): + + ```console + $ git branch + + experiment + * less-salt + main + + $ git graph + + * bf28166 (HEAD -> less-salt) reduce amount of salt + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 (main) don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + Here is a graphical representation of what we have created: + + ```{figure} img/gitink/git-branch-2.svg + ``` + + - Now switch to `main`. + - In a new commit, improve the `README.md` file (we added the word "Guacamole"): + + ```markdown + # Guacamole recipe + + This is an exercise repository. + ``` + + Now you should have this situation: + + ```console + $ git graph + + * b4af65b (HEAD -> main) improve the documentation + | * bf28166 (less-salt) reduce amount of salt + |/ + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + ```{figure} img/gitink/git-branch-3.svg + ``` + + And for comparison this is how it looks [on GitHub](https://github.com/coderefinery/recipe-before-merge/network). +```` + +(exercise-branches-merging)= + +## Exercise: Merging branches + +It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge `experiment` into `main`. + +```{exercise} Branch-2: Merge branches +Merge `experiment` and `less-salt` back into `main` following the lesson below +until the point where we start deleting branches. +``` + +````{admonition} If you got stuck in the above exercises or joined later + **If you got stuck in the above exercises or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git switch experiment + $ git switch less-salt + $ git switch main + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +First we make sure we are on the branch we wish to merge **into**: + +```{code-block} console +--- +emphasize-lines: 5 +--- +$ git branch + + experiment + less-salt +* main +``` + +Then we merge `experiment` into `main`: + +```console +$ git merge experiment +``` + +```{figure} img/gitink/git-merge-1.svg +``` + +We can verify the result: + +```console +$ git graph + +* 81fcc0c (HEAD -> main) Merge branch 'experiment' +|\ +| * bcb8b78 (experiment) maybe little bit less cilantro +| * f6ec7b7 let us try with some cilantro +* | b4af65b improve the documentation +|/ +| * bf28166 (less-salt) reduce amount of salt +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents. + +To view the branches that are merged into the current branch we can use the command: + +```console +$ git branch --merged + + experiment +* main +``` + +We are also happy with the work on the `less-salt` branch. Let us merge that +one, too, into `main`: + +```console +$ git branch # make sure you are on main +$ git merge less-salt +``` + +```{figure} img/gitink/git-merge-2.svg +:alt: Commit graph after merge + +Commit graph after merge. +``` + +We can verify the result in the terminal: + +```console +$ git graph + +* 4e03d4b (HEAD -> main) Merge branch 'less-salt' +|\ +| * bf28166 (less-salt) reduce amount of salt +* | 81fcc0c Merge branch 'experiment' +|\ \ +| * | bcb8b78 (experiment) maybe little bit less cilantro +| * | f6ec7b7 let us try with some cilantro +| |/ +* / b4af65b improve the documentation +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +Observe how Git nicely merged the changed amount of salt and the new ingredient **in the same file +without us merging it manually**: + +```console +$ cat ingredients.txt + +* 1 tbsp cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually *settle merge conflicts* (we will do that later). + + +## Deleting branches safely + +Both feature branches are merged: + +```console +$ git branch --merged + + experiment + less-salt +* main +``` + +This means we can delete the branches: + +```console +$ git branch -d experiment +$ git branch -d less-salt +``` + +This is the result: + +```{figure} img/gitink/git-deleted-branches.svg +:alt: Commit graph after merged branches were deleted + +Commit graph after merged branches were deleted. +``` + +We observe that when deleting branches, +only the pointers ("sticky notes") disappeared, not the commits. + +Git will not let you delete a branch which has not been reintegrated unless you +insist using `git branch -D`. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them. + + +(exercise-branches-optional)= + +## Optional exercises with branches + +The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section. + +````{exercise} (optional) Branch-3: Perform a fast-forward merge +1. Create a new branch from `main` and switch to it. +2. Create a couple of commits on the new branch (for instance edit `README.md`): + ```{figure} img/gitink/git-pre-ff.svg + ``` +3. Now switch to `main`. +4. Merge the new branch to `main`. +5. Examine the result with `git graph`. +6. Have you expected the result? Discuss what you see. + + ```{solution} + You will see that in this case no merge commit was created and Git merged the + two branches by moving (fast-forwarding) the "main" branch (label) three + commits forward. + + This was possible since one branch is the ancestor of the other and their + developments did not diverge. + + A merge that does not require any merge commit is a fast-forward merge. + ``` +```` + +````{exercise} (optional) Branch-4: Rebase a branch (instead of merge) +As an alternative to merging branches, one can also *rebase* branches. +Rebasing means that the new commits are *replayed* on top of another branch +(instead of creating an explicit merge commit). +**Note that rebasing changes history and should not be done on public commits!** +1. Create a new branch, and make a couple of commits on it. +2. Switch back to `main`, and make a couple of commits on it. +3. Inspect the situation with `git graph`. +4. Now rebase the new branch on top of `main` by first switching to the new branch, and then `git rebase main`. +5. Inspect again the situation with `git graph`. Notice that the commit hashes have changed - think about why! + + ```{solution} + You will notice two things: + - History is now linear and does not contain merge commits. + - All the commit hashes that were on the branch that got rebased, have + changed. This also demonstrates that `git rebase` is a command that alters + history. The commit history looks as if the rebased commits were all done + after the `main` commits. + ``` +```` + + +## Tags + +- A tag is a pointer to a commit but in contrast to a branch it **does not ever + move** when creating new commits later. +- It can be useful to think of branches as sticky notes and of tags as + [commemorative plaques](https://en.wikipedia.org/wiki/Commemorative_plaque). +- We use tags to record particular states or milestones of a project at a given + point in time, like for instance versions (have a look at [semantic versioning](http://semver.org), + v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a). +- There are two basic types of tags: annotated and lightweight. +- **Use annotated tags** since they contain the author and can be cryptographically signed using + GPG, timestamped, and a message attached. + +Let's add an annotated tag to our current state of the guacamole recipe: +```console +$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet" +``` + +As you may have found out already, `git show` is a very versatile command. Try this: + +```console +$ git show nobel-2023 +``` + +For more information about tags see for example +[the Pro Git book](https://git-scm.com/book/en/v2/Git-Basics-Tagging) chapter on the +subject. + +--- + +## Summary + +Let us pause for a moment and recapitulate what we have just learned: + +```console +$ git branch # see where we are +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +$ git merge NAME # merge branch NAME (to current branch) +$ git branch -d NAME # delete branch NAME +$ git branch -D NAME # delete unmerged branch NAME +``` + +Since the following command combo is so frequent: + +```console +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +``` + +There is a shortcut for it: + +```console +$ git switch --create NAME # create branch NAME and switch to it +``` + +### Typical workflows + +With this there are two typical workflows: + +```console +$ git switch --create new-feature # create branch, switch to it +$ git commit # work, work, work, ..., and test +$ git switch main # once feature is ready, switch to main +$ git merge new-feature # merge work to main +$ git branch -d new-feature # remove branch +``` + +Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging: + +```console +$ git switch --create wild-idea # create branch, switch to it, work, work, work ... +$ git switch main # realize it was a bad idea, back to main +$ git branch -D wild-idea # it is gone, off to a new idea +``` + +--- + +````{challenge} Branch-5: Test your understanding + Which of the following combos (one or more) creates a new branch and makes a commit to it? + 1. ```console + $ git branch new-branch + $ git add file.txt + $ git commit + ``` + 2. ```console + $ git add file.txt + $ git branch new-branch + $ git switch new-branch + $ git commit + ``` + 3. ```console + $ git switch --create new-branch + $ git add file.txt + $ git commit + ``` + 4. ```console + $ git switch new-branch + $ git add file.txt + $ git commit + ``` + + ```{solution} + Both 2 and 3 would do the job. Note that in 2 we first stage the file, and then create the + branch and commit to it. In 1 we create the branch but do not switch to it, while in 4 we + don't give the `--create` flag to `git switch` to create the new branch. + ``` +```` + +```{keypoints} +- A branch is a division unit of work, to be merged with other units of work. +- A tag is a pointer to a moment in the history of a project. +``` diff --git a/_sources/browsing.md.txt b/_sources/browsing.md.txt new file mode 100644 index 00000000..538dfbe9 --- /dev/null +++ b/_sources/browsing.md.txt @@ -0,0 +1,394 @@ +# Copy and browse an existing project + +In this episode, we will look at an **existing repository** to +understand how all the pieces work together. Along the way, we will make a copy +(a {term}`fork`) of the {term}`repository` for us, which will be used for our +own changes in the next episode. + +- We used to start by directly going and creating a repository from scratch. This + was abstract and hard to understand. +- Instead, we'll show you all the cool stuff in a Git repository + first, and then start adding files. +- We use an example recipe book we created just for this course. +- By the end of the course, you'll know how to contribute your own + recipes to it. + +:::{objectives} +* See a real Git repository and understand what is inside of it. +* Understand how version control allows advanced inspection of a + repository. +* See how Git allows multiple people to collaborate easily. +* See the big picture instead of remembering a bunch of commands. +::: + + +## GitHub, VS Code, Command line, and more + +We offer **three different paths** of how to do this exercise: +- **GitHub** (this is the one we will demonstrate on day 1) +- **VS Code** (if you prefer to follow along using an editor; we will + do this on day 2) +- **Command line** (for people comfortable with the command line; you + will see more of this on day 2) + +In the future we'll add more paths, for example Jupyter and RStudio +(contributions welcome!). + + +## Creating a copy of the repository by "forking" + +A {term}`repository` is a collection of files in one directory tracked +by git. A {term}`GitHub repository` is GitHub's copy, which adds +things like access control. Each GitHub repository is owned by a user +or organization, who controls what is in it. + +First, we need to make our own copy of the exercise repository. This will +become important later, when we make our own changes. + +1. Go to the repository view on GitHub: + - : you can use this one if you don't want your fork and contributions + to be visible on the stream or the recording + - : we will use this one for the demonstration which is streamed and recorded +1. First, on GitHub, click the button that says "Fork". It is towards + the top-right of the screen: + :::{figure} img/browsing/forking.png + :alt: Screenshot on GitHub before clicking on "Fork" + :width: 80% + :class: with-border + ::: +1. You should shortly be redirected to your copy of the repository + **YOUR_USER_NAME/recipe-book**. + +At all times you should be aware of if you looking at *your* repository +or the *CodeRefinery {term}`upstream`* repository. +* Your repository: https://github.com/**USERNAME**/recipe-book +* CodeRefinery upstream repository: https://github.com/**coderefinery**/recipe-book + +:::::{tabs} +::::{group-tab} GitHub +You only need to open your own view, as described above. The browser +URL should look like `https://github.com/USER/recipe-book`, where +`USER` is your GitHub username. +:::: + +::::{group-tab} VS Code +You need to have forked the repository as described above. + +We need to start by making a copy of this repository locally. + +1. Start VS Code. +1. If you don't have the default view (you already have a project +open), go to File → New Window. +1. Under "Start" on the screen, select "Clone Git Repository...". Alternatively + navigate to the "Source Control" tab on the left sidebar and click on the "Clone Repository" button. +1. Paste in this URL: `https://github.com/USER/recipe-book`, where + `USER` is your username. You can copy this from the browser. +1. Browse and select the folder in which you want to clone the + repository. +1. Say yes, you want to open this repository. +1. Select "Yes, I trust the authors" (the other option works too). +:::: + +::::{group-tab} Command line +**This path is advanced and we do not include all command line +information: you need to be somewhat +comfortable with the command line already.** + +We need to start by making a copy of this repository locally. You +need to have forked the repository as described above. + +1. Start the terminal in which you use Git (terminal application, or + Git Bash). +1. Change to the directory where you would want the repository to be + (`cd ~/code` for example, if the `~/code` directory is where you + store your files). +1. Run the following command: `git clone + https://github.com/USER/recipe-book`, where `USER` is your + username. You might need to use a SSH clone command instead of + HTTPS, depending on your setup. +1. Change to that directory: `cd recipe-book` +:::: +::::: + + +## Exercise + +Work on this by yourself or in your team. + +:::{instructor-note} +Before starting the exercise session: +- Make sure you have shown how to fork the repository to own account + (above). +::: + +:::{exercise} Exercise: Browsing an existing project (25 min) + +Browse the recipe-book project (introduced above) and explore commits and branches. Take notes +and prepare questions. The hints are for the GitHub path in the +browser. + +1. Browse the **commit history**: Are commit messages understandable? + (Hint: "Commit history", the timeline symbol, above the file list) +1. Compare the commit history with the **network graph** ("Insights" -> "Network"). Can you find the branches? +1. How can you find out when a recipe was **last modified**? +1. **How many changes** did the Guacamole recipe receive (you find it under "sides")? + Try to click on some of the commits to see what changed. + (Hint: "History" in the view of a single file) +1. **Which recipes include the ingredient "salt"**? + (Hint: the GitHub search. From the repository view, it should offer + the filter "repo:USER/recipe-book" by default. What if you + add a search term?) +1. In the Guacamole recipe, find out **who modified each line last and when** + (click on file, then click "Blame" button). Find out who added the cilantro + and in which commit. + (Hint: "Blame" view in the file view) +1. Can you use these recipes yourself? **Are you allowed to share + modifications**? + (Hint: look for a license file) +1. **Browse issues and pull requests** in the {term}`upstream` repository (the + repository you forked from). Any idea what these might be good for? + (Hint: tabs in the repository view) +::: + + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by +design. + + +## Solution and walk-through + +### (1) Basic browsing + +The most basic thing to look at is the history of commits. + +* This is visible from a button in the repository view. We see every + change, when, and who has committed. +* Every change has a unique identifier, such as `554c187`. This can + be used to identify both this change, and the whole project's + version as of that change. +* Clicking on a change in the view shows more. + +:::::{tabs} + +::::{group-tab} GitHub +Click on the timeline symbol in the repository view: + :::{figure} img/browsing/history.png + :alt: Screenshot on GitHub of where to find the commit history + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +This can be done from "Timeline", in the bottom of explorer, but only +for a single file. +:::: + +::::{group-tab} Command line +Run: +```console +$ git log +``` + +Try also: +```console +$ git log --oneline +``` +:::: + +::::: + + +### (2) Compare commit history with network graph + +The commit history we saw above looks linear: one commit after +another. But if we look at the network view, we see some branches and +merges. We'll see how to do these later. This is another one of the +basic Git views. + +:::::{tabs} +::::{group-tab} GitHub +In a new browser tab, open the "Insights" tab, and click on "Network". +You can hover over the commit dots to see the person who committed and +how they correspond with the commits in the other view: + :::{figure} img/browsing/network.png + :alt: Screenshot on GitHub of the network graph + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +We don't know how to do this without an extension. Try starting a terminal and using the +"Command Line" option. +:::: + +::::{group-tab} Command line +If you defined the `git graph` alias as in {doc}`configuration`, you +can view the network graph with: +```console +$ git graph +``` +If not, you can use the basic command: +```console +$ git log --graph --oneline --decorate --all +:::: + +::::: + + +### (3) When was a recipe last modified? + +We see the history for the whole repository, but we can also see it +for a single file. + +:::::{tabs} + +::::{group-tab} GitHub +Navigate to the file view: Main page → sides directory → +guacamole.md. Click the "History" button near the top right: + :::{figure} img/browsing/file-history.png + :alt: Screenshot on GitHub showing the history of a single file + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +Open sides/guacamole.md file in the editor. Under the file browser, +we see a "Timeline" view there. +:::: + +::::{group-tab} Command line +The `git log` command can take a filename and provide the log of only +a single file: + +``` +$ git log sides/guacamole.md +``` +:::: + +::::: + + +### (4) How many changes did the Guacamole recipe receive? + +According to the view above, it seems to have five changes (as of +2024-03-07). This could change later on. + + +### (5) Which recipes include the ingredient "salt" + +Version control makes it very easy to find all occurrences of a single +word. This is useful for things like finding where functions or +variables are defined or used. + +:::::{tabs} +::::{group-tab} GitHub +We go to the main recipe book view. We click the Search magnifying +class at the very top, type "salt", and click enter. We see every +instance, including the context. + ```{admonition} Searching in a forked repository will not work instantaneously! + + It usually takes a few minutes before one can search for keywords in a forked repository + since it first needs to build the search index the very first time we search. + Start it, continue with other steps, then come back to this. + ``` + + :::{figure} img/browsing/search.png + :alt: Screenshot on GitHub performing a search + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +If you use the "Search" magnifying class on the left sidebar, and +search for "Salt" it shows the occurrences in every file. You can +click to see the usage in context. +:::: + +::::{group-tab} Command line +`grep` is the command line tool that searches for lines matching a term +```console +$ git grep salt # only the lines +$ git grep -C 3 salt # three lines of context +$ git grep -i salt # case insensitive +``` +:::: + +::::: + + +### (6) Who modified each line last and when? + +This is called the "annotate" or "blame" view. The name "blame" +is very unfortunate, but it is the standard term for historical reasons +for this functionality and it is not meant to blame anyone. + +:::::{tabs} + +::::{group-tab} GitHub +From a recipe view, change preview to "Blame" towards the top-left. +To get the actual commit, click on the commit message. + :::{figure} img/browsing/annotate.png + :alt: Screenshot on GitHub showing the "Blame" view + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +This requires an extension. We recommend for now you use the command +line version, after opening a terminal. +:::: + +::::{group-tab} Command line +These two commands are similar but have slightly different output. +```console +$ git annotate sides/guacamole.md +$ git blame sides/guacamole.md +``` +:::: + +::::: + + +### (7) Can you use these recipes yourself? Are you allowed to share modifications? + +* Look at the file `LICENSE`. +* It says it is "Creative Commons Zero 1.0", which is equivalent to + public domain. You can use them without conditions. +* Note the GitHub view of the file `LICENSE` gives a nice summary of what it + means. Try it out: + :::{figure} img/browsing/license.png + :alt: Screenshot on GitHub summarizing license terms + :width: 100% + :class: with-border + ::: + + +### (8) Browse issues and pull requests in the {term}`upstream` repository + +This can only be done through the GitHub view. Go to the main +repository **coderefinery/recipe-book**, (not your fork): +. {term}`Issues ` +and {term}`Pull requests ` are different for each GitHub +copy. + +* Click on the "Issues" tab. These are notes that people have added, + which allow discussion about the project. Often they are used to communicate + problems or ideas. +* Click on the "Pull requests" tab. This allows anyone to *propose + changes*, but only the repository owners can accept. + + +## Summary + +- Git allowed us to understand this simple project much better than we + could, if it was just a few files on our own computer. +- It was also very easy to share the project with the course. +- By forking the repository, we created our own copy. This is + important for the next episode, where we will make changes to + our copy. diff --git a/_sources/commits.md.txt b/_sources/commits.md.txt new file mode 100644 index 00000000..20f65d6f --- /dev/null +++ b/_sources/commits.md.txt @@ -0,0 +1,452 @@ +# Committing changes + +The first and most basic task to do in Git is *record changes* using +commits. In this part, we will record changes in two +ways: on a new branch (which supports multiple lines of work at once), and directly +on the "main" branch (which happens to be the default branch here). + +:::{objectives} +* Record new changes to our own copy of the project. +* Understand adding changes in two separate branches. +* See how to compare different versions. +::: + + +## Background + +- In the previous episode we have browsed an existing {term}`repository` and saw {term}`commits ` + and branches. +- Each commit is a snapshot of the entire project at a certain + point in time and has a unique identifier ({term}`hash`) . +- A {term}`branch` is a line of development, and the `main` branch or `master` branch + are often the default branch in Git. +- A branch in Git is like a sticky note that is attached to a commit. When we add + new commits to a branch, the sticky note moves to the new commit. +- {term}`Tags ` are a way to mark a specific commit as important, for example a release + version. They are also like a sticky note, but they don't move when new + commits are added. + +:::{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +What if two people, at the same time, make two different changes? Git +can merge them together easily. Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +::: + + +## Exercise + +We offer **three different paths** of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the **GitHub +path** only and recommend you do that. (You can get experience with +the other paths on day 2) + +:::{exercise} Exercise: Practice creating commits and branches (20 min) +1. Make sure that you now work **on your fork** of the recipe-book + repository (`USER/recipe-book`, *not* `coderefinery/recipe-book`) +1. First create a new branch and then add a recipe to the branch and commit the change. +1. In a new commit, modify the recipe you just added. +1. Switch to the `main` branch and modify a recipe there. +1. Browse the network and locate the commits that you just created ("Insights" -> "Network"). +1. Compare the branch that you created with the `main` branch. Can you find an easy way to see the differences? +1. Can you find a way to compare versions between two arbitrary commits in the repository? +1. Try to rename the branch that you created and then browse the network again. +1. Try to create a tag for one of the commits that you created (on GitHub, + create a "release"). +::: + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by +design. + + +## Solution and walk-through + + +### (1) Make sure you are on your fork + +:::{figure} img/commits/fork.png +:alt: Screenshot on GitHub where we verify that we are on our fork. +:width: 60% +:class: with-border + +You want to see your username in the URL and you want to see the "forked from +..." part. +::: + + +### (2) Create a branch and add a recipe to the branch + +A recipe template is below. This format is called "Markdown", but it +doesn't matter right now. You don't have to use this particular template. +```markdown +# Recipe name + +## Ingredients + +- Ingredient 1 +- Ingredient 2 + + +## Instructions + +- Step 1 +- Step 2 +``` + +There is a {term}`main` branch that is default. We want to create a +*different* {term}`branch` for our new commit, because we will *merge* it later. +{term}`Commit ` is the verb to describe recording more changes, and also the +name of the thing you make. A commit is identified by something such as +`554c187`. + +:::::{tabs} +::::{group-tab} GitHub +1. Where it says "main" at the top left, click, enter a new branch + name `new-recipe`, click on the offer to create the new branch + ("Create branch new-recipe from main"). + :::{figure} img/commits/github-create-branch.png + :alt: Screenshot on GitHub where we create a new branch. + :width: 60% + :class: with-border + ::: +1. Change to some sub-directory, for example `sides` +1. Make sure you are still on the `new-recipe` branch (it should say + it at the top), and click "Add file" → "Create new file" from the + upper right. +1. Enter a filename where it says "Name your file...", with a `.md` at + the end. Example: `mixed-nuts.md`. +1. Enter the recipe. You can use the template above. +1. Click "Commit changes" +1. Enter a commit message. Then click "Commit + changes". + +You should appear back at the file browser view, and see your new +recipe there. +:::: + +::::{group-tab} VS Code +1. Make sure that you are on the main branch. +1. Version control button on left sidebar → Three dots in upper right of source control → Branch → Create branch. +1. VS Code automatically switches to the new branch. + +:::{figure} img/commits/vscode-create-branch.png +:width: 80% +:class: with-border +:alt: VS Code screenshot of create branch + +Creating a new branch in VS Code. +::: + +4. Create a new file, for example `sides/mixed-nuts.md`. +4. In the version control sidebar, click the `+` sign to add the file for the next commit. +4. Enter a brief message and click "Commit". + +:::{figure} img/commits/vscode-add-and-commit.png +:alt: Screenshot of VS Code commit process +:width: 80% +:class: with-border + +Committing a new file in VS Code. +::: +:::: + +::::{group-tab} Command line +Create a new branch called `new-recipe` from `main` and switch to it: +```console +$ git switch --create new-recipe main +``` + +Then create the new file. Finally add and commit the file: +```console +$ git add sides/mixed-nuts.md +$ git commit -m "Add mixed nuts recipe" +``` +:::: +::::: + + +### (3) Modify the recipe with a new commit + +:::::{tabs} +::::{group-tab} GitHub +This is similar to before, but we click on the existing file to +modify. + +1. Click on your new recipe, for example `mixed-nuts.md`. +2. Click the edit button, the pencil icon at top-right. +3. Follow the "Commit changes" instructions as in the previous step. +:::: + +::::{group-tab} VS Code +Repeat as in the previous step. +:::: + +::::{group-tab} Command line +Modify the file. Then commit the new change: +```console +$ git add sides/mixed-nuts.md +$ git commit -m "Short summary of the change" +``` + +Make sure to replace "Short summary of the change" with a meaningful commit +message. +:::: +::::: + + +### (4) Switch to the main branch and modify a recipe there + +:::::{tabs} +::::{group-tab} GitHub +1. Go back to the main repository page (your user's page). +1. In the branch switch view (top left above the file view), switch to + `main`. +1. Modify another recipe that already exists, following the pattern + from above. Don't modify the one you just created (but it shouldn't + even be visible on the `main` branch). +:::: + +::::{group-tab} VS Code +Use the branch selector at the bottom to switch back to the main branch. Repeat the same steps as above. + +:::{figure} img/commits/vscode-change-branch.png +:class: with-border +:width: 80% +:alt: VS Code screenshot + +Switching branch via selector at bottom. +:::: + +::::{group-tab} Command line +First switch to the `main` branch: +```console +$ git switch main +``` + +Then modify a file. Finally `git add` and then commit the change: +```console +$ git commit -m "Short summary of the change" +``` +:::: +::::: + + +### (5) Browse the commits you just made + +Let's look at what we did. Now, the `main` and `new-recipe` branches +have diverged: both have some modifications. Try to find the commits +you created. + +:::::{tabs} +::::{group-tab} GitHub +Insights tab → Network view (just like we have done before). +:::: + +::::{group-tab} VS Code +This requires an extension. Opening the VS Code terminal lets you use the command line method. + +:::{figure} img/commits/vscode-open-terminal.png +:class: with-border +:width: 80% +:alt: VS Code screenshot as described + +View → Terminal will open a terminal at bottom. This is a normal command line interface and very useful for work. (Note the git-aware prompt that shows the current branch. This requires other setup.) +:::: + +::::{group-tab} Command line +```console +$ git graph +$ git log --graph --oneline --decorate --all # If you didn't define git graph yet. +``` + +In my case I got: +```{code-block} +--- +emphasize-lines: 1-3 +--- +* b4de93b (HEAD -> main) add spring onion to poke +| * dc5d6f0 (origin/new-recipe, new-recipe) adding chocolate to the mixed nuts recipe +| * b4035e3 add mixed nuts recipe +|/ +* 554c187 (origin/main, origin/HEAD) Merge branch 'alex/fruit-salad' +|\ +| * 89d5ef9 fruit salad: instructions +| * 3bd2468 fruit salad: ingredients +* | 8bcb766 a todo note to not forget the instructions +|/ +* b950c5c just fixing capitalization +* d18035e fix formatting +* 7051cca add some cilantro +* ae19e81 add categories for easier browsing +* a6fe629 we also need salad +* 30b89c4 document what this is about +* fd12dc1 Merge branch 'radovan/lasagna' +|\ +| * 7753d43 vegetarian lasagna: instructions +| * aa0473e vegetarian lasagna: ingredients +* | 1e5a24a Merge branch 'radovan/poke' +|\ \ +| * | 5aa6687 oh no! forgot onion - adding +| * | cc84e4f working on a poke recipe +| |/ +* | 9500901 a classic pumpkin pie recipe - yum! +* | 34ce939 drafting a recipe for a pasta, so far only ingredients +* | 28e5f26 recipe for a mushroom soup +|/ +* a550963 reduce amount of salt +* f2d6d58 don't forget to enjoy +* 1fde064 add half an onion +* 4c1873e drafting a guacamole recipe +* 2992443 this will be licensed under CC0 +* 084a1ea starting with an almost empty readme +``` +:::: +::::: + + +### (6) Compare the branches + +Comparing changes is an important thing we need to do. When using the +GitHub view only, this may not be so common, but we'll show it so that +it makes sense later on. + +:::::{tabs} + +::::{group-tab} GitHub +Next to the branch name switcher, click on "Branches" to get an overview. + +Another way to compare branches or commits on GitHub is to adjust the following URL: +`https://github.com/USER/recipe-book/compare/VERSION1..VERSION2` + +Replace `USER` with your username and `VERSION1` and `VERSION2` with a commit hash or branch name. +Please try it out. +:::: + +::::{group-tab} VS Code +This seems to require an extension. We recommend you use the command line method. +:::: + +::::{group-tab} Command line +```console +$ git diff main new-recipe +``` + +Try also the other way around: +```console +$ git diff new-recipe main +``` + +Try also this if you only want to see the file names that are different: +```console +$ git diff --name-only main new-recipe +``` +:::: +::::: + + +### (7) Compare two arbitrary commits + +This is similar to above, but not only between branches. + +:::::{tabs} +::::{group-tab} GitHub +Like above, one can compare commits on GitHub by adjusting the following URL: +`https://github.com/USER/recipe-book/compare/VERSION1..VERSION2` + +Replace `USER` with your username and `VERSION1` and `VERSION2` with a commit hash or branch name. +Please try it out. +:::: + +::::{group-tab} VS Code +Again, we recommend using the Command Line method. +:::: + +::::{group-tab} Command line +First try this to get a short overview of the commits: +```console +$ git log --oneline +``` + +Then try to compare any two commit identifiers with `git diff`. +:::: +::::: + + +### (8) Renaming a branch + +:::::{tabs} +::::{group-tab} GitHub + +Branch button → View all branches → three dots at right side → Rename branch. + +:::: +::::{group-tab} VS Code +Version control sidebar → Three dots (same as in step 2) → Branch → Rename branch. Make sure you are on the right branch before you start. +:::: + +::::{group-tab} Command line +Renaming the current branch: +```console +$ git branch -m better-recipe +``` + +Renaming a different branch: +```console +$ git branch -m new-recipe better-recipe +``` +:::: +::::: + + +### (9) Creating a tag + +Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don't move when new +commits are added. + +:::::{tabs} +::::{group-tab} GitHub +Click on the branch switcher, and then on "Tags", then on "View all tags", then +"Create a new release": + :::{figure} img/commits/github-create-tag.png + :alt: Screenshot on GitHub where we create a new tag. + :width: 60% + :class: with-border + ::: + +What GitHub calls releases are actually tags in Git with additional metadata. +For the purpose of this exercise we can use them interchangeably. +:::: + +::::{group-tab} VS Code +Version control sidebar → Three dots (same as in step 2) → Tags → Creat tag. Make sure you are on the expected commit before you do this. +:::: + +::::{group-tab} Command line +Creating a tag: +```console +$ git tag -a v1.0 -m "New manuscript version of my recipe for the pre-print" +``` +:::: +::::: + + +## Discussion + +In this part, we saw how we can make changes to our files. +With {term}`branches `, we can +track several lines of work at once, and can compare +their differences. + +- You could commit directly to `main` if there is only one single line + of work and it's only you. +- You could commit to branches if there are multiple lines of work at + once, and you don't want them to interfere with each other. +- Tags are useful to mark a specific commit as important, for example a + release version. +- In Git, commits form a so-called "graph". Branches are tags in Git function + like sticky notes that stick to specific commits. What this means for us is + that it does not cost any significant disk space to create new branches. diff --git a/_sources/configuration.md.txt b/_sources/configuration.md.txt new file mode 100644 index 00000000..b00b7a89 --- /dev/null +++ b/_sources/configuration.md.txt @@ -0,0 +1,147 @@ +(configuration)= + +# Configuring Git command line and editor + +We have a longer version of this in the [installation +instructions](https://coderefinery.github.io/installation/git-in-terminal/). +But for clarity, we will review the most important parts here. + +You don't need to set these if you work only through the GitHub web interface. +If you use VS Code or other editors or integrated development environments, +the editor might prompt you to set these up. + +These configuration settings are saved in a file called `.gitconfig` in your +home directory. If this file exists, editors like VS Code will use this +configuration. + +If you want to see your configuration settings, you can use the +command (`--show-origin` means it shows the file *where* each setting +is defined): +```console +$ git config --list --show-origin +``` + + +## Name and email address for Git commit metadata + +Git commits carry metadata about the author and two things you will always need +to define somewhere are: +```console +$ git config --global user.name "Your Name" +$ git config --global user.email yourname@example.com +``` + +For the email address we recommend to use the one you use for your GitHub account. +If you prefer to not use it, you can instead use +`YOUR_GITHUB_USERNAME@users.noreply.github.com` as the email address (replace `YOUR_GITHUB_USERNAME`). +This means that nobody can write to this email address, but GitHub will still +be able to connect your contributions with your GitHub account. + +Note that these can, in theory, be anything: this is just data, not a +registration or identity requirement. + + +## Default branch name + +The default branch name in Git has been `master` for a long time, but it is +changing to `main` in many places. We recommend to set it to `main` for new +repositories that you create locally: +```console +$ git config --global init.defaultbranch main +``` + + +## Useful alias for the command line + +We recommend to define an {term}`alias` in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command: +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` + +We have an own section about aliases: {ref}`aliases`. + + +## Default text editor for commit messages + +Git sometimes needs to start a text editor for you to enter messages (unless you create +commits from inside an editor or on the web). +This may have already been set to something (like VS Code), but if not +`nano` is usually a safe choice: + +```console +$ git config --global core.editor nano +``` + +The [installation instructions text editor page](https://coderefinery.github.io/installation/editors/) gives ways +to set other editors, or do a web search for "git set editor to +[editor name]". + + +% This anchor used for linking from other lessons +(clone-method)= + +## Authenticating to GitHub: SSH or HTTPS or VS Code? + +**How does GitHub know who you are?** There are three options: +- **SSH** is the classic method, using [Secure Shell + Protocol](https://en.wikipedia.org/wiki/Secure_Shell) remote connection + keys. +- **HTTPS** works with the **Git Credential Manager**, which is an + extra add-on that works easily in Windows and Mac. +- **VS Code** editor can authenticate with GitHub using its own + authentication method. + +Read how to install them from the [installation +instructions](https://coderefinery.github.io/installation/ssh/). + +Test which one you should use: + +:::::{tabs} + ::::{group-tab} Command line: SSH + Try this command: + ```console + $ ssh -T git@github.com + ``` + + If it returns `Hi USERNAME! You've successfully authenticated, ...`, + then SSH is configured and the following steps will work with the SSH + cloning. + + See our [installation + instructions](https://coderefinery.github.io/installation/ssh/) to + set up SSH access. + + **From now on, if you know that SSH works, you should always select + SSH as the clone URL from GitHub, or translate the URL to start with + the right thing yourself:** `git@github.com:` (with the `:`). + :::: + + ::::{group-tab} Command line: HTTPS + Try this command: + ```console + $ git config --get credential.helper + ``` + + If this shows something, then the credential manager is probably + configured and HTTPS cloning will work (but you can't verify it until + you try using it). + + From now on, **if you know that HTTPS works, you should always select + HTTPS as the clone URL from GitHub, or translate the URL to start with + the right thing yourself:** `https://github.com/` + :::: + + ::::{group-tab} VS Code + VS Code has its own authentication method and the editor will guide you + through the process. If you are using VS Code, you can skip the SSH and + HTTPS checks. + + From now on, you should **Select HTTPS as the clone URL from + GitHub, or translate the URL to start with the right thing + yourself:** `https://github.com/` + + If you don't want VS Code to be connected to your GitHub account, + set up and use the SSH method instead. + :::: +::::: diff --git a/_sources/conflicts.md.txt b/_sources/conflicts.md.txt new file mode 100644 index 00000000..34b978ad --- /dev/null +++ b/_sources/conflicts.md.txt @@ -0,0 +1,463 @@ +(conflict-resolution)= + +# Conflict resolution + +```{objectives} +- Understand merge conflicts sufficiently well to be able to fix them. +``` + +```{instructor-note} +- 20 min teaching/type-along +- 20 min exercise +``` + + +## Conflicts in Git and why they are good + +Imagine we start with the following text file: +```{code-block} +1 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1/2 onion +``` + +On branch A somebody modifies: +```{code-block} +--- +emphasize-lines: 1, 4 +--- +2 tbsp cilantro +2 avocados +1 chili +2 lime +1 tsp salt +1/2 onion +``` + +On branch B somebody else modifies: +```{code-block} +--- +emphasize-lines: 1, 6 +--- +1/2 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1 onion +``` + +When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro: +```{code-block} +--- +emphasize-lines: 1 +--- +????????????????? +2 avocados +1 chili +2 lime +1 tsp salt +1 onion +``` + +Git is very good at resolving modifications when merging branches and +in most cases a `git merge` runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see {ref}`exercise-branches-optional`) without you even noticing. + +But sometimes the **same portion** of the code/text is modified on two branches +**in two different ways** and Git issues a **conflict**. +Then you need to tell Git which version to keep (**resolve** it). + +There are several ways to do that as we will see. + +Please remember: + +- It is good that Git conflicts exist: Git will not silently overwrite one of + two differing modifications. +- Conflicts may look scary, but are not that bad after a little bit of + practice. Also they are luckily rare. +- Don't be afraid of Git because of conflicts. You may not meet some conflicts + using other systems because you simply can't do the kinds of things you do + in Git. +- You can take human measures to reduce them. + +--- + +```{discussion} The human side of conflicts +- What does it mean if two people do the same thing in two different ways? +- What if you work on the same file but do two different things in the different sections? +- What if you do something, don't tell someone from 6 months, and then try to combine it with other people's work? +- How are conflicts avoided in other work? (Only one person working at once? + Declaring what you are doing before you start, if there is any chance someone + else might do the same thing, helps.) +- Minor conflicts (two people revise spelling) vs semantic (two people rewrite + a function to add two different new features). How did Git solve these in + branching/merging easily? +``` + +Now we can go to show how Git controls when there is actually a conflict. + + +## Preparing a conflict + +```{instructor-note} +We do the following together as type-along/demo. +``` + +````{admonition} If you got stuck previously or joined later + **If you got stuck previously or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together. + +- Create two branches from `main`: one called `like-cilantro`, one called `dislike-cilantro`: + ```console + $ git branch like-cilantro main + $ git branch dislike-cilantro main + ``` + +- On the two branches make **different modifications** to the amount of the **same ingredient**: + +- On the branch `like-cilantro` we have the following change: + ```console + $ git diff main like-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6cacd50 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + +- And on the branch `dislike-cilantro` we have the following change: + ```console + $ git diff main dislike-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6484462 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 1/2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + + +## Merging conflicting changes + +What do you expect will happen when we try to merge these two branches into +main? + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +The first merge will work: + +```console +$ git switch main +$ git status +$ git merge like-cilantro + +Updating 4e03d4b..3caa632 +Fast-forward + ingredients.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +``` + +But the second will fail: + +```console +$ git merge dislike-cilantro + +Auto-merging ingredients.txt +CONFLICT (content): Merge conflict in ingredients.txt +Automatic merge failed; fix conflicts and then commit the result. +``` + +Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit: + +```{code-block} console +--- +emphasize-lines: 9 +--- +$ git status + +You have unmerged paths. + (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) + +Unmerged paths: + (use "git add ..." to mark resolution) + both modified: ingredients.txt + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +Git won't decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward. + +Let us inspect the conflicting file: + +```console +$ cat ingredients.txt + +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +Git inserted resolution markers (the `<<<<<<<`, `>>>>>>>`, and `=======`). + +Try also `git diff`: + +```console +$ git diff +``` + +```diff +diff --cc ingredients.txt +index 6cacd50,6484462..0000000 +--- a/ingredients.txt ++++ b/ingredients.txt +@@@ -1,4 -1,4 +1,10 @@@ +++<<<<<<< HEAD + +* 2 tbsp cilantro +++======= ++ * 1/2 tbsp cilantro +++>>>>>>> dislike-cilantro + * 2 avocados + * 1 chili + * 1 lime +``` + +`git diff` now only shows the conflicting part, nothing else. + + +## Conflict resolution + +``` +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +``` + +We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged. + +```{admonition} Steps to resolve a conflict + +- Check status with `git status` and `git diff`. +- Decide what you keep (the one, the other, or both or something + else). Edit the file to do this. + - Remove the resolution markers, if not already done. + - The file(s) should now look exactly how you want them. +- Check status with `git status` and `git diff`. +- Tell Git that you have resolved the conflict with `git add ingredients.txt` + (if you use the Emacs editor with a certain plugin the editor may stage the + change for you after you have removed the conflict markers). +- Verify the result with `git status`. +- Finally commit the merge with only `git commit`. Everything is pre-filled. +``` + +(exercise-conflicts)= + +## Exercise: Create and resolve a conflict + +````{exercise} Conflict-1: Create another conflict and resolve +In this exercise, we repeat almost exactly what we did above with a +different ingredient. + +1. Create two branches before making any modifications. +2. Again modify some ingredient on both branches. +3. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge. +4. What happens if you apply the same modification on both branches? +5. If you create a branch `like-avocados`, commit a change, then from this + branch create another banch `dislike-avocados`, commit again, and try to + merge both branches into `main` you will not see a conflict. Can you + explain, why it is different this time? +```{solution} +4: No conflict in this case if the change is the same. + +5: No conflict in this case since in Git history one change happened after the other. The two changes + are related and linked by Git history and one is a Git ancestor of the + other. Git will assume that since we applied one change after the other, + we meant this. There is nothing to resolve. +``` +```` + +(exercise-conflicts-optional)= + +## Optional exercises with conflict resolution + +````{exercise} (optional) Conflict-2: Resolve a conflict when rebasing a branch +1. Create two branches where you anticipate a conflict. +2. Try to merge them and observe that indeed they conflict. +3. Abort the merge with `git merge --abort`. +4. What do you expect will happen if you rebase one branch on top of the + other? Do you anticipate a conflict? Try it out. +```{solution} +Yes, this will conflict. If it conflicts during a merge, it will also conflict +during rebase but the conflict resolution looks slightly different: +You still need to look for conflict markers but you tell Git that you resolved +a conflict with `git add` and then you continue with `git rebase --continue`. +Follow instructions that you get from the Git command line. +``` +```` + +````{exercise} (optional) Conflict-3: Resolve a conflict using mergetool + - Again create a conflict (for instance disagree on the number of avocados). + - Stop at this stage: + + ```markdown + Auto-merging ingredients.txt + CONFLICT (content): Merge conflict in ingredients.txt + Automatic merge failed; fix conflicts and then commit the result. + ``` + + - Instead of resolving the conflict manually, use a visual tool + (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + ```console + $ git mergetool + ``` + + ```{figure} img/conflict-resolution/mergetool.png + :alt: Conflict resolution using mergetool + :width: 100% + ``` + + - Your current branch is left, the branch you merge is right, result is in the middle. + - After you are done, close and commit, `git add` is not needed when using `git mergetool`. + + If you have not instructed Git to avoid creating backups when using mergetool, then to be on + the safe side there will be additional temporary files created. To remove those you can do + a git clean after the merging. + + To view what will be removed: + + ```console + $ git clean -n + ``` + + To remove: + + ```console + $ git clean -f + ``` + + To configure Git to avoid creating backups at all: + + ```console + $ git config --global mergetool.keepBackup false + ``` +```` + +--- + +## Using "ours" or "theirs" strategy + +- Sometimes you know that you want to keep "ours" version (version on the branch you are on) + or "theirs" (version on the merged branch). +- Then you do not have to resolve conflicts manually. +- See [merge strategies](https://git-scm.com/docs/merge-strategies). + +Example (merge and in doubt take the changes from current branch): +```console +$ git merge -s recursive -Xours less-avocados +``` + +Or (merge and in doubt take the changes from less-avocados branch): +```console +$ git merge -s recursive -Xtheirs less-avocados +``` + +--- + +## Aborting a conflicting merge + +Sometimes you get a merge conflict but realize that you can't solve it without +talking to a colleague (who created the other change) first. What to do? + +You can abort the merge and postponing conflict resolution by resetting the +repository to `HEAD` (last committed state): + +```console +$ git merge --abort +``` + +The repository looks then exactly as it was before the merge. + +--- + +## Avoiding conflicts + +- Human measures + - Think and plan to which branch you will commit to. + - Do not put unrelated changes on the same branch. +- Collaboration measures + - Open an issue and discuss with collaborators before starting a long-living + branch. +- Project layout measures + - Modifying global data often causes conflicts. + - Modular programming reduces this risk. +- Technical measures + - **Share your changes early and often** - this is one of the happy, + rare circumstances when everyone doing the selfish thing (e.g. `git push` as + early as practical) results in best case for everyone! + - Pull/rebase often to keep up to date with upstream. + - Resolve conflicts early. + +```{discussion} +Discuss how Git handles conflicts compared to services like Google Drive. +``` + +```{keypoints} +- Conflicts often appear because of not enough communication or not optimal + branching strategy. +``` diff --git a/_sources/customizing.md.txt b/_sources/customizing.md.txt new file mode 100644 index 00000000..c8fdf72b --- /dev/null +++ b/_sources/customizing.md.txt @@ -0,0 +1,25 @@ +# Customizing Git + +## Shell prompt + +```{instructor-note} +Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like. +``` + +You can make your shell display contextual information about +your Git state even at all times. + +Here are few example projects that make this possible and easy: +- (bash) +- (zsh) +- (fish) +- (bash and fish) + + +## More useful "diff" output + +[Delta](https://github.com/dandavison/delta) is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +"diff" output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more. diff --git a/_sources/exercises.md.txt b/_sources/exercises.md.txt new file mode 100644 index 00000000..fe455cfa --- /dev/null +++ b/_sources/exercises.md.txt @@ -0,0 +1,10 @@ +# List of exercises + +This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests. + +```{exerciselist} +``` diff --git a/_sources/guide.md.txt b/_sources/guide.md.txt new file mode 100644 index 00000000..89b3eda7 --- /dev/null +++ b/_sources/guide.md.txt @@ -0,0 +1,221 @@ +# Instructor guide + + +:::warning +## Exercise preparation: one day before the workshop + +- Create two exercise repository from + preserving history + (this means **not** using "generating from template") + - + - +- You can create these using `git clone --mirror` and `git push --mirror` to make sure to copy all branches. +- Create one or two issues to both +- Create one or two pull requests to both +- In both, try to search for something in the recipes to trigger a search index + update +::: + + +## Privacy + +When presenting the material in a streamed and recorded workshop, make sure to +only show the +repository. + + +## Schedule Day 1 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:20 (20 min) Welcome and practical information + +- 09:20 - 09:35 (15 min) [Motivation](https://coderefinery.github.io/git-intro/motivation/) +- 09:35 - 10:00 (25 min) [Copy and browse an existing project](https://coderefinery.github.io/git-intro/browsing/) + +- 10:00 - 10:10 (10 min) Break + +- 10:10 - 11:00 (50 min) [Committing changes](https://coderefinery.github.io/git-intro/commits/) + +- 11:00 - 12:00 (60 min) Break + +- 12:00 - 12:50 (50 min) [Merging changes and contributing to the project](https://coderefinery.github.io/git-intro/merging/) + +- 12:50 - 13:00 (10 min) Break + +- 13:00 - 13:30 (20 min) Demonstrating conflict resolution, Q&A, feedback, and what will we be doing tomorrow? + + +## Schedule Day 2 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:50 (50 min) [Cloning a Git repository and working locally](https://coderefinery.github.io/git-intro/local-workflow/) + +- 09:50 - 10:00 (10 min) Break + +- 10:00 - 11:00 (60 min) [Inspecting history](https://coderefinery.github.io/git-intro/archaeology/) + +- 11:00 - 12:00 (60 min) Break + +- 12:00 - 12:50 (50 min) [How to turn your project to a Git repo and share it](https://coderefinery.github.io/git-intro/sharing/) + +- 12:50 - 13:00 (10 min) Break + +- 13:00 - 13:30 (20 min) Practical advice, Q&A, feedback, and what will we be doing tomorrow? + + +## Why we teach this lesson + +Everyone should be using a version control system for their work, even if they're working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories. + +Specific motivations: +- Code easily becomes a disaster without version control +- Mistakes happen - Git offers roll-back functionality and easy backup mechanism +- One often needs to work on multiple things in parallel - branches solve that problem +- Git enables people to collaborate on code or text without stepping on each other's toes +- Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, + and if bugs are found one can find out exactly when it was introduced + +Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices. + + +## Intended learning outcomes + +By the end of this lesson, learners should: +- realize that version control is very important and Git is a valuable tool to learn and use +- understand that Git is configurable and know how to set basic configurations +- be able to set up Git repositories and make commits +- know how to write good commit messages +- have an idea of how the staging area can be used to craft good commits +- know how to create branches and switch between branches +- have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way +- know how to merge branches and understand what that means in terms of combining different modifications +- realize that conflicts are generally a good thing since they prevent incorrect merges +- be able to set up a repository on GitHub and connect it with local repository +- push changes to a remote repository +- know a few ways to search through a repository and its history + + +## Inspecting history + +Key lesson is *how to find when something is broken or what commit has broken +the code*. + +It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that `git annotate` +and `git show` are available on GitHub and GitLab. + +When discussing `git annotate` and `git bisect` the "when" is more important +than "who". It is not to blame anybody but rather to find out whether published +results are affected. + +Discuss how one would find out this information without version control. + +**Questions to involve participants:** + +- Have you ever found a bug in your code and wondered whether it has affected published results? +- Have you ever wondered when, and by whom, a particular line of code was introduced? +- Have you ever found out that a code behaves differently than it used to but you are not sure when + precisely this changed? + + +**Confusion during `git bisect` exercise:** + +Learners may get stuck in the `git bisect` exercise if they incorrectly assign a commit +as *bad* or *good*. +To leave the bisect mode and return to the commit before `git bisect start` was issued, +one can do +```shell +$ git bisect reset +``` +and start over if needed. + + +### Live better than reading the website material + +It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier. + + +### Log your history in a separate window + +The screencasting (shell window cheatsheet) hints have been moved to +the [presenting +manual](https://coderefinery.github.io/manuals/instructor-tech-setup/). + + +### Create a cheatsheet on the board + +For in-person workshops, create a "cheatsheet" on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven't forgotten anything. Re-create and expand in future git lessons. +One strategy is: + +- a common section for basic commands: `init`, `config`, `clone`, `help`, `stash` +- info commands, can be run anytime: `status`, `log`, `diff`, `graph` +- A section for all the commands that move code from different states: + `add`, `commit`, etc. See the visual cheat sheet below. + +You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it's probably too confusing to use after this course. But, the idea +of commands moving from the "working dir", "staging area", "commits", +etc is good. + +```{figure} img/cheat-sheet.jpg +:alt: Example cheat sheet +:width: 100% + +Example cheat sheet. +``` + +We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to. + + +### Draw a graph on the board + +Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run `git graph`, then do the command, +then look at `git graph` again. + + +### Repeat the following points + +- Always check `git status`, `git diff`, and `git graph` (our alias) before and + after every command until you get used to things. These give you a clear view + into what is going on, the key to knowing what you are doing. Even + after you are used to things... anytime you do something you do + infrequently, it's good to check. + +- `git graph` is a direct representation of what we are drawing on the + board and should constantly be compared to it. + +- Once you `git add` something, it's almost impossible to lose it. + This is used all the time, for example once you commit or even add + it is hard to lose. Commit before you merge or rebase. And so on. + + +### Start from identical environment + +You probably have a highly optimized bash and git environment - one +that is different from students. Move `.gitconfig` and `.bashrc` out +of the way before you start so that your environment is identical to +what students have. diff --git a/_sources/index.md.txt b/_sources/index.md.txt new file mode 100644 index 00000000..ccbd5471 --- /dev/null +++ b/_sources/index.md.txt @@ -0,0 +1,124 @@ +# Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version + +```{warning} +In February and March 2024 we rewrote this lesson from the ground up. +If you are looking for the previous version, you can browse the +[2023 version of this lesson](https://coderefinery.github.io/git-intro/branch/2023-version/). +``` + +This is the introductory lesson to version control using +[Git](https://git-scm.com/). + +We start with an existing repository on the web to visually explain the basic +concepts of version control. We later move to a local +repository. Our goal there is not only to be able to apply changes to an +existing repository but to also be able to turn own projects into Git +repositories and to share them with others. + +In the separate [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/), we teach more use +of remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with Git to +be able to work well. + +The goals of the module as a whole are that the learner will feel comfortable +about committing changes, branching, and merging. + +```{prereq} +We offer several options to go through the material: **on the web, in an editor, +or in the terminal**. +Please see the [installation instructions](https://coderefinery.github.io/installation/). + +We recommend to have a [GitHub](https://github.com) account. +**Why GitHub?** +Also [GitLab](https://gitlab.com) and [Bitbucket](https://bitbucket.org) would +allow similar workflows and basically everything that we will discuss is +transferable. With this material and these exercises we do not implicitly +endorse the company [GitHub](https://github.com). We have chosen to demonstrate +a number of concepts using examples with [GitHub](https://github.com) because +it is currently the most popular web platform for hosting Git repositories and +the chance is high that you will interact with +[GitHub](https://github.com)-based repositories even if you choose to host your +Git repository on another service. +``` + +```{toctree} +:maxdepth: 1 +:caption: Getting started + +motivation +configuration +``` + +```{toctree} +:maxdepth: 1 +:caption: Modifying an existing project + +browsing +commits +merging +local-workflow +``` + +```{toctree} +:maxdepth: 1 +:caption: Studying an existing project + +archaeology +``` + +```{toctree} +:maxdepth: 1 +:caption: Sharing your work + +sharing +``` + +```{toctree} +:maxdepth: 1 +:caption: Finding the balance + +level +what-to-avoid +``` + +```{toctree} +:maxdepth: 1 +:caption: Older episodes + +basics +branches +conflicts +``` + +```{toctree} +:maxdepth: 1 +:caption: Optional episodes + +staging-area +recovering +interrupted +aliases +under-the-hood +``` + +```{toctree} +:maxdepth: 1 +:caption: Reference + +reference +customizing +resources +exercises +guide +PDF version +``` + +```{toctree} +:maxdepth: 1 +:caption: About + +All lessons +CodeRefinery +Reusing +``` diff --git a/_sources/interrupted.md.txt b/_sources/interrupted.md.txt new file mode 100644 index 00000000..0516cad1 --- /dev/null +++ b/_sources/interrupted.md.txt @@ -0,0 +1,106 @@ +# Interrupted work + +```{objectives} +- Learn to switch context or abort work without panicking. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{keypoints} +- There is almost never reason to clone a fresh copy to complete a task that + you have in mind. +``` + + +## Frequent situation: interrupted work + +We all wish that we could write beautiful perfect code. But the real world is +much more chaotic: + +- You are in the middle of a "Jackson-Pollock-style" debugging spree with 27 modified files + and debugging prints everywhere. +- Your colleague comes in and wants you to fix/commit something right now. +- What to do? + +Git provides lots of ways to switch tasks without ruining everything. + + +## Option 1: Stashing + +The **stash** is the first and easiest place to temporarily "stash" +things. + +- `git stash` will put working directory and staging area changes + away. Your code will be same as last commit. +- `git stash pop` will return to the state you were before. Can give it a list. +- `git stash list` will list the current stashes. +- `git stash save NAME` is like the first, but will give it a name. + Useful if it might last a while. +- `git stash save [-p] [filename]` will stash certain files files + and/or by patches. +- `git stash drop` will drop the most recent stash (or whichever stash + you give). +- The stashes form a stack, so you can stash several batches of modifications. + + +(exercise-stashing)= + +### Exercise: Stashing + +````{exercise} Interrupted-1: Stash some uncommitted work +1. Make a change. +2. Check status/diff, stash the change with `git stash`, check status/diff again. +3. Make a separate, unrelated change which doesn't touch the same + lines. Commit this change. +4. Pop off the stash you saved with `git stash pop`, and check status/diff. +5. Optional: Do the same but stash twice. Also check `git stash list`. + Can you pop the stashes in the opposite order? +6. Advanced: What happens if stashes conflict with other changes? Make + a change and stash it. Modify the same line or one right above or + below. Pop the stash back. Resolve the conflict. Note there is no + extra commit. +7. Advanced: what does `git graph` show when you have something + stashed? + +```{solution} +5: Yes you can. With `git stash pop INDEX` you can decie which stash +index to pop. + +6: In this case Git will ask us to resolve the conflict the same way +when resolving conflicts between two branches. + +7: It shows an additional commit hash with `refs/stash`. +``` +```` + + +## Option 2: Create branches + +You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch. + +You basically know how to do this: + +```console +$ git switch --create temporary # create a branch and switch to it +$ git add PATHS # stage changes +$ git commit # commit them +$ git switch main # back to main, continue your work there ... +$ git switch temporary # continue again on "temporary" where you left off +``` + +Later you can merge it to main or rebase it on top of main and resume work. + + +## Storing various junk you don't need but don't want to get rid of + +It happens often that you do something and don't need it, but you don't want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still. diff --git a/_sources/level.md.txt b/_sources/level.md.txt new file mode 100644 index 00000000..b191088c --- /dev/null +++ b/_sources/level.md.txt @@ -0,0 +1,120 @@ +# Practical advice: how much Git is necessary? + +:::{instructor-note} +- 20 min teaching/discussion +::: + + +## Writing useful commit messages + +Useful commit messages summarize the change and provide context. + +If you need a commit message that is longer than one line, +then the convention is: **one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary**. + +Good example: +```text +increase alpha to 2.0 for faster convergence + +the motivation for this change is +to enable ... +... +(more context) +... +this is based on a discussion in #123 +``` + +- **Why something was changed is more important than what has changed.** +- Cross-reference to issues and discussions if possible/relevant. +- Bad commit messages: "fix", "oops", "save work" +- Bad examples: [http://whatthecommit.com](http://whatthecommit.com) +- Write commit messages in English that will be understood + 15 years from now by someone else than you. Or by your future you. +- Many projects start out as projects "just for me" and end up to be successful projects + that are developed by 50 people over decades. +- [Commits with multiple authors](https://help.github.com/articles/creating-a-commit-with-multiple-authors/) are possible. + +Good references: + +- ["My favourite Git commit"](https://fatbusinessman.com/2019/my-favourite-git-commit) +- ["On commit messages"](https://who-t.blogspot.com/2009/12/on-commit-messages.html) +- ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) + +```{note} +A great way to learn how to write commit messages and to get inspired by their +style choices: **browse repositories of codes that you use/like**: + +Some examples (but there are so many good examples): +- [SciPy](https://github.com/scipy/scipy/commits/main) +- [NumPy](https://github.com/numpy/numpy/commits/main) +- [Pandas](https://github.com/pandas-dev/pandas/commits/main) +- [Julia](https://github.com/JuliaLang/julia/commits/master) +- [ggplot2](https://github.com/tidyverse/ggplot2/commits/main), + compare with their [release + notes](https://github.com/tidyverse/ggplot2/releases) +- [Flask](https://github.com/pallets/flask/commits/main), + compare with their [release + notes](https://github.com/pallets/flask/blob/main/CHANGES.rst) + +When designing commit message styles consider also these: +- How will you easily generate a changelog or release notes? +- During code review, you can help each other improving commit messages. +``` + +But remember: it is better to make any commit, than no commit. Especially in small projects. +**Let not the perfect be the enemy of the good enough**. + + +## What level of branching complexity is necessary for each project? + +**Simple personal projects**: +- Typically start with just the `main` branch. +- Use branches for unfinished/untested ideas. +- Use branches when you are not sure about a change. +- Use tags to mark important milestones. +- If you are unsure what to do with unfinished and not working code, commit it + to a branch. + +**Projects with few persons: you accept things breaking sometimes** +- It might be reasonable to commit to the `main` branch and feature branches. + +**Projects with few persons: changes are reviewed by others** +- You create new feature branches for changes. +- Changes are reviewed before they are merged to the `main` branch + (more about that in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). +- Consider to write-protect the `main` branch so that it can only be changed + with pull requests or merge requests. + + +## How about staging and committing? + +- Commit early and often: rather create too many commits than too few. + You can always combine commits later. +- Once you commit, it is very, very hard to really lose your code. +- Always fully commit (or stash) before you do dangerous things, so that you know you are safe. + Otherwise it can be hard to recover. +- Later you can start using the staging area (where you first stage and then commit in a second step). +- Later start using `git add -p` and/or `git commit -p`. + + +## How large should a commit be? + +- Better too small than too large (easier to combine than to split). +- Often I make a commit at the end of the day (this is a unit I would not like to lose). +- Smaller sized commits may be easier to review for others than huge commits. +- Imperfect commits are better than no commits. +- A commit should not contain unrelated changes to simplify review and possible + repair/adjustments/undo later (but again: imperfect commits are better than no commits). + +--- + +:::{keypoints} +- There is no one size fits all - start simple and grow your project. +::: + +:::{discussion} +How do you [plan to] use Git? + +- Advanced users or beginners, please provide your input in the online collaborative document. +::: diff --git a/_sources/local-workflow.md.txt b/_sources/local-workflow.md.txt new file mode 100644 index 00000000..1414d608 --- /dev/null +++ b/_sources/local-workflow.md.txt @@ -0,0 +1,371 @@ +# Cloning a Git repository and working locally + +If you've been following the main path, you have just had interacted +with repositories on GitHub. This might not be what you usually +do, so now we move to working on your own computer. + +:::{objectives} +- We are able to clone a repository from the web and modify it locally. +- We can do the same things we did before (commit, branch, merge), but locally. +- We get a feeling for remote repositories ([more later](https://coderefinery.github.io/git-collaborative/)). +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## What is in a Git repository and what are we cloning? + +**Git repository**: +- Contains all the files and directories of a project. +- Contains the complete history of all changes (commits) to these files and directories. +- Each commit is a snapshot of the entire project at a certain point in time and has a unique identifier ("hash"). +- Sometimes it contains multiple branches and tags. +- All the commits and history of a local repository are stored in a directory + called `.git` which is located at the root of the repository. + +**Cloning**: +- Copying (downloading) the entire repository with all commits, branches, and tags to your computer. +- It is a full backup of the repository, including all history. +- You can then work on your local clone of the repository. +- Changes on local clone will not automatically appear in the repository where + we cloned from. We have to actively "push" them there (we will practice this + in a later episode: {ref}`sharing-repositories`). + + +## Exercise + +Work on this by yourself or in your teams. Conceptually this episode should +seem familiar, from the browser-based exercises we did yesterday. + +We offer the **Command Line and VS Code** paths for this exercise. +GitHub isn't an option in this episode, since that is what we already +demonstrated in {doc}`commits` and {doc}`merging` and since the point of this +episode is to work **locally**. + +It is also possible to use the command line (terminal) from inside VS Code. + +```{exercise} Exercise: Cloning a Git repository and working locally (25 min) +1. {ref}`Configure Git command line and editor ` if you haven't done that already. +1. **Decide which repository you want to clone**: your fork or the original repository? Both will work for this exercise. + Then, **clone the recipe book**. +1. **Create a new branch**. +1. Make a **commit** on your new branch. +1. **Switch** back to the `main` branch and create one or two commits there. +1. **Merge** the new branch into `main`. +1. Compare the graph locally and on GitHub and observe that the **changes only exist locally on your computer**. +1. Where are the **remote branches**? Practice how you can see all remote branches + also locally and how you can fetch them and make local changes to them. +``` + +The solution below goes over most of the answer and should be used as +your guide (you can't figure it out just from the exercise instructions). + + +## Solution and walk-through + + +### (1) Configure Git command line and editor + +We have an own section for this: {ref}`configuration`. + + +### (2) Cloning a repository + +Now you need to decide which repository you want to clone. All of these options will work for this exercise +since we don't plan to push changes back (for step 8 it might be easier to use the original repository): +- Clone the recipe book from your fork. +- Or clone the recipe book from the original repository: +- Or first fork the original repository and then clone your fork. + +The examples below assume you are cloning the original repository. If you are cloning your fork, you should +replace `coderefinery` with your GitHub username. + +:::::::{tabs} +::::::{group-tab} Command line +If you are unsure whether you are using SSH or HTTPS, please read {ref}`clone-method`. + :::::{tabs} + ::::{group-tab} SSH + ```console + $ git clone git@github.com:coderefinery/recipe-book.git + ``` + :::: + + ::::{group-tab} HTTPS + ```console + $ git clone https://github.com/coderefinery/recipe-book.git + ``` + :::: + ::::: + +This creates a directory called "recipe-book" unless it already exists. You can also specify the target directory +on your computer (in this case "my-recipe-book"): + :::::{tabs} + ::::{group-tab} SSH + ```console + $ git clone git@github.com:coderefinery/recipe-book.git my-recipe-book + ``` + :::: + + ::::{group-tab} HTTPS + ```console + $ git clone https://github.com/coderefinery/recipe-book.git my-recipe-book + ``` + :::: + ::::: +:::::: + +::::::{group-tab} VS Code +Under "Start" on the screen, select "Clone Git Repository...". + +Alternatively navigate to the "Source Control" tab on the left sidebar and +click on the "Clone Repository" button. + +Paste in this URL: `https://github.com/USER/recipe-book` (replace `USER`) +:::::: +::::::: + + +### (3) Creating branches locally + +:::::{tabs} +::::{group-tab} Command line +Create a new branch called `another-recipe` from `main` and switch to it: +```console +$ git switch --create another-recipe main +``` + +If you leave out the last argument, it will create a branch from the current +branch: +```console +$ git switch --create another-recipe +``` +:::: + +::::{group-tab} VS Code +1. Make sure that you are on the main branch. +1. Source Control button on left sidebar → Three dots in upper right of source control → Branch → Create Branch. +1. VS Code automatically switches to the new branch. + +:::{figure} img/commits/vscode-create-branch.png +:width: 80% +:class: with-border +:alt: VS Code screenshot of create branch + +Creating a new branch in VS Code. +:::: +::::: + + +### (4) Creating commits locally + +:::::{tabs} +::::{group-tab} Command line +Create a new file. **After we have created it**, we can stage and commit +the change: +```console +$ git add new-file.md +$ git commit -m "Short summary of the change" +``` + +Make sure to replace "new-file.md" with the actual name of the file you created +and to replace "Short summary of the change" with a meaningful commit message. +:::: + +::::{group-tab} VS Code +1. Create a new file. +1. In the version control sidebar, click the `+` sign to add the file for the next commit. +1. Enter a brief message and click "Commit". + +:::{figure} img/commits/vscode-add-and-commit.png +:alt: Screenshot of VS Code commit process +:width: 80% +:class: with-border + +Committing a new file in VS Code. +::: +:::: +::::: + + +### (5) Switching branches and creating commits + +:::::{tabs} +::::{group-tab} Command line +First switch to the `main` branch: +```console +$ git switch main +``` + +Then modify a file. Finally `git add` and then commit the change: +```console +$ git commit -m "Short summary of the change" +``` +:::: + +::::{group-tab} VS Code +Use the branch selector at the bottom to switch back to the main branch. +Repeat the same steps as above. + +:::{figure} img/commits/vscode-change-branch.png +:class: with-border +:width: 80% +:alt: VS Code screenshot + +Switching branch via selector at bottom. +:::: +::::: + + +### (6) Merging branches locally + +:::::{tabs} +::::{group-tab} Command line +On the command line, when we merge, we always modify our current branch. + +If you are not sure anymore what your current branch is, type: +```console +$ git branch +``` + +Another way to find out where we are in Git: +```console +$ git status +``` + +In this case we merge the `another-recipe` branch into our current branch: +```console +$ git merge another-recipe +``` +:::: + +::::{group-tab} VS Code +Just like with the command line, when we merge we modify our *current* branch. Verify you are on the `main` branch. + +1. Verify current branch at the bottom. +1. From the version control sidebar → Three dots → Branch → Merge +1. In the selector that comes up, choose the branch you want to merge *from*. The commits on that branch will be added to the current branch. + +:::{figure} img/merging/vscode-merging.png +:alt: VSCode screenshot as described +:width: 80% +:class: with-border +:::: +::::: + + +### (7) How to compare the graph locally and on GitHub + +:::::{tabs} +::::{group-tab} Command line +```console +$ git log --graph --oneline --decorate --all +``` + +We recommend to define an {term}`alias` in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command: +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` +Then you can just type `git graph` from there on. We have an own section about +aliases: {ref}`aliases`. + +Compare this with the graph on GitHub: Insights tab → Network view (just like +we have done before). + +The result is that we should not be able to see the new branch and the new +commits on GitHub. +:::: + +::::{group-tab} VS Code +This requires an extension. Opening the VS Code terminal lets you use the command line method. + +:::{figure} img/commits/vscode-open-terminal.png +:class: with-border +:width: 80% +:alt: VS Code screenshot as described + +View → Terminal will open a terminal at bottom. This is a normal command line interface and very useful for work. (Note the git-aware prompt that shows the current branch. This requires other setup.) +:::: +::::: + + +### (8) Browsing remote branches and creating local branches from them + +:::::{tabs} +::::{group-tab} Command line +With `git branch` you can list all local branches: +```console +$ git branch + + another-recipe +* main +``` + +But where are the remote branches? We expect to see [a couple of +them](https://github.com/coderefinery/recipe-book/branches/all). + +We can see them by asking for all branches (your output might vary depending on +where you cloned from): +```console +$ git branch --all + + another-recipe +* main + remotes/origin/HEAD -> origin/main + remotes/origin/alex/fruit-salad + remotes/origin/main + remotes/origin/radovan/lasagna + remotes/origin/radovan/poke +``` + +You can create a local branch from a remote branch which will "track" the remote branch. +For instance, to create a local branch `alex/fruit-salad` from the remote branch `origin/alex/fruit-salad` +and switch to it, you can do: +```console +$ git switch --create alex/fruit-salad origin/alex/fruit-salad +``` + +This shortcut will do the same thing: +```console +$ git switch --track origin/alex/fruit-salad +``` + +Or even shorter: +```console +$ git switch alex/fruit-salad +``` + +If you want to create a branch and not switch to it, you can use `git branch`. +```console +$ git branch alex/fruit-salad +``` +:::: + +::::{group-tab} VS Code +To create a local branch from a remote branch: + +Source Control button on left sidebar → Three dots in upper right of source control → Branch → +"Create Branch From ...". + +Then select the remote branch you want to create a local branch from. +:::: +::::: + + +## Summary + +- When we clone a repository, we get a full backup of the repository, including + all history: all commits, branches, and tags. +- Yesterday we learned about branches and commits, and now we created and used them locally. +- **Creating local branches and commits does not automatically modify the remote + repository**. To "push" our local changes to the remote repository, we have to actively + "push" them there. We will practice this in a later episode: + {ref}`sharing-repositories` +- Remote branches and local branches are not the same thing. If we want to + create local commits, we always need to create a local branch first. But the local branch can + "track" the remote branch and we can push and pull changes to and from the + remote branch. diff --git a/_sources/merging.md.txt b/_sources/merging.md.txt new file mode 100644 index 00000000..8bfba557 --- /dev/null +++ b/_sources/merging.md.txt @@ -0,0 +1,435 @@ +# Merging changes and contributing to the project + +Git allows us to have different development lines where we can try things out. +It also allows different people to work on the same project at the same. This +means that we have to somehow combine the changes later. In this part we will +practice this: {term}`merging`. + +:::{objectives} +- Understand that on GitHub merging is done through a {term}`pull request`. Think of it as a change proposal. +- Create and merge a pull request within your own repository. +- Understand (and optionally) do the same across repositories, to contribute to + the {term}`upstream` public repository. +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## Background + +* In the last episode, we added a new recipe on a branch. This allows + us to test it before it becomes "live". +* Now, we want to bring that change into the "main" branch. +* We will find it's not that hard! But you do have to keep track of the + steps and make sure that you work very precisely. + + +## Exercise + +In this exercise, we will show how we can **propose changes** and **merge +changes** within our own repository. Optionally, you can propose a recipe to +the {term}`upstream` recipe book - which shows the true purpose of this. But +this is only a preview and we will practice collaboration much more in the +[collaborative Git lesson](https://coderefinery.github.io/git-collaborative/). + +We offer **three different paths** of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the **GitHub +path** only and recommend you do that. The exercise text below has +some GitHub-specific notes, but most is possibly with any path. + +:::::{tabs} +::::{group-tab} GitHub + +First, we make something called a {term}`pull request`, which allows +review and commenting before the actual merge. + +:::{exercise} Exercise: Merging branches with pull requests (20 min) +We assume that in the previous exercise you have created a new branch +with a recipe. In our previous example, it is called `new-recipe`. +If not, create it first and add a recipe to your new branch, see +{doc}`commits`. + +We provide basic hints. You should refer to the solution as needed. + +1. Navigate to your branch from the previous episode + (Hint: the same branch view we used last time). + +1. Begin the pull request process. + (Hint: There is a "Contribute" button in the branch view). + +1. Add or modify the pull request title and description, and verify the other data. + In the pull request verify the target repository and the target + branch. Make sure that you are merging within your own repository. + **GitHub: By default, it will offer to make the change to the + upstream repository, `coderefinery`. You should change this**, you + shouldn't contribute your test recipe upstream yet. Where it says + `base repository`, select your own user's repository. + +1. Create the pull request by clicking "Create pull request". Browse + the network view to see if anything has changed yet. + +1. Merge the pull request, or if you are not on GitHub you can merge + the branch locally. Browse the network again. What has changed? + +1. Find out which branches are merged and thus safe to delete. Then remove them + and verify that the commits are still there, only the branch labels are + gone. (Hint: you can delete branches that have been merged into `main`). + +1. Optional: Try to create a new branch with a new change, then open a pull + request but towards the central repository. We will later merge few of + those. + (Hint: this is mostly the same as above, for the GitHub path. But, + you set the base repository as CodeRefinery. You might need to + compare across forks.) +::: +:::: + +::::{group-tab} Local (VS Code, Command line) + +When working locally, it's easier to merge branches: we can just do +the merge, without making a pull request. But we don't have that step +of review and commenting and possibly adjusting. + +:::{exercise} + +1. Switch to the `main` branch that you want to merge the *other* + branch into. (Note that this is the other way around from the + GitHub path). + +Then: + +5. Merge the other branch into `main` (which is then your current branch). + +6. Find out which branches are merged and thus safe to delete. Then remove them + and verify that the commits are still there, only the branch labels are + gone. (Hint: you can delete branches that have been merged into `main`). + +7. (optional, advanced) Try to create a new branch, and make a + GitHub pull request with your recipe, and contribute it to our + upstream repository. *This is very complex right now since your + change has to get to GitHub, and we haven't shown that yet. We + don't give a solution for this.* +::: + +:::: +::::: + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by design. + + +## Solution and walk-through + +### (1) Navigate to your branch + +Before making the pull request, or doing a merge, it's important to +make sure that you are on the right branch. Many people have been +frustrated because they forgot this! + +:::::{tabs} +::::{group-tab} GitHub +On GitHub make sure you are on the branch you want to merge **from**: + :::{figure} img/merging/github-navigate-to-branch.png + :alt: Screenshot on GitHub where we navigate to the branch we wish to merge. + :width: 80% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +Remember, you need to switch to the `main` branch, the branch we want to merge **to**. +This is different from the GitHub path. +:::: + +::::{group-tab} Command line +Remember, you need to switch to the `main` branch, the branch we want to merge **to**. +This is different from the GitHub path: +```console +$ git switch main +``` +:::: +::::: + + +### (2) Begin the pull request process + +In GitHub, the pull request is the way we propose to merge two +branches together. We start the process of making one. + +:::::{tabs} +::::{group-tab} GitHub + :::{figure} img/merging/github-contribute.png + :alt: Screenshot on GitHub where we get to the pull request process. + :width: 80% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +It is possible to open pull requests from the editor, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +It is possible to open pull requests from the command line, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: +::::: + + +### (3) Fill out and verify the pull request + +Check that the pull request is directed to the right repository and branch +and that it contains the changes that you meant to merge. + +:::::{tabs} +::::{group-tab} GitHub +Things to check: +- Base repository: this should be your own +- Title: make it descriptive +- Description: make it informative +- Scroll down to see commits: are these the ones you want to merge? +- Scroll down to see the changes: are these the ones you want to merge? + :::{figure} img/merging/github-comparing-changes.png + :alt: Screenshot on GitHub where we verify the changes we want to merge. + :width: 80% + :class: with-border + + This screenshot only shows the top part. If you scroll down, you + can see the commits and the changes. We recommend to do this before + clicking on "Create pull request". + ::: +:::: + +::::{group-tab} VS Code +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +If you are working locally, continue to step 5. +:::: +::::: + + +### (4) Create the pull request + +We actually create the pull request. Don't forget to navigate to the Network +view after opening the pull request. Note that the changes proposed in the +pull request are not yet merged. + +:::::{tabs} +::::{group-tab} GitHub +Click on the green button "Create pull request". + +If you click on the little arrow next to "Create pull request", you can also +see the option to "Create draft pull request". This will be interesting later +when collaborating with others. It allows you to open a pull request that is +not ready to be merged yet, but you want to show it to others and get feedback. +:::: + +::::{group-tab} VS Code +It is possible to create pull requests from the editor, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +It is possible to create pull requests from the command line, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: +::::: + + +### (5) Merge the pull request + +Now, we do the actual merging. We see some effects now. + +:::::{tabs} +::::{group-tab} GitHub +Review it again (commits and changes), and then click "Merge pull request". + +After merging, verify the network view. Also navigate then to your "main" +branch and check that your new recipe is there. +:::: + +::::{group-tab} VS Code +Just like with the command line, when we merge we modify our *current* branch. Verify you are on the `main` branch. + +1. Verify current branch at the bottom. +1. From the version control sidebar → Three dots → Branch → Merge +1. In the selector that comes up, choose the branch you want to merge *from*. The commits on that branch will be added to the current branch. + +:::{figure} img/merging/vscode-merging.png +:alt: VSCode screenshot as described +:width: 80% +:class: with-border +:::: + +::::{group-tab} Command line +On the command line, when we merge, we always modify our *current* branch. + +If you are not sure anymore what your current branch is, type: +```console +$ git branch +``` +... or equally useful to see where we are right now: +```console +$ git status +``` + +In this case we merge the `new-recipe` branch into our current branch: +```console +$ git merge new-recipe +``` +:::: +::::: + + +### (6) Delete merged branches + +Before deleting branches, first check whether they are merged. + +If you delete an un-merged branch, it will be difficult to find the commits +that were on that branch. If you delete a merged branch, the commits are now +also part of the branch where we have merged to. + +:::::{tabs} +::::{group-tab} GitHub +One way to delete the branch is to click on the "Delete branch" button after the pull +request is merged: + :::{figure} img/merging/github-merged.png + :alt: Screenshot on GitHub suggesting us to delete a branch after it has been merged. + :width: 80% + :class: with-border + ::: + +But what if we forgot? Then navigate to the branch view: + :::{figure} img/merging/github-branches.png + :alt: Screenshot on GitHub where we navigate to the branches view. + :width: 80% + :class: with-border + ::: + +In the overview we can see that it has been merged and we can delete it: + :::{figure} img/merging/github-branches-overview.png + :alt: Screenshot on GitHub where we see an overview of branches and can delete them. + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +From the Source Control sidebar → the three dots (as before) → Branch → Delete Branch. Select the branch name to delete. +:::: + +::::{group-tab} Command line +Verify which branches are merged to the current branch: +```console +$ git branch --merged + +* main + new-recipe +``` + +This means that it is safe to delete the `new-recipe` branch: +```console +$ git branch -d new-recipe +``` + +Verify then that the branch is gone but that the commits are still there: +```console +$ git branch +$ git log --oneline +``` +:::: +::::: + + +### (7) Contribute to the original repository with a pull request + +Remember, this is an advanced step. If you do this, you are donating +a recipe to everyone. + +:::::{tabs} +::::{group-tab} GitHub +Now that you know how to create branches and opening a pull request, try to +open a new pull request with a new change but this time the base repository +should be the upstream one. + +In other words, you now send a pull request across repositories: from your fork +to the original repository. + +Another thing that is different now is that you might not have permissions to +merge the pull request. We can then together review and browse the pull +request. +:::: + +::::{group-tab} VS Code +Not described. We will return to this in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +You would create a new branch locally like above, {term}`push` it to GitHub to your own user's repository `USER/recipe-book`, then go to GitHub and open a pull request *to* `coderefinery/recipe-book`. Or you do it all through VS Code. +:::: + +::::{group-tab} Command line +Not described. We will return to this in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +You would create a new branch locally like above, {term}`push` it to GitHub to your own user's repository `USER/recipe-book`, then go to GitHub and open a pull request *to* `coderefinery/recipe-book`. + +:::: +::::: + + +## Resolving a conflict (demonstration) + +A conflict is when Git asks humans to decide during a merge which of two +changes to keep if the same portion of a file has been changed in two different +ways on two different branches. + +We will practice conflict resolution in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +Here we will only demonstrate how to create a conflict and how to resolve it, +all on GitHub. Once we understand how this works, we will be more confident to +resolve conflicts also in the command line. + +How to create a conflict (please try this in your own time *and just watch now*): +- Create a new branch from `main` and on it make a change to a file. +- On `main`, make a different change to the same part of the same file. +- Now try to merge the new branch to `main`. You will get a conflict. + +How to resolve conflicts: +- On GitHub, you can resolve conflicts by clicking on the "Resolve conflicts" + button. This will open a text editor where you can choose which changes to + keep. + Make sure to remove the conflict markers. + After resolving the conflict, you can commit the changes and merge the + pull request. +- Sometimes a conflict is between your change and somebody else's change. In + that case, you might have to discuss with the other person which changes to + keep. + +How to avoid conflicts: +- We will talk about it in the [collaborative Git + lesson](https://coderefinery.github.io/git-collaborative/). + + +## Summary + +- We learned how to merge two branches together. +- When is this useful? This is not only useful to combine development lines in + your own work. Being able to merge branches also forms a basis for collaboration. +- Branches which are merged to other branches are safe to delete, since we only + delete the "sticky note" next to a commit, not the commits themselves. diff --git a/_sources/motivation.md.txt b/_sources/motivation.md.txt new file mode 100644 index 00000000..60c0e11c --- /dev/null +++ b/_sources/motivation.md.txt @@ -0,0 +1,184 @@ +# Motivation + +```{objectives} +- Make sure nobody leaves the workshop without starting to use some form of version control. +- Discuss the reasons why we advocate distributed version control. +``` + +```{instructor-note} +- 15 min discussion/demonstration +``` + + +## Git is all about keeping track of changes + +We will learn how to keep track of changes first in the web browser. +Below are screenshots of **tracked changes with Git** +(from this [example repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): +```{figure} img/git-log-github.png +:alt: Screenshot of a git log on GitHub +:width: 80% +:class: with-border + +Web browser, GitHub view +``` +Later also using the terminal or the editor +(the same [example repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): +```{figure} img/git-log-terminal.png +:alt: Screenshot of a git log in terminal +:width: 80% + +The same as above, but the terminal view +``` + + +## Why do we need to keep track of versions? + +**Problem: If you have to identify and find your code from 17 days +ago, can you?** + +Version control is an answer to the following questions (do you recognize some +of them?): + +- "It broke ... hopefully I have a working version somewhere?" + +- "Can you please send me the latest version?" + +- "Where is the latest version?" + +- "Which version are you using?" + +- "Which version have the authors used in the paper I am trying to reproduce?" + +- "Found a bug! Since when was it there?" + +- "I am sure it used to work. When did it change?" + +- "My laptop is gone. Is my thesis now gone?" + + +## Features: roll-back, branching, merging, collaboration + +**Problem: Your code worked two days ago, but is giving an error now. +You don't know what you changed.** + +**Problem: You and your colleague want to work on the same code at the +same time.** + + +- **Roll-back**: you can always go back to a previous version and compare + +- **Branching and merging**: + - Work on different ideas at the same time + - Different people can work on the same code/project without interfering + - You can experiment with an idea and discard it if it turns out to be a bad idea + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +- **Collaboration**: review, compare, share, discuss + +- [Example network graph](https://github.com/coderefinery/git-intro/network) + + +## Reproducibility + +**Problem: Someone asks you about your results from 5 years ago. Can +you get the same results now?** + +- How do you indicate which version of your code you have used in your paper? +- When you find a bug, how do you know **when precisely** this bug was introduced + (Are published results affected? Do you need to inform collaborators or users of your code?). + +With version control we can "annotate" code +([browse this example online](https://github.com/networkx/networkx/blame/main/networkx/algorithms/boundary.py)): + +```{figure} img/git-annotate.png +:alt: Example of a git-annotated code with code and history side-by-side +:width: 100% +:class: with-border + +Example of a git-annotated code with code and history side-by-side. +``` + + +## Talking about code + +**Problem: You want to show someone a few lines from one of your projects.** + +Which of these two is more practical? +- "Clone the code, go to the file 'src/util.rs', and search for 'time_iso8601'". + Oh! But make sure you use the version from August 2023." +- Or I can send you a [permalink](https://github.com/NordicHPC/sonar/blob/75daafc86582feb06299d6a47c82112f39888152/src/util.rs#L40-L44): + +```{figure} img/code-portion.png +:alt: Screen-shot of a code portion +:width: 100% +:class: with-border + +Permalink that points to a code portion. +``` + + +## What we typically like to snapshot + +- Software (this is how it started but Git/GitHub can track a lot more) +- Scripts +- Documents (plain text files much better suitable than Word documents) +- Manuscripts (Git is great for collaborating/sharing LaTeX or [Quarto](https://quarto.org/) manuscripts) +- Configuration files +- Website sources +- Data + +````{discussion} + In this example somebody tried to keep track of versions without a version + control system tool like Git. Discuss the following directory listing. What + possible problems do you anticipate with this kind of "version control": + ```shell + myproject-2019.zip + myproject-2020-February.zip + myproject-2021-August.zip + myproject-2023-09-19-working.zip + myproject-2023-09-21.zip + myproject-2023-09-21-test.zip + myproject-2023-09-21-myversion.zip + myproject-2023-09-21-newfeature.zip + ... + ``` + + ```{solution} + - Giving a version to a collaborator and merging changes later with own + changes sounds like lots of work. + - What if you discover a bug and want to know since when the bug existed? + ``` +```` + + +## Difficulties of version control + +Despite the benefits, let's be honest, there are some difficulties: + +- One more thing to learn (it's probably worth it and will save you more time in the long run; basic career skill). +- Difficult if your collaborators don't want to use it (in the worst case, you can version control on your side and email them versions). +- Advanced things can be difficult, but basics are often enough (ask others for help when needed). + + +## Why Git and not another tool? + +- **Easy to set up**: no server needed. +- **Very popular**: chances are high you will need to contribute to somebody else's code which is tracked with Git. +- **Distributed**: good backup, no single point of failure, you can track and + clean-up changes offline, simplifies collaboration model for open-source + projects. +- Important **platforms** such as [GitHub](https://github.com), [GitLab](https://gitlab.com), and [Bitbucket](https://bitbucket.org) + build on top of Git. + +However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +[Subversion](https://subversion.apache.org), +[Mercurial](https://www.mercurial-scm.org), [Pijul](https://pijul.org/), or others. diff --git a/_sources/recovering.md.txt b/_sources/recovering.md.txt new file mode 100644 index 00000000..3c705f3e --- /dev/null +++ b/_sources/recovering.md.txt @@ -0,0 +1,260 @@ +# Undoing and recovering + +```{objectives} +- Learn to undo changes safely +- See when undone changes are permanently deleted and when they can be retrieved +``` + +```{instructor-note} +- 25 min teaching/type-along +- 25 min exercise +``` + +One of the main points of version control is that you can *go back in +time to recover*. Unlike this xkcd comic implies: + +In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn't a "commit" permanent? + +- You can modify old commit history. +- But if you have shared that history already, *modifying it can make + a huge mess*. + +```{admonition} It is almost always possible to recover +As long as you commit something once (or at least `git add` it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru... *until that guru becomes you*. +``` + +```{admonition} Nice resource to visually simulate Git operation +[git-sim](https://github.com/initialcommit-com/git-sim#video-animation-examples) +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command. +``` + +--- + +## Undoing your recent, uncommitted and unstaged changes (preserves history) + +```{note} +In case `git restore` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git restore`. +``` + +You do some work, and want to **undo your uncommitted and unstaged modifications**. +You can always do that with: + +- `git restore .` (the dot means "here and in all folders below") + +You can also undo things selectively: + +- `git restore -p` (decide which portions of changes to undo) or `git restore PATH` (decide which path/file) + +If you have staged changes, you have at least two options to undo the staging: +- `git restore --staged .` followed by `git status` and `git restore .` +- `git reset --hard HEAD` throws away everything that is not in last + commit (`HEAD` - this literal word, this isn't a placeholder) + +--- + +## Reverting commits (preserves history) + +Imagine we made a few commits. +We realize that the latest commit `e02efcd` was a mistake and we wish to undo it: +```console +$ git log --oneline + +e02efcd (HEAD -> main) not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +A safe way to undo the commit is to revert the commit with `git revert`: +```console +$ git revert e02efcd +``` + +This creates a **new commit** that does the opposite of the reverted commit. +The old commit remains in the history: +```console +$ git log --oneline + +d3fc63a (HEAD -> main) Revert "not sure this is a good idea" +e02efcd not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +You can revert any commit, no matter how old it is. It doesn't affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we'll learn about later). + +(exercise-revert)= + +### Exercise: Revert a commit + +```{exercise} Undoing-1: Revert a commit +- Create a commit (commit A). +- Revert the commit with `git revert` (commit B). +- Inspect the history with `git log --oneline`. +- Now try `git show` on both the reverted (commit A) and the newly created commit (commit B). +``` + + +## Adding to the previous commit (modifies history) + +Sometimes we commit but realize we forgot something. +We can amend to the last commit: + +```console +$ git commit --amend +``` + +This can also be used to modify the last commit message. + +Note that this **will change the commit hash**. This command **modifies the history**. +This means that we avoid this command on commits that we have shared with others. + +(exercise-amend)= + +### Exercise: Modify a previous commit + +````{exercise} Undoing-2: Modify a previous commit +1. Make an incomplete change to the recipe or a typo in your change, `git + add` and `git commit` the incomplete/unsatisfactory change. +2. Inspect the unsatisfactory but committed change with `git show`. Remember + or write down the commit hash. +3. Now complete/fix the change but instead of creating a new commit, add the + correction to the previous commit with `git add`, followed by `git commit + --amend`. What changed? + + ```{solution} + One thing that has changed now is the commit hash. Modifying the previous + commit has changed the history. This is OK to do on commits that other people + don't depend on yet. + ``` +```` + + +## Rewinding branches (modifies history) + +You can **reset branch history** to move your branch back to some +point in the past. + +* `git reset --hard HASH` will force a branch label to any other point. All + other changes are lost (but it is possible to recover if you force reset by mistake). +* Be careful if you do this - it can mess stuff up. Use `git graph` a + lot before and after. + + +(exercise-reset)= + +### Exercise: Git reset + +````{exercise} Undoing-3: Destroy our experimentation in this episode + After we have experimented with reverts and amending, let us destroy + all of that and get our repositories to a similar state. + + - First, we will look at our history (`git log`/`git graph`) and + find the last commit `HASH` before our tests. + - Then, we will `git reset --hard HASH` to that. + - Then, `git graph` again to see what happened. + + ```console + $ git log --oneline + + d3fc63a (HEAD -> main) Revert "not sure this is a good idea" + e02efcd not sure this is a good idea + b4af65b improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + + $ git reset --hard b4af65b + + HEAD is now at b4af65b improve the documentation + + $ git log --oneline + + b4af65b (HEAD -> main) improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + ``` +```` + +--- + +## Recovering from committing to the wrong branch + +It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes. + +Here we assume that we made a couple of commits but we realize they went to the +wrong branch. + +**Solution 1 using git cherry-pick**: +1. Make sure that the correct branch exists and if not, create it. Make sure to + create it from the commit hash where you wish you had created it from: `git + branch BRANCHNAME HASH` +2. Switch to the correct branch. +3. `git cherry-pick HASH` can be used to take a specific commit to the + current branch. Cherry-pick all commits that should have gone to the correct + branch, **from oldest to most recent**. +4. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + +**Solution 2 using `git reset --hard`** (makes sense if the correct branch should +contain all commits of the accidentally modified branch): +1. Create the correct branch, pointing at the latest commit: `git branch BRANCHNAME`. +2. Check with `git log` or `git graph` that both branches point to the same, latest, commit. +3. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + + +## Recovering from merging/pulling into the wrong branch + +`git merge`, `git rebase`, and `git pull` modify the **current** branch, never +the other branch. But sometimes we run this command on the wrong branch. + +1. Check with `git log` the commit hash that you would like to rewind the + wrongly modified branch to. +2. Rewind the branch that accidentally got wrong commits with `git reset --hard HASH` (see also above). + + +## Recovering from conflict after pulling changes + +Pulling changes with +`git pull` can create a conflict since `git pull` always also includes a `git merge` (more about this +in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). + +The recovery is same as described in {ref}`conflict-resolution`. Either +resolve conflicts or abort the merge with `git merge --abort`. + +--- + +````{challenge} Undoing-4: Test your understanding + 1. What happens if you accidentally remove a tracked file with `git rm`, is it gone forever? + 2. Is it OK to modify commits that nobody has seen yet? + 3. What situations would justify to modify the Git history and possibly remove commits? + + ```{solution} + 1. It is not gone forever since `git rm` creates a new commit. You can revert the commit to get the file back. + 2. If you haven't shared your commits with anyone it can be alright to modify them. + 3. If you have shared your commits with others (e.g. pushed them to GitHub), only extraordinary + conditions would justify modifying history. For example to remove sensitive or secret information. + ``` +```` diff --git a/_sources/reference.md.txt b/_sources/reference.md.txt new file mode 100644 index 00000000..80a5cce8 --- /dev/null +++ b/_sources/reference.md.txt @@ -0,0 +1,158 @@ +# Quick reference + +## Other cheatsheets + +* [Detailed 2-page Git + cheatsheet](https://aaltoscicomp.github.io/cheatsheets/git-the-way-you-need-it-cheatsheet.pdf) +* [Interactive Git cheatsheet](http://www.ndpsoftware.com/git-cheatsheet.html) + + +## Glossary + +:::::{glossary} + +alias + With aliases you can define your own shortcuts for Git commands. + +version control system + A system that records changes to a file or set of files over time so that + you can recall specific versions later. + +git + Implementation of a version control system. Currently the most popular one. + +commit + As a verb, the process of recording more changes. + As a noun, the name of the record of changes. + A commit is identified by something such as `554c187`. + +working directory +workspace + the actual files you see and edit + +staging area + Place files go after `git add` and before `git commit` + +hash + Unique reference of any commit or state. Comes from [hash + functions](https://en.wikipedia.org/wiki/Hash_function) such as MD5 + or SHA1. + +branch + One line of work. Different branches can exist at the same time + and split/merge. Committing on a branch updates that branch. + +tag + Like a {term}`branch` in that it points to a commit for reference. + It is designed to be permanent an not updated. + +HEAD + Pointer to the most recent commit on the current branch. + +remote + Roughly, another server that holds .git. + +origin + Default name for a remote repository. + +repository + One collection of files managed by Git. It contains entire history + of all files managed by git. GitHub has one repository as one + GitHub repository. VS Code has one repository as one directory you + can open. The command line has one repository as one directory. + +clone + As a verb, the process of making a copy of a repository locally. + It brings in all history and all files. (As a noun, the copy that + was made when cloning). + +GitHub repository + The files from the Git repository, but also other things from + GitHub such as access permissions, issues, and pull requests. + +upstream + The original repository from which the code comes. If you + {term}`fork` the repository, it is your upstream and it is easy to + send changes back to there. + +fork + As a noun: a one person's copy of a repository. + As a verb: making that copy. + As a verb on GitHub: Making a copy of a repository linked to the + original. It is easy to send changes to the original + +issue + Within a web repository like GitHub, discussion of a topic, for + example a problem or improvement suggestion. These are a property + of the web platform and not of the Git program itself. + +pull request + A GitHub concept: change proposal. A proposal to merge one branch + into another. Usually used to contribute code back to + {term}`upstream`. + +push + Moving changes from your local copy to another copy + +pull + Getting changes from another copy to your own copy. `git pull` + does this fetch, and also tries to automatically merge. + +master + Default name for main branch on Git. Depending on the configuration and service, + the default branch is sometimes **main**. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. + +main + Default name for main branch on GitLab and GitHub. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. + +merge +merging + Bringing changes from one branch into another, either as a noun or + verb. + +VS Code + A text editor and development environment by Microsoft. It's quite + popular, partly because it is powerful and easy to use. [VS + Codium](https://vscodium.com/) is the same but without Microsoft + tracking. +::::: + +## Commands we use + +Setup: + +* `git config`: edit configuration options +* `git init -b main`: create new repository with `main` as the default branch + +See our status: + +* `git status`: see status of files - use often! +* `git log`: see history of commits and their messages, newest first +* `git graph`: see a detailed graph of commits. Create this command + with `git config --global alias.graph "log --all --graph --decorate --oneline"` +* `git diff`: show difference between working directory and last commit +* `git diff --staged`: show difference between staging area and last commit +* `git show COMMIT`: inspect individual commits + +General work: + +* `git add FILE`: + - Add a new file + - Add a file to staging +* `git commit`: record a version, add it to current branch +* `git commit --amend`: amend our last commit +* `git branch`: show which branch we're on +* `git branch NAME`: create a new branch called "name" +* `git restore FILE`: restore last committed/staged version of FILE, losing unstaged changes +* `git switch --create BRANCH-NAME`: create a new branch and switch to it +* `git revert HASH`: create a new commit which reverts commit HASH +* `git reset --soft HASH`: remove all commits after HASH, but keep their modifications as staged changes +* `git reset --hard HASH`: remove all commits after HASH, permanently throwing away their changes +* `git merge BRANCH-NAME`: merge branch BRANCH-NAME into current branch +* `git grep PATTERN`: search for patterns in tracked files +* `git annotate FILE`: find out when a specific line got introduced and by whom +* `git bisect`: find a commit which broke some functionality diff --git a/_sources/resources.md.txt b/_sources/resources.md.txt new file mode 100644 index 00000000..564f5247 --- /dev/null +++ b/_sources/resources.md.txt @@ -0,0 +1,11 @@ +# Other resources + +- [Learn Git branching](http://pcottle.github.io/learnGitBranching/) +- [The entire Pro Git book, written by Scott Chacon and Ben Straub](http://git-scm.com/book) +- [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) +- [Commit Often, Perfect Later, Publish Once: Git Best Practices](http://sethrobertson.github.io/GitBestPractices/) +- [PeepCode Git Internals](https://github.com/pluralsight/git-internals-pdf/releases) +- [Git Workflows for Pros: A Good Git Guide](https://www.toptal.com/git/git-workflows-for-pros-a-good-git-guide) +- [Branch-per-Feature](http://dymitruk.com/blog/2012/02/05/branch-per-feature/) +- [Git on XKCD](http://xkcd.com/1597/) +- [An efficient GIT workflow for mid/long term projects](http://fle.github.io/an-efficient-git-workflow-for-midlong-term-projects.html) diff --git a/_sources/sharing.md.txt b/_sources/sharing.md.txt new file mode 100644 index 00000000..661e96d7 --- /dev/null +++ b/_sources/sharing.md.txt @@ -0,0 +1,300 @@ +(sharing-repositories)= + +# How to turn your project to a Git repo and share it + +:::{objectives} +- Turn our own coding project (small or large, finished or unfinished) into a + Git repository. +- Be able to share a repository on the web to have a backup or so that others + can reuse and collaborate or even just find it. +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## Exercise + +:::::{exercise} Exercise: Turn your project to a Git repo and share it (25 min) + +1. Create a new directory called **myproject** with one or few files in it. + This represents our own project. It is not yet a Git repository. You can try + that with your own project or use a simple placeholder example. +2. Turn this new directory into a Git repository. +3. Share this repository on GitHub (or GitLab, since it really works the same). + +We offer **three different paths** of how to do this exercise. +* Via **GitHub web interface**: easy and can be a good starting point if you are completely + new to Git. +* **VS Code** is quite easy, since VS Code can offer to create the + GitHub repositories for you. +* **Command line**: you need to create the + repository on GitHub and link it yourself. + +::::{tabs} + +:::{group-tab} Only using GitHub +### Create an repository on GitHub + +First log into GitHub, then follow the screenshots and descriptions below. +```{figure} img/sharing/new-repository.png +:alt: Screenshot on GitHub before a new repository form is opened +:width: 60% +:class: with-border + +Click on the "plus" symbol on top right, then on "New repository". +``` + +Then: +```{figure} img/sharing/create-repository-with-readme.png +:alt: Screenshot on GitHub just before a new repository is created +:width: 100% +:class: with-border + +Choose a repository name, add a short description, and in this case **make sure to check** "Add a +README file". Finally "Create repository". +``` + + +### Upload your files + +Now that the repository is created, you can upload your files: +```{figure} img/sharing/upload-files.png +:alt: Screenshot on GitHub just before uploading files +:width: 100% +:class: with-border + +Click on the "+" symbol and then on "Upload files". +``` +::: + +:::{group-tab} VS Code +In VS Code it only takes few clicks. + +First, open the folder in VS Code. My example project here contains two files. +Then click on the source control icon: +```{figure} img/sharing/vscode-start.png +:alt: Screenshot of VS Code before clicking on the source control icon +:width: 100% +:class: with-border + +Open the folder in VS Code. Then click on the source control icon. +``` + +```{figure} img/sharing/vscode-publish-to-github1.png +:alt: Screenshot of VS Code before publishing to GitHub +:width: 100% +:class: with-border + +Choose "Publish to GitHub". In this case I never even clicked on "Initialize Repository". +``` + +```{figure} img/sharing/vscode-publish-to-github2.png +:alt: Screenshot of VS Code before publishing to GitHub +:width: 100% +:class: with-border + +In my case I chose to "Publish to GitHub public repository". Here you can also rename +the repository if needed. +``` + +```{figure} img/sharing/vscode-authorize.png +:alt: Screenshot of VS Code asking for authorization +:width: 50% +:class: with-border + +First time you do this you might need to authorize VS Code to access your +GitHub account by redirecting you to https://github.com/login/oauth/authorize. +``` + +```{figure} img/sharing/vscode-publish-to-github3.png +:alt: Screenshot of VS Code after publishing to GitHub +:width: 100% +:class: with-border + +After it is published, click on "Open on GitHub". +``` +::: + +:::{group-tab} Command line +### Make sure your Git is configured + +We have an own section on this: {ref}`configuration`. + + +### Put your project under version control + +My example project here consists of two files. Replace this with your own +example files: +```console +$ ls -l + +.rw------- 19k user 7 Mar 17:36 LICENSE +.rw------- 21 user 7 Mar 17:36 myscript.py +``` + +I will first initialize a Git repository in this directory. +If you get an error, try without the `-b main` (and your default branch will +then be called `master`, this will happen for Git versions older than +2.28): +```console +$ git init -b main +``` + +Now add and commit the two files to the Git repository: +```console +$ git add LICENSE myscript.py +$ git commit -m "putting my project under version control" +``` + +If you want to add all files in one go, you can use `git +add .` instead of `git add LICENSE myscript.py`. + +Now you have a Git repository with one commit. Verify this with `git log`. +But it's still only on your computer. Let's put it on GitHub next. + + +### Create an empty repository on GitHub + +First log into GitHub, then follow the screenshots and descriptions below. +```{figure} img/sharing/new-repository.png +:alt: Screenshot on GitHub before a new repository form is opened +:width: 60% +:class: with-border + +Click on the "plus" symbol on top right, then on "New repository". +``` + +Then create an empty repository without any files and without any commits: +```{figure} img/sharing/create-repository.png +:alt: Screenshot on GitHub just before a new repository is created +:width: 100% +:class: with-border + +Choose a repository name, add a short description, but please **do not check** "Add a +README file". For "Add .gitignore" and "Choose a license" also leave as "None". Finally "Create repository". +``` + +Once you click the green "Create repository", you will see a page similar to: +```{figure} img/sharing/bare-repository.png +:alt: Screenshot on GitHub after a bare repository was created +:width: 100% +:class: with-border +``` + +What this means is that we have now an empty project with either an HTTPS or an +SSH address: click on the HTTPS and SSH buttons to see what happens. + + +### Push an existing repository from your computer to GitHub + +We now want to follow the "**... or push an existing repository from the command line**": + +1. In your terminal make sure you are still in your myproject directory. +2. Copy paste the three lines below the red arrow to the terminal and execute + those, in my case (**you need to replace the "USER" part and possibly also + the repository name**): + +`````{tabs} + ````{group-tab} SSH + ```console + $ git remote add origin git@github.com:USER/myproject.git + ``` + ```` + ````{group-tab} HTTPS + ```console + $ git remote add origin https://github.com/USER/myproject.git + ``` + ```` +````` + +Then: +```console +$ git branch -M main +$ git push -u origin main +``` + +The meaning of the above lines: +- Add a remote reference with the name "origin" +- Rename current branch to "main" +- Push branch "main" to "origin" + +You should now see: + +```text +Enumerating objects: 4, done. +Counting objects: 100% (4/4), done. +Delta compression using up to 12 threads +Compressing objects: 100% (3/3), done. +Writing objects: 100% (4/4), 6.08 KiB | 6.08 MiB/s, done. +Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 +To github.com:USER/myproject.git + * [new branch] main -> main +branch 'main' set up to track 'origin/main'. +``` + +Reload your GitHub project website and your commits should now be +online! + + +### Troubleshooting + +**error: remote origin already exists** +- Explanation: You probably ran a `git remote add origin ...` command, then changed your + mind about HTTPS or SSH and then tried to run the other `git remote add + origin ...` command but "origin" then already exists. +- Recovery: + - First remove "origin" with `git remote remove origin` + - Then run the correct `git remote add origin ...` command + +**remote contains work that you do not have** +- Explanation: You probably clicked on "Add a README file" and now the + repository on GitHub is not empty but contains one commit and locally you + have a different history. Git now prevents you from accidentally overwriting + the history on GitHub. +- Recovery: + - Use `git push --force` instead of `git push`, which will force Git to overwrite the history on GitHub + - Note that this is a powerful but also possibly dangerous option but here it + helps us. If it's a brand new repo, it probably is fine to do this. For real + repositories, don't do this unless you are very sure what is happening. +::: + +:::: +::::: + + +## Remote repositories + +In this exercise we have pushed our local repository to a remote repository. +We will learn how to work with remote repositories in detail in the +[collaborative distributed version +control](https://coderefinery.github.io/git-collaborative/) lesson. To store +your git data on another server, you use **remotes**. A remote is a repository +on its own, with its own branches. We can **push** changes to the remote and +**pull** from the remote. + +You might use remotes to: +- Back up your own work or make your work findable. +- To collaborate with other people. + +There are different types of remotes: +- If you have a server you can SSH to, you can use that as a remote. +- [GitHub](https://github.com) is a popular, closed-source commercial site. +- [GitLab](https://about.gitlab.com) is a popular, open-core + commercial site. Many universities have their own private GitLab servers + set up. +- [Bitbucket](https://bitbucket.org) is yet another popular commercial site. +- Another option is [NotABug](https://notabug.org). +- There are more ... + + +## Is putting software on GitHub/GitLab/... publishing? + +It is a good first step but to make your code truly **findable and +accessible**, condider making your code **citable and persistent**: Get a +persistent identifier (PID) such as DOI in addition to sharing the code +publicly, by using services like [Zenodo](https://zenodo.org) or similar +services. diff --git a/_sources/staging-area.md.txt b/_sources/staging-area.md.txt new file mode 100644 index 00000000..94d0fe83 --- /dev/null +++ b/_sources/staging-area.md.txt @@ -0,0 +1,330 @@ +# Using the Git staging area + +```{objectives} +- Learn how to tell a story with your commit history. +- Demystify the Git staging area. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 10 min exercise +``` + + +## Commit history is telling a story + +Your *current code* is very important, but the *history* can be just +as important - it tells a story about how your code came to be. + +- Each individual line of code rarely stands alone. +- You often want to see all the related changes together. +- But you also hardly ever do one thing at once. + +Along with your code, Git creates a *history* for you, and if your +history is clear then you are a long way to organized code. + +````{discussion} + Here are five types of history. What are the advantages and + disadvantages of each, when you look at it later? + + **Example 1**: + ```shell + b135ec8 add features A, B, and C + ``` + + **Example 2** (newest commit is on top): + ```shell + 6f0d49f implement feature C + fee1807 implement feature B + 6fe2f23 implement feature A + ``` + + **Example 3**: + ```shell + ab990f4 saving three months of miscellaneous work I forgot to commit + ``` + + **Example 4** (newest commit is on top): + ```shell + bf39f9d more work on feature B + 45831a5 removing debug prints for feature A and add new file + bddb280 more work on feature B and make feature A compile again + 72d78e7 feature A did not work and started work on feature B + b135ec8 now feature A should work + 72e0211 another fix to make it compile + 61dd3a3 forgot file and bugfix + 49dc419 wip (work in progress) + ``` + + **Example 5** (newest commit is on top): + ```shell + 1949dc4 Work of 2020-04-07 + a361dd3 Work of 2020-04-06 + 1172e02 Work of 2020-04-03 + e772d78 Work of 2020-04-02 + ``` + + Discuss these examples. Can you anticipate problems? +```` + +We want to have nice commits. But we also want to "save often" +(checkpointing) - how can we have both? + +- We will now learn to create nice commits using `git commit --patch` and/or the staging area. +- Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits. +- The staging area isn't the only way to organize your history nicely, some alternatives are discussed at the end of the lesson. + + +## Interactive commits + +- The simplest ways to solve this is to do **interactive commits**: + the `git commit --patch` option (or `git commit -p` for short). +- It will present you with every change you have made individually, + and you can decide which ones to commit right now. +- Reference and key commands + - `git commit --patch` to start the interactive commit + - `y` to use the change + - `n` to skip the change + - `s` (split) if there are several changes grouped together, but + separated by a blank line, split them into separate choices. + - `q` aborts everything. + - `?` for more options. +- The `-p` option is also available on `commit`, `restore`, `checkout`, `reset`, and `add`. + + +(exercise-interactive-commits)= + +## Exercise: Interactive commits + +````{exercise} Staging-1: Perform an interactive commit +One option to help us create nice logical commits is to stage *interactively* +with `git commit --patch`: + +1. Make two changes in `instructions.txt`, at the top and bottom + of the file. + **Make sure that they are separated by at least several unmodified lines.** +2. Run `git commit --patch`. Using the keystrokes above, commit one of + the changes. +3. Do it again for the other change. +4. When you're done, inspect the situation with `git log`, `git status`, `git diff` and `git diff --staged`. +5. When would this be useful? + + ```{solution} + This can be useful if you have several modification in a file (or several + files) but you decide that it would be beneficial to save them as two (or + more) separate commits. + ``` +```` + + +## The staging area + +- The interactive commits above are great, but what if there are so + many changes that you can't sort them out in one shot? +- What if you make progress and want to record it somehow, but it's + not ready to be committed? +- The **staging area** is a place to record things before committing. + +```{instructor-note} +We give two examples and the instructor can pick one or both: +- Analogy using moving boxes +- Analogy using shopping receipts +``` + +```{discussion} + **Analogy using moving boxes** + + - You're moving and you have a box to pack your things in. + - You can put stuff into the box, but you can also take stuff out of the box. + - You wouldn't want to mix items from the bathroom, kitchen, and living room + into the same box. + - The box corresponds to the staging area of Git, where you can craft your commits. + - Committing is like sealing the box and sticking a label on it. + - You wouldn't want to label your box with "stuff", but rather give a more + descriptive label. + - See also + + + **Analogy using shopping receipts** + + - You need to go shopping and buy some stuff for work and for home. + You need two separate receipts. + - Bad idea: go through the store get home stuff, pay, start at the + beginning and go through the store again. This is inefficient and + annoying. + - What you actually do: + - Go through the store and put everything you need in your shopping + basket. + - Get to the check-out. Put your home stuff on the conveyor belt + (`git add`). Check both the belt (`git diff --staged`) and your + basket (`git diff`) to make sure you got all your home stuff. + - Pay (`git commit`) + - Repeat for work stuff. + + In order to keep organized, you have to use multiple locations to + stage things in sequence. +``` + + +## Staging area commands + +The staging area is a middle ground between what you have done to your files +(the **working directory**) and what you have last committed (the **HEAD commit**). +Just like the name implies, it lets you prepare (**stage**) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since **you can modify and stage several times before committing**. + +**git add** stages/prepares for the next commit: +```text + git add + [project*] <------------ project* + ^ + | modify with editor + | + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git commit** creates a new commit: +```text + + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + HEAD~2 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git reset \\--soft HEAD~1** (move HEAD back by one but keep changes and stage +them) would do the opposite of **git commit**. (in this case, `HEAD` +is literally this - not a replacement) + +Going back to the last staged version: +```text + git restore + [project*] ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Unstaging changes with **git restore \\--staged**: +```text + git restore --staged + ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Discarding unstaged changes: +```text + + project* + | + | git restore + v + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Comparing: +```text + git diff + [project*] <-----------> project* + ^ ^ + | git diff --staged | git diff HEAD + v v + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +```{figure} img/staging-basics.svg +:alt: Staging basics +:width: 100% + +The different states of the repository and the commands to move from one to +another. +``` + +(exercise-staging-area)= + +## Exercise: Using the staging area + +```{exercise} Staging-2: Use the staging area to make a commit in two steps +1. In your recipe example, make two different changes to + `ingredients.txt` and `instructions.txt` which do not go together. +2. Use `git add` to stage one of the changes. +3. Use `git status` to see what's going on, and use `git diff` and `git diff --staged` to see the changes. +4. Feel some regret and unstage the staged change. +``` + +```{discussion} +- When is it better to "save" a change as commit, when is it better to "save" + it with `git add`? +- Is it a problem to commit many small changes? +``` + +```{keypoints} +- The staging area helps us to create well-defined commits. +``` diff --git a/_sources/under-the-hood.md.txt b/_sources/under-the-hood.md.txt new file mode 100644 index 00000000..977968da --- /dev/null +++ b/_sources/under-the-hood.md.txt @@ -0,0 +1,185 @@ +# Git under the hood + +```{objectives} +- Verify that branches are pointers to commits and extremely lightweight. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{figure} img/stranger.jpg +:alt: Git under the hood +:width: 100% +``` + + +## Down the rabbit hole + +When working with Git, **you will never need to go inside .git**, but in this +exercise we will, in order to learn about how branches are implemented in Git. + +For this exercise create a new repository and commit a couple of changes. + +Now that we've made a couple of commits let us look at what is happening under +the hood. + +```console +$ cd .git +$ ls -l + +drwxr-xr-x - user 25 Aug 15:51 branches +.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG +.rw-r--r-- 92 user 25 Aug 15:51 config +.rw-r--r-- 73 user 25 Aug 15:51 description +.rw-r--r-- 21 user 25 Aug 15:51 HEAD +drwxr-xr-x - user 25 Aug 15:51 hooks +.rw-r--r-- 137 user 25 Aug 15:52 index +drwxr-xr-x - user 25 Aug 15:51 info +drwxr-xr-x - user 25 Aug 15:52 logs +drwxr-xr-x - user 25 Aug 15:52 objects +drwxr-xr-x - user 25 Aug 15:51 refs +``` + +Git stores everything under the .git folder in your repository. In fact, **the +.git directory is the Git repository.** + +Previously when you wrote the commit messages using your text editor, they +were in fact saved to `COMMIT_EDITMSG`. + +Each commit in Git is stored as a "blob". This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file. + +Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string). + +```{figure} img/commit-and-tree.png +:alt: A commit inside Git +:width: 100% + +States of a Git file. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a [directed acyclic +graph](http://eagain.net/articles/git-for-computer-scientists/) (do not worry +if the term is not familiar). + +```{figure} img/commits-and-parents.png +:alt: A commit and its parents +:width: 100% + +A commit and its parents. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +All branches and tags in Git are pointers to commits. + + +## Git is basically a content-addressed storage system + +- CAS: ["mechanism for storing information that can be retrieved based on its content, not its storage location"](https://en.wikipedia.org/wiki/Content-addressable_storage) +- Content address is the content digest (SHA-1 checksum) +- Stored data does not change - so when we modify commits, we always create new + commits. Git doesn't delete these right away, which is why it is *very hard + to lose data if you commit it once*. + +Let us poke a bit into raw objects! Start with: + +```console +$ git cat-file -p HEAD +``` + +Then explore the `tree` object, then the `file` object, etc. recursively using the hashes you see. + + +## Demonstration: experimenting with branches + +Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an "Aha!" moment and provide us a +good understanding of the underlying model. + +We are starting from the `main` branch and create an `idea` branch: + +```console +$ git status + +On branch main +nothing to commit, working tree clean +``` + +```console +$ git switch --create idea + +Switched to a new branch 'idea' +``` + +```console +$ git branch + +* idea + main +``` + +Now let us go in: + +```console +$ cd .git +$ cd refs/heads +$ ls -l + +.rw-r--r-- 41 user 25 Aug 15:54 idea +.rw-r--r-- 41 user 25 Aug 15:52 main +``` + +Let us check what the `idea` file looks like +(do not worry if the hash is different): +```console +$ cat idea + +045e3db14740c60684d745e5fb891ae71e335611 +``` + +Now let us replicate this file: +```console +$ cp idea idea-2 +$ cp idea idea-3 +$ cp idea idea-4 +$ cp idea idea-5 +``` + +Let us go up two levels and inspect the file `HEAD`: +```console +$ cd ../.. +$ cat HEAD + +ref: refs/heads/idea +``` + +Let us open this file and change it to: +``` +ref: refs/heads/idea-3 +``` + +**Now we are ready for the aha moment!** +First let us go back to the working area: +```console +$ cd .. +``` + +Now - on which branch are we? +```console +$ git branch + + idea + idea-2 +* idea-3 + idea-4 + idea-5 + main +``` + +```{discussion} +Discuss the findings with other course participants. +``` diff --git a/_sources/what-to-avoid.md.txt b/_sources/what-to-avoid.md.txt new file mode 100644 index 00000000..ed76c118 --- /dev/null +++ b/_sources/what-to-avoid.md.txt @@ -0,0 +1,62 @@ +# What to avoid + +The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas. + +**Postponing commits because the changes are "unfinished"/"ugly"**: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all. + +**Not updating your branch before starting new work**: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later. +So update your branch before adding new commits. + +**Commit unrelated changes together**: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects. + +**Too ambitious branch which risks to never get completed**: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere. + +**Committing generated files**: Compiled and generated files are not +committed to version control. There are many reasons for this: + +- These files can make it more difficult to run on different platforms. +- These files are automatically generated and thus do not contribute in any meaningful way. +- When tracking generated files you could see differences in the code although you haven't touched the code. + +For this we use [.gitignore files](https://git-scm.com/docs/gitignore) where +you can list which files and paths should be ignored by Git. You can also use +wild-cards to ignore files with a certain extension or files in a certain +directory. + +**Over-engineering the branch layout and safeguards in small projects**: This +may prevent people from contributing (maybe even including yourself?). Add more +restrictions and safeguards only as the project and the group of collaborators +grows. + +**Commit messages that explain what has been changed but do not explain why it has been +changed**: This is as useful as code comments which describe the "obvious" such +as "this is a loop" instead of explaining why something is done this way. +But don't let perfect commit messages stop you from the most important point, committing often (first point). + +**Commit huge files**: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent `git rm` does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request. + +:::{discussion} +Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements. +::: diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 00000000..f3ecd034 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,241 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos, .gp'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..87fc516a --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minipres.js b/_static/minipres.js new file mode 100644 index 00000000..ad11c871 --- /dev/null +++ b/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 00000000..33566310 --- /dev/null +++ b/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/_static/sphinx_lesson.css b/_static/sphinx_lesson.css new file mode 100644 index 00000000..14b20c64 --- /dev/null +++ b/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/_static/sphinx_rtd_theme_ext_color_contrast.css b/_static/sphinx_rtd_theme_ext_color_contrast.css new file mode 100644 index 00000000..e68feb82 --- /dev/null +++ b/_static/sphinx_rtd_theme_ext_color_contrast.css @@ -0,0 +1,47 @@ +/* The following are for web accessibility of sphinx_rtd_theme: they + * solve some of the most frequent contrast issues. Remove when this + * solved: + * https://github.com/readthedocs/sphinx_rtd_theme/issues/971 + */ +/* background: #fcfcfc, note boxes #E7F2FA */ +a { color: #2573A7; } /* original #2980B9, #1F5C84; */ +body { color: #242424; } /* original #404040, #383838 */ +.wy-side-nav-search>a, .wy-side-nav-search .wy-dropdown>a { + color: #ffffff; +} /* original #fcfcfc */ +footer { color: #737373; } /* original gray=#808080*/ +footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { + color: #737373; +} /* original gray=#808080*/ +.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { + color: #AB2314; +} +/* Sidebar background */ +.wy-side-nav-search { background-color: #277CB4;} + +/* Same, but for pygments */ +.highlight .ch { color: #3E7A89; } /* #! line */ +.highlight .c1 { color: #3E7A89; } /* also comments */ +.highlight .nv { color: #AD3ECC; } /* variable */ +.highlight .gp { color: #B45608; } /* prompt character, $*/ +.highlight .si { color: #3975B1; } /* ${} variable text */ +.highlight .nc { color: #0C78A7; } + +/* Sphinx admonitions */ +/* warning */ +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { + background: #B15E16; } +/* important */ +.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { + background: #12826C; } +/* seealso, note, etc */ +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { + background: #277CB4; } +/* error, danger */ +.rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { + background: #e31704; +} + +/* Generic admonition titles */ +.wy-alert-title, .rst-content .admonition-title { + background: #277CB4; } diff --git a/_static/tabs.css b/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/_static/tabs.js b/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/_static/term_role_formatting.css b/_static/term_role_formatting.css new file mode 100644 index 00000000..0b66095c --- /dev/null +++ b/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/_static/togglebutton.css b/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/_static/togglebutton.js b/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/aliases/index.html b/aliases/index.html new file mode 100644 index 00000000..6213cc4b --- /dev/null +++ b/aliases/index.html @@ -0,0 +1,337 @@ + + + + + + + Aliases and configuration — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Aliases and configuration

+
+

Objectives

+
    +
  • Learn to use aliases for most common commands.

  • +
+
+

Are you getting tired of typing so much? In Git you can define aliases (shortcuts):

+
    +
  • These are great because they can save you time typing.

  • +
  • But it’s easy to forget them, get confused, or be inconsistent with your colleagues.

  • +
+

There is plenty of other configuration for Git, that can make it nicer.

+
+

Aliases

+
    +
  • Aliases offer a way to improve the usability of Git: for +example git ci instead of git commit.

  • +
  • Aliases are based on simple string replacement in the command.

  • +
  • Aliases can either be specific to a repository or global.

    +
      +
    • Global aliases help you do the things you are used to across Git projects.

    • +
    • Per-project aliases can also be created.

    • +
    +
  • +
  • Global aliases are stored in ~/.gitconfig.

  • +
+
+
+

Example alias: git graph

+

A very useful shortcut which we use a lot in our workshops:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ cd your_git_repository
+$ git graph
+
+
+
+
+

Using external commands

+

It is possible to call external commands using the exclamation mark character “!”. +In this example here we create a local alias which is +stored in .git/config and not synchronized with remotes:

+
$ cd your_git_repository
+$ git config alias.hi '!echo hello'
+$ git hi
+
+
+
+

Food for thought: When to alias?

+
    +
  • How many times should you wait before aliasing a command?

  • +
  • Do you believe a list of generic two-letter acronyms for common commands will +save your time?

  • +
+
+
+
+

List of aliases the instructors use

+

You are welcome to reuse, suggest, improve. +You can see your current aliases in ~/.gitconfig.

+
$ git config --global alias.ap "add --patch"
+$ git config --global alias.br branch
+$ git config --global alias.ci "commit -v"
+$ git config --global alias.cip "commit --patch -v"
+$ git config --global alias.cl "clone --recursive"
+$ git config --global alias.di diff
+$ git config --global alias.dic "diff --staged --color-words"
+$ git config --global alias.diw "diff --color-words"
+$ git config --global alias.dis "!git --no-pager diff --stat"
+$ git config --global alias.fe fetch
+$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ git config --global alias.rem remote
+$ git config --global alias.st status
+$ git config --global alias.su "submodule update --init --recursive"
+
+
+

Here is what they do:

+
    +
  • ap: add, selecting parts individually, interactively.

  • +
  • br: branch (obvious)

  • +
  • ci: commit (check in), with -v option for clarity

  • +
  • cip: commit, selecting parts individually, interactively.

  • +
  • cl: clone, init submodules (submodules are an advanced topic)

  • +
  • di: diff (obvious)

  • +
  • dic: diff of staging area vs last commit (what is about to be committed)

  • +
  • diw: a word diff, color. Useful for small changes.

  • +
  • dis: a “diffstat”: what files are changed, not contents

  • +
  • fe: fetch (obvious)

  • +
  • graph: show whole git graph (so useful, some of us call it l)

  • +
  • rem: remote (obvious)

  • +
  • st: status (obvious)

  • +
  • su: submodule update (advanced)

  • +
+

A useful setting for the p aliases:

+
$ git config --global interactive.singlekey true
+
+
+
+
+

Advanced aliases

+

These are advanced aliases and configuration options. We won’t explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages!

+
$ git config --global alias.cif "commit -v -p --fixup"
+$ git config --global alias.rb "rebase --autosquash"
+$ git config --global alias.rbi "rebase --interactive --autosquash"
+$ git config --global alias.rbis "rebase --interactive --autosquash --autostash"
+$ git config --global alias.rbs "rebase --autosquash --autostash"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard"
+$ git config --global alias.new "log HEAD..HEAD@{upstream}"
+$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}"
+$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}"
+$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all"
+$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD"
+$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat"
+
+
+
+
+

Advanced Git configuration

+

Besides aliases, you can do plenty of other configuration of git. +Here are some of the most common ones:

+
$ git config --global interactive.singlekey true
+$ git config --global core.pager "less -RS"
+$ git config --global core.excludesfile ~/.gitignore
+$ git config --global merge.conflictstyle diff3
+$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]"
+$ git config --global diff.mnemonicPrefix true
+
+
+

Do you get tired of typing and copying and pasting your remote names +all the time, like git@github.com:myusername? You can create remote +aliases like this:

+
$ git config --global url.git@github.com:.insteadOf gh:
+$ git config --global url.git@github.com:/username/.insteadOf ghu:
+
+
+

Then, when you add a remote ghu:recipe, it will automatically be +translated to git@github.com:/username/recipe using a simple prefix +matching.

+
+

Keypoints

+
    +
  • If you are frustrated about remembering a command, you should create an alias.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/archaeology/index.html b/archaeology/index.html new file mode 100644 index 00000000..1855a63a --- /dev/null +++ b/archaeology/index.html @@ -0,0 +1,595 @@ + + + + + + + Inspecting history — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Inspecting history

+
+

Objectives

+
    +
  • Be able find a line of code, find out why it was introduced and when.

  • +
  • Be able to quickly find the commit that changed a behavior.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Command line, GitHub, and VS Code

+

As usual, we offer ways to do this with the command line, VS Code, and +GitHub.

+
    +
  • Command line is most powerful and relatively easy with this. +You may also use it along with other things. If you haven’t tried +it yet, we’d recommend you to give it a try.

  • +
  • The GitHub web interface allows many things to be done, but not +everything.

  • +
  • VS Code allows some of these, but for some it’s easier to open +the VS Code terminal and run git there.

  • +
+
+
+

Our toolbox for history inspection

+
+

Instructor note

+

First the instructor demonstrates few commands on a real life example +repository https://github.com/networkx/networkx (mentioned in the amazing site The +Programming Historian). +Later we will practice these in an archaeology exercise (below).

+
+
+

Warm-up: “Git History” browser

+

As a warm-up we can try the “Git History” browser +on the README.rst file of the networkx repository:

+ +
+
+

Searching text patterns in the repository

+

With git grep you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or +some error message printed.

+
+

The Git command is as described above:

+
$ git grep TEXT
+$ git grep "some text with spaces"
+
+
+

In the networkx repository you can try:

+
$ git clone https://github.com/networkx/networkx
+$ cd networkx
+$ git grep -i fixme
+
+
+

While git grep searches the current state of the repository, +it is also possible to search through all changes with git log -S sometext +which can be useful to find where something got removed.

+
+
+
+

Inspecting individual commits

+
+

We have seen this one before already. Using git show we can inspect an individual commit if +we know its hash:

+
$ git show HASH
+
+
+

For instance:

+
$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7
+
+
+
+
+
+

Line-by-line code annotation with metadata

+

With git annotate you can see line by line who and when the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility.

+
+
$ git annotate FILE
+
+
+

Example:

+
$ git annotate networkx/convert_matrix.py
+
+
+

If you annotate in a terminal and the file is longer than the screen, Git by default uses the program less to +scroll the output. +Use /sometext <ENTER> to find “sometext” and you can cycle through the results with n (next) and N (last). +You can also use page up/down to scroll. You can quit with q.

+
+
+

Discussion

+

Discuss how these relatively trivial changes affect the annotation:

+
    +
  • Wrapping long lines of text/code into shorter lines

  • +
  • Auto-formatting tools such as black

  • +
  • Editors that automatically remove trailing whitespace

  • +
+
+
+
+

Inspecting code in the past

+
+

We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code:

+
$ git switch --create BRANCHNAME HASH
+
+
+

Example (lines starting with “#” are only comments):

+
$ # create branch called "older-code" from hash 347e6292419b
+$ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9
+
+$ # now you can navigate and inspect the code as it was back then
+$ # ...
+
+$ # after we are done we can switch back to "main"
+$ git switch main
+
+$ # if we like we can delete the "older-code" branch
+$ git branch -d older-code
+
+
+

On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

+
$ git checkout -b BRANCHNAME SOMEHASH
+
+
+
+
+
+
+

Exercise

+

This is described with the command line method, but by looking above +you can translate to the other options.

+
+

Exercise: Explore basic archaeology commands (20 min)

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Make sure you are not inside another Git repository when running this +exercise. If you are, first step “outside” of it. +We want to avoid creating a Git repository inside another Git repository.

    +
    +

    You can check if you are inside a Git repository with:

    +
    $ git status
    +
    +fatal: not a git repository (or any of the parent directories): .git
    +
    +
    +

    You want to see the above message which tells us that this is not a Git repository.

    +
    +
  • +
  • Clone this repository: +https://github.com/networkx/networkx.git.

    +
    +
    $ git clone https://github.com/networkx/networkx.git
    +
    +
    +
    +
  • +
  • Then let us all make sure we are working on a well-defined version of the repository.

    +
    +

    Step into the new directory and create an exercise branch from the +networkx-2.6.3 tag/release:

    +
    $ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+
+
+
+

Finding out when something broke/changed with git bisect

+

This only works with the command line.

+
+

“But I am sure it used to work! Strange.”

+
+

Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke.

+
+

How would you solve this?

+

Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now.

+
    +
  • How would you find the commit which changed it?

  • +
  • Why could it be useful to know the commit that changed it?

  • +
+
+

We will probably arrive at a solution which is similar to git bisect:

+
    +
  • First find out a commit in past when it worked.

    +
    $ git bisect start
    +$ git bisect good f0ea950  # this is a commit that worked
    +$ git bisect bad main      # last commit is broken
    +
    +
    +
  • +
  • Now compile and/or run and/or test and decide whether “good” or “bad”.

  • +
  • This is how you can tell Git that this was a working commit:

    +
    $ git bisect good
    +
    +
    +
  • +
  • And this is how you can tell Git that this was not a working commit:

    +
    $ git bisect bad
    +
    +
    +
  • +
  • Then bisect/iterate your way until you find the commit that broke it.

  • +
  • If you want to go back to start, type git bisect reset.

  • +
  • This can even be automatized with git bisect run SCRIPT. +For this you write a script that returns zero/non-zero (success/failure).

  • +
+
+
+

Optional exercise: Git bisect

+

This only works with the command line.

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+
+

Summary

+
    +
  • git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project on the command line.

  • +
  • git switch --create NAME HASH is the recommended mechanism to inspect old code on the command line.

  • +
  • Most of these commands can be used in the GitHub web interface (except git bisect).

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/basics/index.html b/basics/index.html new file mode 100644 index 00000000..e0659e5e --- /dev/null +++ b/basics/index.html @@ -0,0 +1,837 @@ + + + + + + + Basics — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Basics

+
+

Objectives

+
    +
  • Learn to create Git repositories and make commits.

  • +
  • Get a grasp of the structure of a repository.

  • +
  • Learn how to inspect the project history.

  • +
  • Learn how to write useful commit log messages.

  • +
+
+
+

Instructor note

+
    +
  • 35 min teaching/type-along

  • +
  • 40 min exercise

  • +
+
+
+

What is Git, and what is a Git repository?

+
    +
  • Git is a version control system: can record/save snapshots and track the content of a folder as it changes over time.

  • +
  • Every time we commit a snapshot, Git records a snapshot of the entire project, saves it, and assigns it a version.

  • +
  • These snapshots are kept inside a sub-folder called .git.

  • +
  • If we remove .git, we remove the repository and history (but keep the working directory!).

  • +
  • The directory .git uses relative paths - you can move the whole repository somewhere else and it will still work.

  • +
  • Git doesn’t do anything unless you ask it to (it does not record anything automatically).

  • +
  • Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces).

  • +
+
+
+

Recording a snapshot with Git

+
    +
  • Git takes snapshots only if we request it.

  • +
  • We will record changes in two steps (we will later explain why this is a recommended practice).

  • +
  • Example (we don’t need to type yet):

    +
    $ git add FILE.txt
    +$ git commit
    +
    +$ git add FILE.txt ANOTHERFILE.txt
    +$ git commit
    +
    +
    +
  • +
  • We first focus (git add, we “stage” the change), then record (git commit):

  • +
+
+Git staging +
+

Git staging and committing.

+
+
+
+

Question for the more advanced participants

+

What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end.

+
+
+
+

Configuring Git command line

+

Before we start using Git on the command line, we need to configure Git. +This is also part of the +installation instructions +but we need to make sure we all have +set name, email address, editor, and +default branch:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+$ git config --global core.editor nano
+$ git config --global init.defaultBranch main
+
+
+

Verify with:

+
$ git config --list
+
+
+
+

Instructor note

+

Instructors, give learners enough time to do the above configuration steps.

+
+
+
+

Type-along: Tracking a guacamole recipe with Git

+

We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list)

+

The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language.

+
+

Instructor note

+

Instructors, please encourage now that participants type along.

+
+
+

Note

+

It is possible to go through this lesson in the command line or in the browser +(on GitHub).

+
    +
  • We recommend to start with the command line but later to also try in the browser.

  • +
  • If you get really stuck in the command line, try following in the browser and +later you can try to return to the command line.

  • +
+
+
+
+

Creating a repository

+

One of the basic principles of Git is that it is easy to create repositories:

+
+
$ mkdir recipe
+$ cd recipe
+$ git init -b main
+
+
+

That’s it! With git init -b main have now created an empty Git repository +where main is the default branch (more about branches later).

+

We will use git status a lot to check out what is going on:

+
$ git status
+
+On branch main
+
+No commits yet
+
+nothing to commit (create/copy files and use "git add" to track)
+
+
+

We will make sense of this information during this workshop.

+
+
+
+

Adding files and committing changes

+

Let us now create two files.

+

One file is called ingredients.txt and contains:

+
* 2 avocados
+* 1 chili
+* 1 lime
+* 2 tsp salt
+
+
+

The second file is called instructions.txt and contains:

+
* chop avocados
+* chop onion
+* chop chili
+* squeeze lime
+* add salt
+* and mix well
+
+
+
+

As mentioned above, in Git you can always check the status of files in your repository using +git status. It is always a safe command to run and in general a good idea to +do when you are trying to figure out what to do next:

+
$ git status
+
+On branch main
+
+No commits yet
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    ingredients.txt
+    instructions.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+
+

The two files are untracked in the repository (directory). You want to add the files (focus the camera) +to the list of files tracked by Git. Git does not track +any files automatically and you need make a conscious decision to add a file. Let’s do what +Git hints at, and add the files, one by one:

+
$ git add ingredients.txt
+$ git status
+
+On branch main
+
+No commits yet
+
+Changes to be committed:
+  (use "git rm --cached <file>..." to unstage)
+    new file:   ingredients.txt
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    instructions.txt
+
+
+

Now this change is staged and ready to be committed. +Let us now commit the change to the repository:

+
$ git commit -m "adding ingredients"
+
+[main (root-commit) f146d25] adding ingredients
+ 1 file changed, 4 insertions(+)
+ create mode 100644 ingredients.txt
+
+
+

Right after we query the status to get this useful command into our muscle memory:

+
$ git status
+
+
+

Now stage and commit also the other file:

+
$ git add instructions.txt
+$ git commit -m "adding instructions"
+
+
+

We will add a third file to the repository, README.md, containing:

+
# recipe
+
+This is an exercise repository.
+
+
+

Now stage and commit also the README.md file:

+
$ git add README.md
+$ git commit -m "adding README"
+
+
+

What does the -m flag mean? Let us check the help page for that command:

+
$ git help commit
+
+
+

You should see a very long help page as the tool is very versatile (press q to quit). +Do not worry about this now but keep in mind that you can always read the help files +when in doubt. Searching online can also be useful, but choosing search terms +to find relevant information takes some practice and discussions in some +online threads may be confusing. +Note that help pages also work when you don’t have a network connection!

+
+
+
+

Exercise: Record changes

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+
+
+

Git history and log

+
+

If you haven’t yet, please try now git log:

+
$ git log
+
+commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main)
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:47 2023 +0200
+
+    don't forget to enjoy
+
+commit 79161b6e67c62ad4688a58c1e54183334611a390
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:32 2023 +0200
+
+    add half an onion
+
+commit a3394e39535343c4dae3bb4f703741a31aa8b78a
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:47:14 2023 +0200
+
+    adding README
+
+commit 369624674e63de48055a65bf63055bd59c985d22
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:46:58 2023 +0200
+
+    adding instructions
+
+commit f146d25b94569a15e94d7f0da6f15d7554f76c49
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:35:52 2023 +0200
+
+    adding ingredients
+
+
+
+
    +
  • We can browse the development and access each state that we have committed.

  • +
  • The long hashes uniquely label a state of the code.

  • +
  • They are not just integers counting 1, 2, 3, 4, … (why?).

  • +
  • Output is in reverse chronological order, i.e. newest commits on top.

  • +
  • We will use them when comparing versions and when going back in time.

  • +
  • git log --oneline only shows the first 7 characters of the commit hash and is good to get an overview.

  • +
  • If the first characters of the hash are unique it is not necessary to type the entire hash.

  • +
  • git log --stat is nice to show which files have been modified.

  • +
+
+
+

Optional exercises: Comparing changes

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+
+
+

Writing useful commit messages

+

Using git log --oneline or browsing a repository on the web, we better +understand that the first line of the commit message is very important.

+

Good example:

+
increase threshold alpha to 2.0
+
+the motivation for this change is
+to enable ...
+...
+this is based on a discussion in #123
+
+
+

Convention: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

Ignoring files and paths with .gitignore

+
+

Discussion

+
    +
  • Should we add and track all files in a project?

  • +
  • How about generated files?

  • +
  • Why is it considered a bad idea to commit compiled binaries to version control?

  • +
  • What types of generated files do you know?

  • +
+
+

Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files. Example:

+
# ignore compiled python 2 files
+*.pyc
+# ignore compiled python 3 files
+__pycache__
+
+
+

An example taken from the official Git documentation:

+
# ignore objects and archives, anywhere in the tree.
+*.[oa]
+# ignore generated html files,
+*.html
+# except foo.html which is maintained by hand
+!foo.html
+# ignore everything under build directory
+build/
+
+
+
    +
  • .gitignore should be part of the repository because we want to make sure that all developers see the same behavior.

  • +
  • All files should be either tracked or ignored.

  • +
  • .gitignore uses something called a +shell glob syntax for +determining file patterns to ignore. You can read more about the syntax in the +documentation.

  • +
  • You can have .gitignore files in lower level directories and they affect the paths below.

  • +
+
+
+

Graphical user interfaces

+

We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI):

+ +
+
+

Summary

+

Now we know how to save snapshots:

+
$ git add FILE(S)
+$ git commit
+
+
+

And this is what we do as we program.

+

Every state is then saved and later we will learn how to go back to these “checkpoints” +and how to undo things.

+
$ git init -b main  # initialize new repository (main is default branch)
+$ git add           # add files or stage file(s)
+$ git commit        # commit staged file(s)
+$ git status        # see what is going on
+$ git log           # see history
+$ git diff          # show unstaged/uncommitted modifications
+$ git show          # show the change for a specific commit
+$ git mv            # move/rename tracked files
+$ git rm            # remove tracked files
+
+
+

Git is not ideal for large binary files +(for this consider git-annex).

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • It takes only one command to initialize a Git repository: git init -b main.

  • +
  • Commits should be used to tell a story.

  • +
  • Git uses the .git folder to store the snapshots.

  • +
  • Don’t be afraid to stage and commit often. Better too often than not often enough.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/.buildinfo b/branch/2023-version/.buildinfo new file mode 100644 index 00000000..e83ecfb1 --- /dev/null +++ b/branch/2023-version/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 4202fab30366226cc703d00775a306ce +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/branch/2023-version/.nojekyll b/branch/2023-version/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/2023-version/_images/add-file.png b/branch/2023-version/_images/add-file.png new file mode 100644 index 00000000..9683b2db Binary files /dev/null and b/branch/2023-version/_images/add-file.png differ diff --git a/branch/2023-version/_images/annotate.png b/branch/2023-version/_images/annotate.png new file mode 100644 index 00000000..8021920a Binary files /dev/null and b/branch/2023-version/_images/annotate.png differ diff --git a/branch/2023-version/_images/bare-repo.png b/branch/2023-version/_images/bare-repo.png new file mode 100644 index 00000000..1aa5699d Binary files /dev/null and b/branch/2023-version/_images/bare-repo.png differ diff --git a/branch/2023-version/_images/browse-files.png b/branch/2023-version/_images/browse-files.png new file mode 100644 index 00000000..5fcc3528 Binary files /dev/null and b/branch/2023-version/_images/browse-files.png differ diff --git a/branch/2023-version/_images/cheat-sheet.jpg b/branch/2023-version/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/branch/2023-version/_images/cheat-sheet.jpg differ diff --git a/branch/2023-version/_images/code-portion.png b/branch/2023-version/_images/code-portion.png new file mode 100644 index 00000000..39356bd5 Binary files /dev/null and b/branch/2023-version/_images/code-portion.png differ diff --git a/branch/2023-version/_images/commit-and-tree.png b/branch/2023-version/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/branch/2023-version/_images/commit-and-tree.png differ diff --git a/branch/2023-version/_images/commit-changes.png b/branch/2023-version/_images/commit-changes.png new file mode 100644 index 00000000..4c0546c6 Binary files /dev/null and b/branch/2023-version/_images/commit-changes.png differ diff --git a/branch/2023-version/_images/commits-and-parents.png b/branch/2023-version/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/branch/2023-version/_images/commits-and-parents.png differ diff --git a/branch/2023-version/_images/commits.png b/branch/2023-version/_images/commits.png new file mode 100644 index 00000000..b154c666 Binary files /dev/null and b/branch/2023-version/_images/commits.png differ diff --git a/branch/2023-version/_images/edit-file.png b/branch/2023-version/_images/edit-file.png new file mode 100644 index 00000000..f7527bd0 Binary files /dev/null and b/branch/2023-version/_images/edit-file.png differ diff --git a/branch/2023-version/_images/git-annotate.png b/branch/2023-version/_images/git-annotate.png new file mode 100644 index 00000000..60c6f7c2 Binary files /dev/null and b/branch/2023-version/_images/git-annotate.png differ diff --git a/branch/2023-version/_images/git-branch-1.svg b/branch/2023-version/_images/git-branch-1.svg new file mode 100644 index 00000000..1174a2e9 --- /dev/null +++ b/branch/2023-version/_images/git-branch-1.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + m2 + + + m3 + + + m1 + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/_images/git-branch-2.svg b/branch/2023-version/_images/git-branch-2.svg new file mode 100644 index 00000000..e3f7abfc --- /dev/null +++ b/branch/2023-version/_images/git-branch-2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l1 + + + e2 + + + e1 + + + m5 + + + m4 + + + m2 + + + m3 + + + m1 + + + + + less-salt + + + + + HEAD + + + + + experiment + + + + + main + + + diff --git a/branch/2023-version/_images/git-branch-3.svg b/branch/2023-version/_images/git-branch-3.svg new file mode 100644 index 00000000..8916d588 --- /dev/null +++ b/branch/2023-version/_images/git-branch-3.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + e2 + + + m3 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + + + less-salt + + + + + experiment + + + diff --git a/branch/2023-version/_images/git-collaborative.svg b/branch/2023-version/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/branch/2023-version/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/branch/2023-version/_images/git-deleted-branches.svg b/branch/2023-version/_images/git-deleted-branches.svg new file mode 100644 index 00000000..2b4b3fd5 --- /dev/null +++ b/branch/2023-version/_images/git-deleted-branches.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + m5 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/_images/git-log-github.png b/branch/2023-version/_images/git-log-github.png new file mode 100644 index 00000000..db44d29b Binary files /dev/null and b/branch/2023-version/_images/git-log-github.png differ diff --git a/branch/2023-version/_images/git-log-terminal.png b/branch/2023-version/_images/git-log-terminal.png new file mode 100644 index 00000000..56493e6e Binary files /dev/null and b/branch/2023-version/_images/git-log-terminal.png differ diff --git a/branch/2023-version/_images/git-merge-1.svg b/branch/2023-version/_images/git-merge-1.svg new file mode 100644 index 00000000..34fd0f87 --- /dev/null +++ b/branch/2023-version/_images/git-merge-1.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + m3 + + + l1 + + + m7 + + + m4 + + + + + experiment + + + + + less-salt + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/_images/git-merge-2.svg b/branch/2023-version/_images/git-merge-2.svg new file mode 100644 index 00000000..5f5fd6a7 --- /dev/null +++ b/branch/2023-version/_images/git-merge-2.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + l1 + + + m5 + + + m4 + + + + + experiment + + + + + main + + + + + HEAD + + + + + less-salt + + + diff --git a/branch/2023-version/_images/git-pre-ff.svg b/branch/2023-version/_images/git-pre-ff.svg new file mode 100644 index 00000000..df06fc7e --- /dev/null +++ b/branch/2023-version/_images/git-pre-ff.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e1 + + + e2 + + + m7 + + + m8 + + + n3 + + + n1 + + + m5 + + + l1 + + + m6 + + + m4 + + + n2 + + + m2 + + + m3 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + main + + + diff --git a/branch/2023-version/_images/git_stage_commit.svg b/branch/2023-version/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/branch/2023-version/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/2023-version/_images/gophers.png b/branch/2023-version/_images/gophers.png new file mode 100644 index 00000000..741406ba Binary files /dev/null and b/branch/2023-version/_images/gophers.png differ diff --git a/branch/2023-version/_images/history.png b/branch/2023-version/_images/history.png new file mode 100644 index 00000000..6384e302 Binary files /dev/null and b/branch/2023-version/_images/history.png differ diff --git a/branch/2023-version/_images/meld.png b/branch/2023-version/_images/meld.png new file mode 100644 index 00000000..774f9cd1 Binary files /dev/null and b/branch/2023-version/_images/meld.png differ diff --git a/branch/2023-version/_images/mergetool.png b/branch/2023-version/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/branch/2023-version/_images/mergetool.png differ diff --git a/branch/2023-version/_images/new-bare-repo-form.png b/branch/2023-version/_images/new-bare-repo-form.png new file mode 100644 index 00000000..939e4f84 Binary files /dev/null and b/branch/2023-version/_images/new-bare-repo-form.png differ diff --git a/branch/2023-version/_images/new-repo-form.png b/branch/2023-version/_images/new-repo-form.png new file mode 100644 index 00000000..b808ee0b Binary files /dev/null and b/branch/2023-version/_images/new-repo-form.png differ diff --git a/branch/2023-version/_images/new-repo-plus.png b/branch/2023-version/_images/new-repo-plus.png new file mode 100644 index 00000000..e58ba5d8 Binary files /dev/null and b/branch/2023-version/_images/new-repo-plus.png differ diff --git a/branch/2023-version/_images/pen-symbol.png b/branch/2023-version/_images/pen-symbol.png new file mode 100644 index 00000000..044902a3 Binary files /dev/null and b/branch/2023-version/_images/pen-symbol.png differ diff --git a/branch/2023-version/_images/preview.png b/branch/2023-version/_images/preview.png new file mode 100644 index 00000000..8a602b66 Binary files /dev/null and b/branch/2023-version/_images/preview.png differ diff --git a/branch/2023-version/_images/search.png b/branch/2023-version/_images/search.png new file mode 100644 index 00000000..4462f71e Binary files /dev/null and b/branch/2023-version/_images/search.png differ diff --git a/branch/2023-version/_images/show.png b/branch/2023-version/_images/show.png new file mode 100644 index 00000000..12d7915c Binary files /dev/null and b/branch/2023-version/_images/show.png differ diff --git a/branch/2023-version/_images/staging-basics.svg b/branch/2023-version/_images/staging-basics.svg new file mode 100644 index 00000000..13df8bf5 --- /dev/null +++ b/branch/2023-version/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + restore + add + commit + restore + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/branch/2023-version/_images/stranger.jpg b/branch/2023-version/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/branch/2023-version/_images/stranger.jpg differ diff --git a/branch/2023-version/_sources/aliases.md.txt b/branch/2023-version/_sources/aliases.md.txt new file mode 100644 index 00000000..c3fd61ce --- /dev/null +++ b/branch/2023-version/_sources/aliases.md.txt @@ -0,0 +1,154 @@ +# Aliases and configuration + +```{objectives} +- Learn to use aliases for most common commands. +``` + +Are you getting tired of typing so much? In Git you can define aliases (shortcuts): +- These are great because they can save you time typing. +- But it's easy to forget them, get confused, or be inconsistent with your colleagues. + +There is plenty of other configuration for Git, that can make it nicer. + + +## Aliases + +- Aliases offer a way to improve the usability of Git: for + example `git ci` instead of `git commit`. +- Aliases are based on simple string replacement in the command. +- Aliases can either be specific to a repository or global. + - Global aliases help you do the things you are used to across Git projects. + - Per-project aliases can also be created. +- Global aliases are stored in `~/.gitconfig`. + + +## Example alias: git graph + +A very useful shortcut which we use a lot in our workshops: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ cd your_git_repository +$ git graph +``` + + +## Using external commands + +It is possible to call external commands using the exclamation mark character "!". +In this example here we create a local alias which is +stored in `.git/config` and not synchronized with remotes: + +```console +$ cd your_git_repository +$ git config alias.hi '!echo hello' +$ git hi +``` + +```{discussion} Food for thought: When to alias? +- How many times should you wait before aliasing a command? +- Do you believe a list of generic two-letter acronyms for common commands will + save your time? +``` + + +## List of aliases the instructors use + +You are welcome to reuse, suggest, improve. +You can see your current aliases in `~/.gitconfig`. + +```console +$ git config --global alias.ap "add --patch" +$ git config --global alias.br branch +$ git config --global alias.ci "commit -v" +$ git config --global alias.cip "commit --patch -v" +$ git config --global alias.cl "clone --recursive" +$ git config --global alias.di diff +$ git config --global alias.dic "diff --staged --color-words" +$ git config --global alias.diw "diff --color-words" +$ git config --global alias.dis "!git --no-pager diff --stat" +$ git config --global alias.fe fetch +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ git config --global alias.rem remote +$ git config --global alias.st status +$ git config --global alias.su "submodule update --init --recursive" +``` + +Here is what they do: +- `ap`: add, selecting parts individually, interactively. +- `br`: branch (obvious) +- `ci`: commit (check in), with `-v` option for clarity +- `cip`: commit, selecting parts individually, interactively. +- `cl`: clone, init submodules (submodules are an advanced topic) +- `di`: diff (obvious) +- `dic`: diff of staging area vs last commit (what is about to be committed) +- `diw`: a word diff, color. Useful for small changes. +- `dis`: a "diffstat": what files are changed, not contents +- `fe`: fetch (obvious) +- `graph`: show whole git graph (so useful, some of us call it `l`) +- `rem`: remote (obvious) +- `st`: status (obvious) +- `su`: submodule update (advanced) + +A useful setting for the `p` aliases: +```console +$ git config --global interactive.singlekey true +``` + + +## Advanced aliases + +These are advanced aliases and configuration options. We won't explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages! + +```console +$ git config --global alias.cif "commit -v -p --fixup" +$ git config --global alias.rb "rebase --autosquash" +$ git config --global alias.rbi "rebase --interactive --autosquash" +$ git config --global alias.rbis "rebase --interactive --autosquash --autostash" +$ git config --global alias.rbs "rebase --autosquash --autostash" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard" +$ git config --global alias.new "log HEAD..HEAD@{upstream}" +$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}" +$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}" +$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all" +$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD" +$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat" +``` + +## Advanced Git configuration + +Besides aliases, you can do plenty of other configuration of `git`. +Here are some of the most common ones: + +```console +$ git config --global interactive.singlekey true +$ git config --global core.pager "less -RS" +$ git config --global core.excludesfile ~/.gitignore +$ git config --global merge.conflictstyle diff3 +$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]" +$ git config --global diff.mnemonicPrefix true +``` + +Do you get tired of typing and copying and pasting your remote names +all the time, like `git@github.com:myusername`? You can create remote +aliases like this: + +```console +$ git config --global url.git@github.com:.insteadOf gh: +$ git config --global url.git@github.com:/username/.insteadOf ghu: +``` + +Then, when you add a remote `ghu:recipe`, it will automatically be +translated to `git@github.com:/username/recipe` using a simple prefix +matching. + + +```{keypoints} +- If you are frustrated about remembering a command, you should create an alias. +``` diff --git a/branch/2023-version/_sources/archaeology.md.txt b/branch/2023-version/_sources/archaeology.md.txt new file mode 100644 index 00000000..90465855 --- /dev/null +++ b/branch/2023-version/_sources/archaeology.md.txt @@ -0,0 +1,397 @@ +# Inspecting history + +```{objectives} +- Be able find a line of code, find out why it was introduced and when. +- Be able to quickly find the commit that changed a behavior. +``` + +```{instructor-note} +- 30 min teaching/type-along +- 30 min exercise +``` + +````{prereq} Preparation +Please make sure that you do not clone repositories inside an already tracked folder: + +```console +$ git status +``` + +If you are inside an existing Git repository, step out of it. +You need to find a different location since we will clone a new repository. + +If you see this message, this is good in this case: + +```shell +fatal: not a git repository (or any of the parent directories): .git +``` +```` + + +## Our toolbox for history inspection + +```{instructor-note} +First the instructor demonstrates few commands on a real life example +repository (mentioned in the amazing site [The +Programming Historian](https://programminghistorian.org/)). +Later we will practice these in an archaeology exercise (below). +``` + + +### Warm-up: ["Git History" browser](https://githistory.xyz/) + +As a warm-up we can try the ["Git History" browser](https://githistory.xyz/) +on the README.rst file of the [networkx](https://github.com/networkx/networkx) repository: + +- Visit and browse (use left/right keys). +- You can try this on some of your GitHub repositories, too! + + +### Searching text patterns in the repository + +`````{tabs} + ````{group-tab} Command line + With `git grep` you can find all lines in a repository which contain some string or regular expression. + This is useful to find out where in the code some variable is used or some error message printed: + + ```console + $ git grep TEXT + $ git grep "some text with spaces" + ``` + + In the [networkx](https://github.com/networkx/networkx) repository you can try: + + ```console + $ git clone https://github.com/networkx/networkx + $ cd networkx + $ git grep -i fixme + ``` + + While `git grep` searches the **current state** of the repository, + it is also possible to search through all changes with `git log -S sometext` + which can be useful to find where something got removed. + ```` + + ````{group-tab} Browser (GitHub) + We can try the same example in the browser: + + + ```{figure} img/archaeology/search.png + :alt: Searching for "fixme" in a GitHub repository + :width: 100% + :class: with-border + + Searching for "fixme" in a GitHub repository. + ``` + ```` +````` + + +### Inspecting individual commits + +`````{tabs} + ````{group-tab} Command line + We have seen this one before already. Using `git show` we can inspect an individual commit if + we know its hash: + + ```console + $ git show HASH + ``` + + For instance: + ```console + $ git show 759d589bdfa61aff99e0535938f14f67b01c83f7 + ``` + ```` + + ````{group-tab} Browser (GitHub) + We can try the same example in the browser: + + + ```{figure} img/archaeology/show.png + :alt: Inspecting an individual commit on GitHub + :width: 100% + :class: with-border + + Inspecting an individual commit on GitHub. + ``` + ```` +````` + + +### Line-by-line code annotation with metadata + +With `git annotate` you can see line by line who and **when** the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility. + +`````{tabs} + ````{group-tab} Command line + ```console + $ git annotate FILE + ``` + + Example: + ```console + $ git annotate networkx/convert_matrix.py + ``` + + If you annotate in a terminal and the file is longer than the screen, Git by default uses the program `less` to + scroll the output. + Use `/sometext` `` to find "sometext" and you can cycle through the results with `n` (next) and `N` (last). + You can also use page up/down to scroll. You can quit with `q`. + ```` + + ````{group-tab} Browser (GitHub) + We can try the same example in the browser: + + + ```{figure} img/archaeology/annotate.png + :alt: Screenshot of file annotation on GitHub + :width: 100% + :class: with-border + + Screenshot of file annotation on GitHub. + ``` + ```` +````` + +```{discussion} +Discuss how these relatively trivial changes affect the annotation: +- Wrapping long lines of text/code into shorter lines +- Auto-formatting tools such as `black` +- Editors that automatically remove trailing whitespace +``` + + +### Inspecting code in the past + +`````{tabs} + ````{group-tab} Command line + We can create branches pointing to a commit in the past. + This is the recommended mechanism to inspect old code: + + ```console + $ git switch --create BRANCHNAME HASH + ``` + + Example (lines starting with "#" are only comments): + + ```console + $ # create branch called "older-code" from hash 347e6292419b + $ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9 + + $ # now you can navigate and inspect the code as it was back then + $ # ... + + $ # after we are done we can switch back to "main" + $ git switch main + + $ # if we like we can delete the "older-code" branch + $ git branch -d older-code + ``` + + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + + ```console + $ git checkout -b BRANCHNAME SOMEHASH + ``` + ```` + + ````{group-tab} Browser (GitHub) + We now know how to visit a specific commit: + + + Once we are there we can "Browse files" at that point in history. + + ```{figure} img/archaeology/browse-files.png + :alt: Browsing code in the past on GitHub + :width: 100% + :class: with-border + + Browsing code in the past on GitHub. + ``` + ```` +````` + + +(exercise-history)= + +## Exercise: Basic archaeology commands + +`````{exercise} History-1: Explore basic archaeology commands + Let us explore the value of these commands in an exercise. Future + exercises do not depend on this, so it is OK if you do not complete + it fully. + + Exercise steps: + - Clone this repository: + . + Then step into the new directory and create an exercise branch from the networkx-2.6.3 tag/release: + ```console + $ git clone https://github.com/networkx/networkx.git + $ cd networkx + $ git switch --create exercise networkx-2.6.3 + ``` + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + ```console + $ git checkout -b exercise networkx-2.6.3 + ``` + + Then using the above toolbox try to: + 1. Find the code line which contains `"Logic error in degree_correlation"`. + 2. Find out when this line was last modified or added. Find the actual commit which modified that line. + 3. Inspect that commit with `git show`. + 4. Create a branch pointing to the past when that commit was created to be + able to browse and use the code as it was back then. + 5. How would you bring the code to the version of the code right before that line was last modified? + + ````{solution} + We provide here a solution for the command line but we also encourage you to + try to solve this in the browser. + + 1. We use `git grep`: + ```console + $ git grep "Logic error in degree_correlation" + ``` + This gives the output: + ``` + networkx/algorithms/threshold.py: print("Logic error in degree_correlation", i, rdi) + ``` + Maybe you also want to know the line number: + ```console + $ git grep -n "Logic error in degree_correlation" + ``` + 2. We use `git annotate`: + ```console + $ git annotate networkx/algorithms/threshold.py + ``` + Then search for "Logic error" by typing "/Logic error" followed by Enter. + The last commit that modified it was `90544b4fa` (unless that line changed since). + 3. We use `git show`: + ```console + $ git show 90544b4fa + ``` + 4. Create a branch pointing to that commit (here we called the branch "past-code"): + ```console + $ git branch past-code 90544b4fa + ``` + 5. This is a compact way to access the first parent of `90544b4fa` (here we + called the branch "just-before"): + ```console + $ git switch --create just-before 90544b4fa~1 + ``` + ```` +````` + +--- + +## Finding out when something broke/changed with `git bisect` + +> *"But I am sure it used to work! Strange."* + +Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke. + +```{discussion} How would you solve this? +Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now. + +- How would you find the commit which changed it? +- Why could it be useful to know the commit that changed it? +``` + +We will probably arrive at a solution which is similar to `git bisect`: + +- First find out a commit in past when it worked. + ```console + $ git bisect start + $ git bisect good f0ea950 # this is a commit that worked + $ git bisect bad main # last commit is broken + ``` +- Now compile and/or run and/or test and decide whether "good" or "bad". +- This is how you can tell Git that this was a working commit: + ```console + $ git bisect good + ``` +- And this is how you can tell Git that this was not a working commit: + ```console + $ git bisect bad + ``` +- Then bisect/iterate your way until you find the commit that broke it. +- If you want to go back to start, type `git bisect reset`. +- This can even be automatized with `git bisect run SCRIPT`. + For this you write a script that returns zero/non-zero (success/failure). + +(exercise-bisect)= + +## Optional exercise: Git bisect + +````{exercise} (optional) History-2: Use git bisect to find the bad commit + In this exercise, we use `git bisect` on an example repository. It + is OK if you do not complete this exercise fully. + + Begin by cloning [https://github.com/coderefinery/git-bisect-exercise](https://github.com/coderefinery/git-bisect-exercise). + + + **Motivation** + + The motivation for this exercise is to be able to do archaeology with Git on a + source code where the bug is difficult to see visually. **Finding the offending + commit is often more than half the debugging**. + + + **Background** + + The script `get_pi.py` approximates pi using terms of the Nilakantha series. It + should produce 3.14 but it does not. The script broke at some point and + produces 3.57 using the last commit: + + ```console + $ python get_pi.py + + 3.57 + ``` + + At some point within the 500 first commits, an error was introduced. The only + thing we know is that the first commit worked correctly. + + + **Your task** + + - Clone this repository and use `git bisect` to find the commit which + broke the computation + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + - Once you have found the offending commit, also practice navigating to the last good commit. + - Bonus exercise: + Write a script that checks for a correct result and use `git bisect run` to + find the offending commit automatically + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + + + **Hints** + + Finding the first commit: + + ```console + $ git log --oneline | tail -n 1 + ``` + + How to navigate to the parent of a commit with hash SOMEHASH: + ```console + $ git switch --create BRANCHNAME SOMEHASH~1 + ``` + + Instead of a tilde you can also use this: + ```console + $ git switch --create BRANCHNAME SOMEHASH^ + ``` +```` + +```{keypoints} +- git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project. +- `git switch --create NAME HASH` is the recommended mechanism to inspect old code. +``` diff --git a/branch/2023-version/_sources/basics.md.txt b/branch/2023-version/_sources/basics.md.txt new file mode 100644 index 00000000..94038290 --- /dev/null +++ b/branch/2023-version/_sources/basics.md.txt @@ -0,0 +1,717 @@ +# Basics + +```{objectives} +- Learn to create Git repositories and make commits. +- Get a grasp of the structure of a repository. +- Learn how to inspect the project history. +- Learn how to write useful commit log messages. +``` + +```{instructor-note} +- 35 min teaching/type-along +- 40 min exercise +``` + + +## What is Git, and what is a Git repository? + +- Git is a version control system: can **record/save snapshots** and track the content of a folder as it changes over time. +- Every time we **commit** a snapshot, Git records a snapshot of the **entire project**, saves it, and assigns it a version. +- These snapshots are kept inside a sub-folder called `.git`. +- If we remove `.git`, we remove the repository and history (but keep the working directory!). +- The directory `.git` uses relative paths - you can move the whole repository somewhere else and it will still work. +- Git doesn't do anything unless you ask it to (it **does not record anything automatically**). +- Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces). + + +## Recording a snapshot with Git + +- Git takes snapshots only if we request it. +- We will record changes in two steps (we will later explain why this is a recommended practice). +- Example (we don't need to type yet): + + ```console + $ git add FILE.txt + $ git commit + + $ git add FILE.txt ANOTHERFILE.txt + $ git commit + ``` + +- We first focus (`git add`, we "stage" the change), then record (`git commit`): + +```{figure} img/git_stage_commit.svg +:alt: Git staging +:width: 100% + +Git staging and committing. +``` + +```{discussion} Question for the more advanced participants +What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end. +``` + + +## Configuring Git command line + +Before we start using Git on the command line, we need to configure Git. +This is also part of the +[installation instructions](https://coderefinery.github.io/installation/shell-and-git/#configuration) +but we need to make sure we all have +set name, email address, editor, and +default branch: +```console +$ git config --global user.name "Your Name" +$ git config --global user.email yourname@example.com +$ git config --global core.editor nano +$ git config --global init.defaultBranch main +``` + +Verify with: +```console +$ git config --list +``` + +```{instructor-note} +Instructors, give learners enough time to do the above configuration steps. +``` + + +## Type-along: Tracking a guacamole recipe with Git + +We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list) + +The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language. + +```{instructor-note} +Instructors, please encourage now that participants type along. +``` + +```{note} +It is possible to go through this lesson in the command line or in the browser +(on GitHub). + +- We recommend to start with the command line but later to also try in the browser. +- If you get really stuck in the command line, try following in the browser and + later you can try to return to the command line. +``` + + +## Creating a repository + +One of the basic principles of Git is that it is **easy to create repositories**: + +`````{tabs} + ````{group-tab} Command line + ```console + $ mkdir recipe + $ cd recipe + $ git init -b main + ``` + + That's it! With `git init -b main` have now created an empty Git repository + where `main` is the default branch (more about branches later). + + We will use `git status` a lot to check out what is going on: + + ```console + $ git status + + On branch main + + No commits yet + + nothing to commit (create/copy files and use "git add" to track) + ``` + + We will make sense of this information during this workshop. + ```` + + ````{group-tab} Browser (GitHub) + First log into GitHub, then follow the screenshots and descriptions below. + + ```{figure} img/basics/new-repo-plus.png + :alt: Screenshot on GitHub before a new repository form is opened + :width: 100% + :class: with-border + + Click on the "plus" symbol on top right, then on "New repository". + ``` + + Another way to create a new repository is to visit + directly. + + ```{figure} img/basics/new-repo-form.png + :alt: Screenshot on GitHub just before creating a new repository + :width: 100% + :class: with-border + + Choose a repository name, add a short description, **check "Add a + README file"**, finally "Create repository". + ``` + + After you have clicked "Create repository" you should see a repository overview + with one file (README.md) and one commit. + ```` +````` + + +## Adding files and committing changes + +Let us now **create two files**. + +One file is called `ingredients.txt` and contains: +```shell +* 2 avocados +* 1 chili +* 1 lime +* 2 tsp salt +``` + +The second file is called `instructions.txt` and contains: +```shell +* chop avocados +* chop onion +* chop chili +* squeeze lime +* add salt +* and mix well +``` + +`````{tabs} + ````{group-tab} Command line + As mentioned above, in Git you can always check the status of files in your repository using + `git status`. It is always a safe command to run and in general a good idea to + do when you are trying to figure out what to do next: + + ```console + $ git status + + On branch main + + No commits yet + + Untracked files: + (use "git add ..." to include in what will be committed) + ingredients.txt + instructions.txt + + nothing added to commit but untracked files present (use "git add" to track) + ``` + + The two files are untracked in the repository (directory). You want to **add the files** (focus the camera) + to the list of files tracked by Git. Git does not track + any files automatically and you need make a conscious decision to add a file. Let's do what + Git hints at, and add the files, one by one: + + ```console + $ git add ingredients.txt + $ git status + + On branch main + + No commits yet + + Changes to be committed: + (use "git rm --cached ..." to unstage) + new file: ingredients.txt + + Untracked files: + (use "git add ..." to include in what will be committed) + instructions.txt + ``` + + Now this change is *staged* and ready to be committed. + Let us now commit the change to the repository: + ```console + $ git commit -m "adding ingredients" + + [main (root-commit) f146d25] adding ingredients + 1 file changed, 4 insertions(+) + create mode 100644 ingredients.txt + ``` + + Right after we query the status to get this useful command into our muscle memory: + ```console + $ git status + ``` + + Now stage and commit also the other file: + ```console + $ git add instructions.txt + $ git commit -m "adding instructions" + ``` + + We will add a third file to the repository, `README.md`, containing: + ```markdown + # recipe + + This is an exercise repository. + ``` + + Now stage and commit also the `README.md` file: + ```console + $ git add README.md + $ git commit -m "adding README" + ``` + + What does the `-m` flag mean? Let us check the help page for that command: + ```console + $ git help commit + ``` + + You should see a very long help page as the tool is very versatile (press q to quit). + Do not worry about this now but keep in mind that you can always read the help files + when in doubt. Searching online can also be useful, but choosing search terms + to find relevant information takes some practice and discussions in some + online threads may be confusing. + Note that help pages also work when you don't have a network connection! + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/add-file.png + :alt: Screenshot on GitHub before a new file is created + :width: 100% + :class: with-border + + Click on "Add file", then "Create new file". + ``` + + ```{figure} img/basics/edit-file.png + :alt: Screenshot on GitHub when editing a file + :width: 100% + :class: with-border + + Edit the file and specify the file name. + ``` + + ```{figure} img/basics/commit-changes.png + :alt: Screenshot on GitHub when editing the commit message + :width: 100% + :class: with-border + + Before you commit the change, adjust the commit message. + ``` + + After you have added `ingredients.txt`, add also `instructions.txt` in a similar + way. + + We have added two files, each in one commit. However, we ended up with + three files and three commits since `README.md` was automatically committed + when we created the repository on GitHub. + ```` +````` + + +(exercise-record-changes)= + +## Exercise: Record changes + +``````{exercise} Basic-1: Record changes + Add 1/2 onion to `ingredients.txt` and also the instruction + to "enjoy!" to `instructions.txt`. + + `````{tabs} + ````{group-tab} Command line + After modifying the files, do not stage the changes yet (do not `git add` + yet). + + When you are done editing the files, try `git diff`: + ```console + $ git diff + ``` + + You will see (can you identify in there the two added lines?): + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index 4422a31..ba8854f 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -2,3 +2,4 @@ + * 1 chili + * 1 lime + * 2 tsp salt + +* 1/2 onion + diff --git a/instructions.txt b/instructions.txt + index 7811273..2b11074 100644 + --- a/instructions.txt + +++ b/instructions.txt + @@ -4,3 +4,4 @@ + * squeeze lime + * add salt + * and mix well + +* enjoy! + ``` + + Now first stage and commit each change separately (what happens when we leave out the `-m` flag?): + ```console + $ git add ingredients.txt + $ git commit -m "add half an onion" + $ git add instructions.txt + $ git commit # <-- we have left out -m "..." + ``` + + When you leave out the `-m` flag, Git should open an editor where you can edit + your commit message. This message will be associated and stored with the + changes you made. This message is your chance to explain what you've done and + convince others (and your future self) that the changes you made were + justified. Write a message and save and close the file. + + When you are done committing the changes, experiment with these commands: + ```console + $ git log + $ git log --stat + $ git log --oneline + ``` + ```` + + ````{group-tab} Browser (GitHub) + We can make modifications to a file by clicking on the file and then the + pen symbol: + ```{figure} img/basics/pen-symbol.png + :alt: Screenshot on GitHub before clicking on the pen symbol + :width: 100% + :class: with-border + + By clicking on the pen symbol we can switch to edit mode. + ``` + + ```{figure} img/basics/preview.png + :alt: Screenshot on GitHub when previewing file changes + :width: 100% + :class: with-border + + Before committing the change, click on "Preview". + ``` + + Our goal is to arrive at two new commits: + - "add half an onion" (modifying `ingredients.txt`) + - "don't forget to enjoy" (modifying `instructions.txt`) + + When you are done committing the changes, try to browse commit history + on GitHub. + ```` + ````` +`````` + + +## Git history and log + +`````{tabs} + ````{group-tab} Command line + If you haven't yet, please try now `git log`: + + ```console + $ git log + + commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main) + Author: Radovan Bast + Date: Sun Sep 17 19:12:47 2023 +0200 + + don't forget to enjoy + + commit 79161b6e67c62ad4688a58c1e54183334611a390 + Author: Radovan Bast + Date: Sun Sep 17 19:12:32 2023 +0200 + + add half an onion + + commit a3394e39535343c4dae3bb4f703741a31aa8b78a + Author: Radovan Bast + Date: Sun Sep 17 18:47:14 2023 +0200 + + adding README + + commit 369624674e63de48055a65bf63055bd59c985d22 + Author: Radovan Bast + Date: Sun Sep 17 18:46:58 2023 +0200 + + adding instructions + + commit f146d25b94569a15e94d7f0da6f15d7554f76c49 + Author: Radovan Bast + Date: Sun Sep 17 18:35:52 2023 +0200 + + adding ingredients + ``` + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/commits.png + :alt: Screenshot on GitHub before clicking on commit history + :width: 100% + :class: with-border + + Click on the history symbol with (here) 5 commits. + ``` + + ```{figure} img/basics/history.png + :alt: Screenshot of GitHub repository commit history + :width: 100% + :class: with-border + + In this overview you can browse each commit individually. + ``` + + On GitHub you can also compare arbitrary two commits (replace "USER", + "HASH1", and "HASH2"): + `https://github.com/USER/recipe/compare/HASH1..HASH2` + + Try it with two of your commits. + ```` +````` + +- We can browse the development and access each state that we have committed. +- The long hashes uniquely label a state of the code. +- They are not just integers counting 1, 2, 3, 4, ... (why?). +- Output is in reverse chronological order, i.e. **newest commits on top**. +- We will use them when comparing versions and when going back in time. +- `git log --oneline` only shows the first 7 characters of the commit hash and is good to get an overview. +- If the first characters of the hash are unique it is not necessary to type the entire hash. +- `git log --stat` is nice to show which files have been modified. + + +(exercise-diff-and-rename)= + +## Optional exercises: Comparing changes + +``````{exercise} (optional) Basic-2: Comparing and showing commits + `````{tabs} + ````{group-tab} Command line + 1. Have a look at specific commits with `git show HASH`. + 2. Inspect differences between commit hashes with `git diff HASH1 HASH2`. + ```` + + ````{group-tab} Browser (GitHub) + 1. Have a look at specific commits. + 2. Inspect differences between commits. + + Use the screenshots under "Git history and log". + ```` + ````` +`````` + +````{exercise} (optional) Basic-3: Visual diff tools + This exercise is only relevant for the command line. In the browser, + the preview is already side-by-side and "visual". + + - Make further modifications and experiment with `git difftool` (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + On Windows or Linux: + ```console + $ git difftool --tool=meld HASH + ``` + + On macOS: + ```console + $ git difftool --tool=opendiff HASH + ``` + + ```{figure} img/meld.png + :alt: Git difftool using meld + :width: 100% + + Git difftool using meld. + ``` + + You probably want to use the same visual diff tool every time and + you can configure Git for that: + ```console + $ git config --global diff.tool meld + ``` +```` + +```{exercise} (optional) Basic-4: Browser and command line +You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both. + +- If you have managed to do the above in the command line, try now in the browser. +- If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git. +``` + + +## Writing useful commit messages + +Using `git log --oneline` or browsing a repository on the web, we better +understand that the first line of the commit message is very important. + +Good example: +```text +increase threshold alpha to 2.0 + +the motivation for this change is +to enable ... +... +this is based on a discussion in #123 +``` + +Convention: **one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary**. + +- **Why something was changed is more important than what has changed.** +- Cross-reference to issues and discussions if possible/relevant. +- Bad commit messages: "fix", "oops", "save work" +- Bad examples: [http://whatthecommit.com](http://whatthecommit.com) +- Write commit messages in English that will be understood + 15 years from now by someone else than you. Or by your future you. +- Many projects start out as projects "just for me" and end up to be successful projects + that are developed by 50 people over decades. +- [Commits with multiple authors](https://help.github.com/articles/creating-a-commit-with-multiple-authors/) are possible. + +Good references: + +- ["My favourite Git commit"](https://fatbusinessman.com/2019/my-favourite-git-commit) +- ["On commit messages"](https://who-t.blogspot.com/2009/12/on-commit-messages.html) +- ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) + +```{note} +A great way to learn how to write commit messages and to get inspired by their +style choices: **browse repositories of codes that you use/like**: + +Some examples (but there are so many good examples): +- [SciPy](https://github.com/scipy/scipy/commits/main) +- [NumPy](https://github.com/numpy/numpy/commits/main) +- [Pandas](https://github.com/pandas-dev/pandas/commits/main) +- [Julia](https://github.com/JuliaLang/julia/commits/master) +- [ggplot2](https://github.com/tidyverse/ggplot2/commits/main), + compare with their [release + notes](https://github.com/tidyverse/ggplot2/releases) +- [Flask](https://github.com/pallets/flask/commits/main), + compare with their [release + notes](https://github.com/pallets/flask/blob/main/CHANGES.rst) + +When designing commit message styles consider also these: +- How will you easily generate a changelog or release notes? +- During code review, you can help each other improving commit messages. +``` + +But remember: it is better to make any commit, than no commit. Especially in small projects. +**Let not the perfect be the enemy of the good enough**. + + +(gitignore)= + +## Ignoring files and paths with .gitignore + +```{discussion} +- Should we add and track all files in a project? +- How about generated files? +- Why is it considered a bad idea to commit compiled binaries to version control? +- What types of generated files do you know? +``` + +Compiled and generated files are not +committed to version control. There are many reasons for this: + +- These files can make it more difficult to run on different platforms. +- These files are automatically generated and thus do not contribute in any meaningful way. +- When tracking generated files you could see differences in the code although you haven't touched the code. + +For this we use `.gitignore` files. Example: +```shell +# ignore compiled python 2 files +*.pyc +# ignore compiled python 3 files +__pycache__ +``` + +An example taken from the [official Git documentation](https://git-scm.com/docs/gitignore): +```shell +# ignore objects and archives, anywhere in the tree. +*.[oa] +# ignore generated html files, +*.html +# except foo.html which is maintained by hand +!foo.html +# ignore everything under build directory +build/ +``` + +- `.gitignore` should be part of the repository because we want to make sure that all developers see the same behavior. +- **All files should be either tracked or ignored**. +- `.gitignore` uses something called a + [shell glob syntax](https://en.wikipedia.org/wiki/Glob_(programming)) for + determining file patterns to ignore. You can read more about the syntax in the + [documentation](https://git-scm.com/docs/gitignore). +- You can have `.gitignore` files in lower level directories and they affect the paths below. + + +## Graphical user interfaces + +We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI): + +- [GitHub Desktop](https://desktop.github.com) +- [SourceTree](https://www.sourcetreeapp.com) +- [List of third-party GUIs](https://git-scm.com/downloads/guis) + + +## Summary + +Now we know how to save snapshots: + +```console +$ git add FILE(S) +$ git commit +``` + +And this is what we do as we program. + +Every state is then saved and later we will learn how to go back to these "checkpoints" +and how to undo things. + +```console +$ git init -b main # initialize new repository (main is default branch) +$ git add # add files or stage file(s) +$ git commit # commit staged file(s) +$ git status # see what is going on +$ git log # see history +$ git diff # show unstaged/uncommitted modifications +$ git show # show the change for a specific commit +$ git mv # move/rename tracked files +$ git rm # remove tracked files +``` + +Git is not ideal for large binary files +(for this consider [git-annex](http://git-annex.branchable.com)). + +````{challenge} Basic-5: Test your understanding + Which command(s) below would save the changes of `myfile.txt` + to an existing local Git repository? + + 1. ```console + $ git commit -m "my recent changes" + ``` + 2. ```console + $ git init myfile.txt + $ git commit -m "my recent changes" + ``` + 3. ```console + $ git add myfile.txt + $ git commit -m "my recent changes" + ``` + 4. ```console + $ git commit -m myfile.txt "my recent changes" + ``` + ```{solution} + + 1. Would only create a commit if files have already been staged. + 2. Would try to create a new repository in a folder "myfile.txt". + 3. **Is correct: first add the file to the staging area, then commit.** + 4. Would try to commit a file "my recent changes" with the message myfile.txt. + ``` +```` + +```{keypoints} +- It takes only one command to initialize a Git repository: `git init -b main`. +- Commits should be used to tell a story. +- Git uses the .git folder to store the snapshots. +- Don't be afraid to stage and commit often. Better too often than not often enough. +``` diff --git a/branch/2023-version/_sources/branches.md.txt b/branch/2023-version/_sources/branches.md.txt new file mode 100644 index 00000000..418e4d67 --- /dev/null +++ b/branch/2023-version/_sources/branches.md.txt @@ -0,0 +1,624 @@ +# Branching and merging + +```{objectives} +- Be able to create and merge branches. +- Know the difference between a branch and a tag. +``` + +```{instructor-note} +- 30 min teaching/type-along +- 20 min exercise +``` + + +## Motivation for branches + +In the previous section we tracked a guacamole recipe with Git. + +Up until now our repository had only one branch with one commit coming +after the other: + +```{figure} img/gitink/git-branch-1.svg +:alt: Linear Git repository +:width: 40% + +Linear Git repository. +``` + +- Commits are depicted here as little boxes with abbreviated hashes. +- Here the branch `main` points to a commit. +- "HEAD" is the current position (remember the recording head of tape + recorders?). When we say `HEAD`, we mean those literal letters - + this isn't a placeholder for something else. +- When we talk about branches, we often mean all parent commits, not only the commit pointed to. + +**Now we want to do this:** + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +Software development is often not linear: + +- We typically need at least one version of the code to "work" (to compile, to give expected results, ...). +- At the same time we work on new features, often several features concurrently. + Often they are unfinished. +- We need to be able to separate different lines of work really well. + +The strength of version control is that it permits the researcher to **isolate +different tracks of work**, which can later be merged to create a composite +version that contains all changes: + +```{figure} img/gitink/git-collaborative.svg +:alt: Isolated tracks of work +:width: 100% + +Isolated tracks of work. +``` + +- We see branching points and merging points. +- Main line development is often called `main` or `master`. +- Other than this convention there is nothing special about `main` or `master`, it is a branch like any other. +- Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow). + +A group of commits that create a single narrative are called a **branch**. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. "fast sequence extraction" or "Python interface" or "fixing bug in +matrix inversion algorithm". + +````{admonition} **An important alias** +--- +class: important +--- + +We will now define an *alias* in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). **This is extensively used in the rest of this +and other lessons**: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` +```` + +```{instructor-note} +Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative. +``` + +Let us inspect the project history using the `git graph` alias: + +```console +$ git graph + +* e7cf023 (HEAD -> main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- We have a couple commits and only + one development line (branch) and this branch is called `main`. +- Commits are states characterized by a 40-character hash (checksum). +- `git graph` print abbreviations of these checksums. +- **Branches are pointers that point to a commit.** +- Branch `main` points to a commit (in this example it is `e7cf023efe382340e5284c278c6ae2c087dd3ff7` but on your computer + the hash will be different). +- `HEAD` is another pointer, it points to where we are right now (currently `main`) + +In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards. + + +## Creating and working with branches + +```{instructor-note} +We do the following part together. Encourage participants to type along. +``` + +```{admonition} It is possible to create and merge branches directly on GitHub +- However, we do not have screenshots for that in this episode +- But if you prefer to work in the browser, please try it +- Please contribute screenshots to this lesson +``` + +Let's create a branch called `experiment` where we add cilantro to `ingredients.txt` +(text after "#" are comments and not part of the command). + +```console +$ git branch experiment main # creates branch "experiment" from "main" +$ git switch experiment # switch to branch "experiment" +$ git branch # list all local branches and show on which branch we are +``` + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +- Verify that you are on the `experiment` branch (note that `git graph` also + makes it clear what branch you are on: `HEAD -> branchname`): + ```console + $ git branch + + * experiment + main + ``` + This command shows where we are, it does not create a branch. + +- Then add 2 tbsp cilantro **on top** of the `ingredients.txt`: + + ```{code-block} shell + --- + emphasize-lines: 1 + --- + * 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + * 2 tsp salt + * 1/2 onion + ``` + +- Stage this and commit it with the message "let us try with some cilantro". +- Then reduce the amount of cilantro to 1 tbsp, stage and commit again with "maybe little bit less cilantro". + +We have created **two new commits**: + +```{code-block} console +--- +emphasize-lines: 3-4 +--- +$ git graph + +* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro +* f6ec7b7 let us try with some cilantro +* e7cf023 (main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- The branch `experiment` is two commits ahead of `main`. +- We commit our changes to this branch. + + +(exercise-branches)= + +## Exercise: Create and commit to branches + +````{exercise} Branch-1: Create and commit to branches + In this exercise, you will create another new branch and few more commits. + We will use this in the next section, to practice + merging. **The goal of the exercise is to end up with 3 branches**. + + - Change to the branch `main`. + - Create another branch called `less-salt`. + - Note! makes sure you are on main branch when you create the `less-salt` branch. + - A safer way would be to explicitly mention to create from the main branch + as shown below: + ```console + $ git branch less-salt main + ``` + - Switch to the `less-salt` branch. + - On the `less-salt` branch reduce the amount of salt. + - Commit your changes to the `less-salt` branch. + + Use the same commands as we used above. + + We now have three branches (in this case `HEAD` points to `less-salt`): + + ```console + $ git branch + + experiment + * less-salt + main + + $ git graph + + * bf28166 (HEAD -> less-salt) reduce amount of salt + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 (main) don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + Here is a graphical representation of what we have created: + + ```{figure} img/gitink/git-branch-2.svg + ``` + + - Now switch to `main`. + - In a new commit, improve the `README.md` file (we added the word "Guacamole"): + + ```markdown + # Guacamole recipe + + This is an exercise repository. + ``` + + Now you should have this situation: + + ```console + $ git graph + + * b4af65b (HEAD -> main) improve the documentation + | * bf28166 (less-salt) reduce amount of salt + |/ + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + ```{figure} img/gitink/git-branch-3.svg + ``` + + And for comparison this is how it looks [on GitHub](https://github.com/coderefinery/recipe-before-merge/network). +```` + +(exercise-branches-merging)= + +## Exercise: Merging branches + +It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge `experiment` into `main`. + +```{exercise} Branch-2: Merge branches +Merge `experiment` and `less-salt` back into `main` following the lesson below +until the point where we start deleting branches. +``` + +````{admonition} If you got stuck in the above exercises or joined later + **If you got stuck in the above exercises or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git switch experiment + $ git switch less-salt + $ git switch main + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +First we make sure we are on the branch we wish to merge **into**: + +```{code-block} console +--- +emphasize-lines: 5 +--- +$ git branch + + experiment + less-salt +* main +``` + +Then we merge `experiment` into `main`: + +```console +$ git merge experiment +``` + +```{figure} img/gitink/git-merge-1.svg +``` + +We can verify the result: + +```console +$ git graph + +* 81fcc0c (HEAD -> main) Merge branch 'experiment' +|\ +| * bcb8b78 (experiment) maybe little bit less cilantro +| * f6ec7b7 let us try with some cilantro +* | b4af65b improve the documentation +|/ +| * bf28166 (less-salt) reduce amount of salt +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents. + +To view the branches that are merged into the current branch we can use the command: + +```console +$ git branch --merged + + experiment +* main +``` + +We are also happy with the work on the `less-salt` branch. Let us merge that +one, too, into `main`: + +```console +$ git branch # make sure you are on main +$ git merge less-salt +``` + +```{figure} img/gitink/git-merge-2.svg +:alt: Commit graph after merge + +Commit graph after merge. +``` + +We can verify the result in the terminal: + +```console +$ git graph + +* 4e03d4b (HEAD -> main) Merge branch 'less-salt' +|\ +| * bf28166 (less-salt) reduce amount of salt +* | 81fcc0c Merge branch 'experiment' +|\ \ +| * | bcb8b78 (experiment) maybe little bit less cilantro +| * | f6ec7b7 let us try with some cilantro +| |/ +* / b4af65b improve the documentation +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +Observe how Git nicely merged the changed amount of salt and the new ingredient **in the same file +without us merging it manually**: + +```console +$ cat ingredients.txt + +* 1 tbsp cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually *settle merge conflicts* (we will do that later). + + +## Deleting branches safely + +Both feature branches are merged: + +```console +$ git branch --merged + + experiment + less-salt +* main +``` + +This means we can delete the branches: + +```console +$ git branch -d experiment +$ git branch -d less-salt +``` + +This is the result: + +```{figure} img/gitink/git-deleted-branches.svg +:alt: Commit graph after merged branches were deleted + +Commit graph after merged branches were deleted. +``` + +We observe that when deleting branches, +only the pointers ("sticky notes") disappeared, not the commits. + +Git will not let you delete a branch which has not been reintegrated unless you +insist using `git branch -D`. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them. + + +(exercise-branches-optional)= + +## Optional exercises with branches + +The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section. + +````{exercise} (optional) Branch-3: Perform a fast-forward merge +1. Create a new branch from `main` and switch to it. +2. Create a couple of commits on the new branch (for instance edit `README.md`): + ```{figure} img/gitink/git-pre-ff.svg + ``` +3. Now switch to `main`. +4. Merge the new branch to `main`. +5. Examine the result with `git graph`. +6. Have you expected the result? Discuss what you see. + + ```{solution} + You will see that in this case no merge commit was created and Git merged the + two branches by moving (fast-forwarding) the "main" branch (label) three + commits forward. + + This was possible since one branch is the ancestor of the other and their + developments did not diverge. + + A merge that does not require any merge commit is a fast-forward merge. + ``` +```` + +````{exercise} (optional) Branch-4: Rebase a branch (instead of merge) +As an alternative to merging branches, one can also *rebase* branches. +Rebasing means that the new commits are *replayed* on top of another branch +(instead of creating an explicit merge commit). +**Note that rebasing changes history and should not be done on public commits!** +1. Create a new branch, and make a couple of commits on it. +2. Switch back to `main`, and make a couple of commits on it. +3. Inspect the situation with `git graph`. +4. Now rebase the new branch on top of `main` by first switching to the new branch, and then `git rebase main`. +5. Inspect again the situation with `git graph`. Notice that the commit hashes have changed - think about why! + + ```{solution} + You will notice two things: + - History is now linear and does not contain merge commits. + - All the commit hashes that were on the branch that got rebased, have + changed. This also demonstrates that `git rebase` is a command that alters + history. The commit history looks as if the rebased commits were all done + after the `main` commits. + ``` +```` + + +## Tags + +- A tag is a pointer to a commit but in contrast to a branch it **does not ever + move** when creating new commits later. +- It can be useful to think of branches as sticky notes and of tags as + [commemorative plaques](https://en.wikipedia.org/wiki/Commemorative_plaque). +- We use tags to record particular states or milestones of a project at a given + point in time, like for instance versions (have a look at [semantic versioning](http://semver.org), + v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a). +- There are two basic types of tags: annotated and lightweight. +- **Use annotated tags** since they contain the author and can be cryptographically signed using + GPG, timestamped, and a message attached. + +Let's add an annotated tag to our current state of the guacamole recipe: +```console +$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet" +``` + +As you may have found out already, `git show` is a very versatile command. Try this: + +```console +$ git show nobel-2023 +``` + +For more information about tags see for example +[the Pro Git book](https://git-scm.com/book/en/v2/Git-Basics-Tagging) chapter on the +subject. + +--- + +## Summary + +Let us pause for a moment and recapitulate what we have just learned: + +```console +$ git branch # see where we are +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +$ git merge NAME # merge branch NAME (to current branch) +$ git branch -d NAME # delete branch NAME +$ git branch -D NAME # delete unmerged branch NAME +``` + +Since the following command combo is so frequent: + +```console +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +``` + +There is a shortcut for it: + +```console +$ git switch --create NAME # create branch NAME and switch to it +``` + +### Typical workflows + +With this there are two typical workflows: + +```console +$ git switch --create new-feature # create branch, switch to it +$ git commit # work, work, work, ..., and test +$ git switch main # once feature is ready, switch to main +$ git merge new-feature # merge work to main +$ git branch -d new-feature # remove branch +``` + +Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging: + +```console +$ git switch --create wild-idea # create branch, switch to it, work, work, work ... +$ git switch main # realize it was a bad idea, back to main +$ git branch -D wild-idea # it is gone, off to a new idea +``` + +--- + +````{challenge} Branch-5: Test your understanding + Which of the following combos (one or more) creates a new branch and makes a commit to it? + 1. ```console + $ git branch new-branch + $ git add file.txt + $ git commit + ``` + 2. ```console + $ git add file.txt + $ git branch new-branch + $ git switch new-branch + $ git commit + ``` + 3. ```console + $ git switch --create new-branch + $ git add file.txt + $ git commit + ``` + 4. ```console + $ git switch new-branch + $ git add file.txt + $ git commit + ``` + + ```{solution} + Both 2 and 3 would do the job. Note that in 2 we first stage the file, and then create the + branch and commit to it. In 1 we create the branch but do not switch to it, while in 4 we + don't give the `--create` flag to `git switch` to create the new branch. + ``` +```` + +```{keypoints} +- A branch is a division unit of work, to be merged with other units of work. +- A tag is a pointer to a moment in the history of a project. +``` diff --git a/branch/2023-version/_sources/conflicts.md.txt b/branch/2023-version/_sources/conflicts.md.txt new file mode 100644 index 00000000..34b978ad --- /dev/null +++ b/branch/2023-version/_sources/conflicts.md.txt @@ -0,0 +1,463 @@ +(conflict-resolution)= + +# Conflict resolution + +```{objectives} +- Understand merge conflicts sufficiently well to be able to fix them. +``` + +```{instructor-note} +- 20 min teaching/type-along +- 20 min exercise +``` + + +## Conflicts in Git and why they are good + +Imagine we start with the following text file: +```{code-block} +1 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1/2 onion +``` + +On branch A somebody modifies: +```{code-block} +--- +emphasize-lines: 1, 4 +--- +2 tbsp cilantro +2 avocados +1 chili +2 lime +1 tsp salt +1/2 onion +``` + +On branch B somebody else modifies: +```{code-block} +--- +emphasize-lines: 1, 6 +--- +1/2 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1 onion +``` + +When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro: +```{code-block} +--- +emphasize-lines: 1 +--- +????????????????? +2 avocados +1 chili +2 lime +1 tsp salt +1 onion +``` + +Git is very good at resolving modifications when merging branches and +in most cases a `git merge` runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see {ref}`exercise-branches-optional`) without you even noticing. + +But sometimes the **same portion** of the code/text is modified on two branches +**in two different ways** and Git issues a **conflict**. +Then you need to tell Git which version to keep (**resolve** it). + +There are several ways to do that as we will see. + +Please remember: + +- It is good that Git conflicts exist: Git will not silently overwrite one of + two differing modifications. +- Conflicts may look scary, but are not that bad after a little bit of + practice. Also they are luckily rare. +- Don't be afraid of Git because of conflicts. You may not meet some conflicts + using other systems because you simply can't do the kinds of things you do + in Git. +- You can take human measures to reduce them. + +--- + +```{discussion} The human side of conflicts +- What does it mean if two people do the same thing in two different ways? +- What if you work on the same file but do two different things in the different sections? +- What if you do something, don't tell someone from 6 months, and then try to combine it with other people's work? +- How are conflicts avoided in other work? (Only one person working at once? + Declaring what you are doing before you start, if there is any chance someone + else might do the same thing, helps.) +- Minor conflicts (two people revise spelling) vs semantic (two people rewrite + a function to add two different new features). How did Git solve these in + branching/merging easily? +``` + +Now we can go to show how Git controls when there is actually a conflict. + + +## Preparing a conflict + +```{instructor-note} +We do the following together as type-along/demo. +``` + +````{admonition} If you got stuck previously or joined later + **If you got stuck previously or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together. + +- Create two branches from `main`: one called `like-cilantro`, one called `dislike-cilantro`: + ```console + $ git branch like-cilantro main + $ git branch dislike-cilantro main + ``` + +- On the two branches make **different modifications** to the amount of the **same ingredient**: + +- On the branch `like-cilantro` we have the following change: + ```console + $ git diff main like-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6cacd50 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + +- And on the branch `dislike-cilantro` we have the following change: + ```console + $ git diff main dislike-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6484462 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 1/2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + + +## Merging conflicting changes + +What do you expect will happen when we try to merge these two branches into +main? + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +The first merge will work: + +```console +$ git switch main +$ git status +$ git merge like-cilantro + +Updating 4e03d4b..3caa632 +Fast-forward + ingredients.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +``` + +But the second will fail: + +```console +$ git merge dislike-cilantro + +Auto-merging ingredients.txt +CONFLICT (content): Merge conflict in ingredients.txt +Automatic merge failed; fix conflicts and then commit the result. +``` + +Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit: + +```{code-block} console +--- +emphasize-lines: 9 +--- +$ git status + +You have unmerged paths. + (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) + +Unmerged paths: + (use "git add ..." to mark resolution) + both modified: ingredients.txt + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +Git won't decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward. + +Let us inspect the conflicting file: + +```console +$ cat ingredients.txt + +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +Git inserted resolution markers (the `<<<<<<<`, `>>>>>>>`, and `=======`). + +Try also `git diff`: + +```console +$ git diff +``` + +```diff +diff --cc ingredients.txt +index 6cacd50,6484462..0000000 +--- a/ingredients.txt ++++ b/ingredients.txt +@@@ -1,4 -1,4 +1,10 @@@ +++<<<<<<< HEAD + +* 2 tbsp cilantro +++======= ++ * 1/2 tbsp cilantro +++>>>>>>> dislike-cilantro + * 2 avocados + * 1 chili + * 1 lime +``` + +`git diff` now only shows the conflicting part, nothing else. + + +## Conflict resolution + +``` +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +``` + +We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged. + +```{admonition} Steps to resolve a conflict + +- Check status with `git status` and `git diff`. +- Decide what you keep (the one, the other, or both or something + else). Edit the file to do this. + - Remove the resolution markers, if not already done. + - The file(s) should now look exactly how you want them. +- Check status with `git status` and `git diff`. +- Tell Git that you have resolved the conflict with `git add ingredients.txt` + (if you use the Emacs editor with a certain plugin the editor may stage the + change for you after you have removed the conflict markers). +- Verify the result with `git status`. +- Finally commit the merge with only `git commit`. Everything is pre-filled. +``` + +(exercise-conflicts)= + +## Exercise: Create and resolve a conflict + +````{exercise} Conflict-1: Create another conflict and resolve +In this exercise, we repeat almost exactly what we did above with a +different ingredient. + +1. Create two branches before making any modifications. +2. Again modify some ingredient on both branches. +3. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge. +4. What happens if you apply the same modification on both branches? +5. If you create a branch `like-avocados`, commit a change, then from this + branch create another banch `dislike-avocados`, commit again, and try to + merge both branches into `main` you will not see a conflict. Can you + explain, why it is different this time? +```{solution} +4: No conflict in this case if the change is the same. + +5: No conflict in this case since in Git history one change happened after the other. The two changes + are related and linked by Git history and one is a Git ancestor of the + other. Git will assume that since we applied one change after the other, + we meant this. There is nothing to resolve. +``` +```` + +(exercise-conflicts-optional)= + +## Optional exercises with conflict resolution + +````{exercise} (optional) Conflict-2: Resolve a conflict when rebasing a branch +1. Create two branches where you anticipate a conflict. +2. Try to merge them and observe that indeed they conflict. +3. Abort the merge with `git merge --abort`. +4. What do you expect will happen if you rebase one branch on top of the + other? Do you anticipate a conflict? Try it out. +```{solution} +Yes, this will conflict. If it conflicts during a merge, it will also conflict +during rebase but the conflict resolution looks slightly different: +You still need to look for conflict markers but you tell Git that you resolved +a conflict with `git add` and then you continue with `git rebase --continue`. +Follow instructions that you get from the Git command line. +``` +```` + +````{exercise} (optional) Conflict-3: Resolve a conflict using mergetool + - Again create a conflict (for instance disagree on the number of avocados). + - Stop at this stage: + + ```markdown + Auto-merging ingredients.txt + CONFLICT (content): Merge conflict in ingredients.txt + Automatic merge failed; fix conflicts and then commit the result. + ``` + + - Instead of resolving the conflict manually, use a visual tool + (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + ```console + $ git mergetool + ``` + + ```{figure} img/conflict-resolution/mergetool.png + :alt: Conflict resolution using mergetool + :width: 100% + ``` + + - Your current branch is left, the branch you merge is right, result is in the middle. + - After you are done, close and commit, `git add` is not needed when using `git mergetool`. + + If you have not instructed Git to avoid creating backups when using mergetool, then to be on + the safe side there will be additional temporary files created. To remove those you can do + a git clean after the merging. + + To view what will be removed: + + ```console + $ git clean -n + ``` + + To remove: + + ```console + $ git clean -f + ``` + + To configure Git to avoid creating backups at all: + + ```console + $ git config --global mergetool.keepBackup false + ``` +```` + +--- + +## Using "ours" or "theirs" strategy + +- Sometimes you know that you want to keep "ours" version (version on the branch you are on) + or "theirs" (version on the merged branch). +- Then you do not have to resolve conflicts manually. +- See [merge strategies](https://git-scm.com/docs/merge-strategies). + +Example (merge and in doubt take the changes from current branch): +```console +$ git merge -s recursive -Xours less-avocados +``` + +Or (merge and in doubt take the changes from less-avocados branch): +```console +$ git merge -s recursive -Xtheirs less-avocados +``` + +--- + +## Aborting a conflicting merge + +Sometimes you get a merge conflict but realize that you can't solve it without +talking to a colleague (who created the other change) first. What to do? + +You can abort the merge and postponing conflict resolution by resetting the +repository to `HEAD` (last committed state): + +```console +$ git merge --abort +``` + +The repository looks then exactly as it was before the merge. + +--- + +## Avoiding conflicts + +- Human measures + - Think and plan to which branch you will commit to. + - Do not put unrelated changes on the same branch. +- Collaboration measures + - Open an issue and discuss with collaborators before starting a long-living + branch. +- Project layout measures + - Modifying global data often causes conflicts. + - Modular programming reduces this risk. +- Technical measures + - **Share your changes early and often** - this is one of the happy, + rare circumstances when everyone doing the selfish thing (e.g. `git push` as + early as practical) results in best case for everyone! + - Pull/rebase often to keep up to date with upstream. + - Resolve conflicts early. + +```{discussion} +Discuss how Git handles conflicts compared to services like Google Drive. +``` + +```{keypoints} +- Conflicts often appear because of not enough communication or not optimal + branching strategy. +``` diff --git a/branch/2023-version/_sources/customizing.md.txt b/branch/2023-version/_sources/customizing.md.txt new file mode 100644 index 00000000..c8fdf72b --- /dev/null +++ b/branch/2023-version/_sources/customizing.md.txt @@ -0,0 +1,25 @@ +# Customizing Git + +## Shell prompt + +```{instructor-note} +Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like. +``` + +You can make your shell display contextual information about +your Git state even at all times. + +Here are few example projects that make this possible and easy: +- (bash) +- (zsh) +- (fish) +- (bash and fish) + + +## More useful "diff" output + +[Delta](https://github.com/dandavison/delta) is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +"diff" output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more. diff --git a/branch/2023-version/_sources/exercises.md.txt b/branch/2023-version/_sources/exercises.md.txt new file mode 100644 index 00000000..c7b63f59 --- /dev/null +++ b/branch/2023-version/_sources/exercises.md.txt @@ -0,0 +1,44 @@ +# List of exercises + +## Summary + +Basics: +- {ref}`exercise-record-changes` +- {ref}`exercise-diff-and-rename` + +Branching and merging: +- {ref}`exercise-branches` +- {ref}`exercise-branches-merging` +- {ref}`exercise-branches-optional` + +Conflict resolution: +- {ref}`exercise-conflicts` +- {ref}`exercise-conflicts-optional` + +Inspecting history: +- {ref}`exercise-history` +- {ref}`exercise-bisect` + +Using the Git staging area: +- {ref}`exercise-interactive-commits` +- {ref}`exercise-staging-area` + +Undoing and recovering: +- {ref}`exercise-revert` +- {ref}`exercise-amend` +- {ref}`exercise-reset` + +Interrupted work: +- {ref}`exercise-stashing` + + +## Full list + +This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests. + +```{exerciselist} +``` diff --git a/branch/2023-version/_sources/guide.md.txt b/branch/2023-version/_sources/guide.md.txt new file mode 100644 index 00000000..0561e2c9 --- /dev/null +++ b/branch/2023-version/_sources/guide.md.txt @@ -0,0 +1,261 @@ +# Instructor guide + +## Schedule Day 1 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:20 (20 min) Welcome and practical information + +- 09:20 - 09:35 (15 min) [Motivation](https://coderefinery.github.io/git-intro/motivation/) +- 09:35 - 09:50 (15 min) [Basics - configuration and first commits](https://coderefinery.github.io/git-intro/basics/) +- 09:50 - 10:00 (10 min) Break +- **10:00 - 10:20 (20 min) [Exercise](https://coderefinery.github.io/git-intro/basics/#exercise-record-changes)** + - Record changes + - Optional exercises +- 10:20 - 10:40 (20 min) [Basics - history, commit log, ignoring](https://coderefinery.github.io/git-intro/basics/#git-history-and-log) +- **10:40 - 11:00 (20 min) [Exercise](https://coderefinery.github.io/git-intro/basics/#optional-exercises-comparing-changes)** + - One or all optional exercises + +- 11:00 - 12:00: Lunch break + +- 12:00 - 12:15 (15 min) [Branching and merging](https://coderefinery.github.io/git-intro/branches/) +- **12:15 - 12:35 (20 min) [Exercise](https://coderefinery.github.io/git-intro/branches/#exercise-create-and-commit-to-branches)** + - Branch-1 + - Branch-2 +- 12:35 - 12:50 (15 min) Summarize/discuss branching and merging +- 12:50 - 13:00 (10 min) Break +- 13:00 - 13:20 (20 min) [Conflict resolution](https://coderefinery.github.io/git-intro/conflicts/) + +- 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow? + + +## Schedule Day 2 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:10 (10 min) Recap and Q&A from day 1 + +- 09:10 - 09:25 (15 min) [Sharing repositories online](https://coderefinery.github.io/git-intro/remotes/) +- **09:25 - 09:50 (25 min) Exercise** + - Set up SSH keys + - Pushing our guacamole recipe repository to GitHub + - Clone repository +- 09:50 - 10:00 (10 min) Break +- 10:00 - 10:15 (15 min) [Inspecting history](https://coderefinery.github.io/git-intro/archaeology/) +- **10:15 - 10:45 (30 min) [Exercise](https://coderefinery.github.io/git-intro/archaeology/#exercise-basic-archaeology-commands)** + - History-1 + - History-2 is optional +- 10:45 - 11:00 (15 min) Summarize/discuss inspecting history + +- 11:00 - 12:00: Lunch break + +- 12:00 - 12:15 (15 min) [Undoing and recovering](https://coderefinery.github.io/git-intro/recovering/) +- **12:15 - 12:40 (25 min) [Exercises](https://coderefinery.github.io/git-intro/recovering/)** + - Undoing-1 + - Undoing-2 + - Undoing-3 +- 12:40 - 11:50 (10 min) Summarize undoing and recovering and discussion and mention that staging area exists +- 12:50 - 13:00 (10 min) Break +- 13:00 - 13:20 (20 min) [How much Git is necessary?](https://coderefinery.github.io/git-intro/level/) + +- 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow? + + +## Installation reminders for each day + +- Day 1: Git configuration +- Day 2: SSH set up (if you don't, sharing repositories online will be demo) + + +## Why we teach this lesson + +Everyone should be using a version control system for their work, even if they're working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories. + +Specific motivations: +- Code easily becomes a disaster without version control +- Mistakes happen - Git offers roll-back functionality and easy backup mechanism +- One often needs to work on multiple things in parallel - branches solve that problem +- Git enables people to collaborate on code or text without stepping on each other's toes +- Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, + and if bugs are found one can find out exactly when it was introduced + +Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices (e.g. how to use the staging area), which is useful for more experienced users. + + +## Intended learning outcomes + +By the end of this lesson, learners should: +- realize that version control is very important and Git is a valuable tool to learn and use +- understand that Git is configurable and know how to set basic configurations +- be able to set up Git repositories and make commits +- understand that information on commits, branches etc. are stored under `.git/`, and have a + mental model of how that relates to the working directory +- have a mental model of the different states a file can have in Git (untracked, modified, staged, unmodified) +- know how to write good commit messages +- have an idea of how the staging area can be used to craft good commits +- know how to undo commits using `git revert` and discard changes using `git restore` +- understand that `git restore` can be dangerous if changes have not been staged +- know how to create branches and switch between branches +- have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way +- know how to merge branches and understand what that means in terms of combining different modifications +- know how to resolve conflicts, or to abort conflicting merges +- realize that conflicts are generally a good thing since they prevent incorrect merges +- be able to set up a repository on GitHub and connect it with local repository +- push changes to a remote repository +- know a few ways to search through a repository and its history + + +## How to teach this lesson + +### Take first editor steps slowly + +Some participants will be new to using a terminal text editor so please open, +edit, and close the editor (Nano) slowly in first type-along sessions and +exercises to avoid that participants will fall behind the instructor. At one +point a student did not follow the file edits of the instructor, and to correct +the mistake they had to do a manual merge, which they were not ready for. + + +### How to use the exercises + +Most episodes have standard exercises followed by optional (often more advanced) exercises +for more experienced learners so they don't get bored waiting for the newcomers. +The instructor should briefly introduce the exercises and mention that after finishing the +standard exercise (and indicating that using the green sticky) the learners can move on to the +optional ones if they wish. When at least half of the learners have raised the green sticky +the instructor should go through the standard exercise to describe its most important take-home messages. +It's also fine to briefly go though important points from the optional exercises, but don't spend +too much time on it since everyone will not have attempted them. + + +### "Test your understanding" exercises + +Some episodes have a "test your understanding" exercise at the end which is intended as *formative assessment*, +i.e. an activity that provides feedback to instructors and learners on whether learning objectives are being met. +The instructor should end each episode by posing the "test your understanding" multiple-choice question, +giving learners a minute to think about it, and then asking for the right answer or asking learners to raise their +hands to signal which answer they think is correct. + + +### Inspecting history + +Key lesson is *how to find when something is broken or what commit has broken +the code*. + +It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that `git annotate` +and `git show` are available on GitHub and GitLab. + +When discussing `git annotate` and `git bisect` the "when" is more important +than "who". It is not to blame anybody but rather to find out whether published +results are affected. + +Discuss how one would find out this information without version control. + +**Questions to involve participants:** + +- Have you ever found a bug in your code and wondered whether it has affected published results? +- Have you ever wondered when, and by whom, a particular line of code was introduced? +- Have you ever found out that a code behaves differently than it used to but you are not sure when + precisely this changed? + + +**Confusion during `git bisect` exercise:** + +Learners may get stuck in the `git bisect` exercise if they incorrectly assign a commit +as *bad* or *good*. +To leave the bisect mode and return to the commit before `git bisect start` was issued, +one can do +```shell +$ git bisect reset +``` +and start over if needed. + + +### Live better than reading the website material + +It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier. + + +### Log your history in a separate window + +The screencasting (shell window cheatsheet) hints have been moved to +the [presenting +manual](https://coderefinery.github.io/manuals/instructor-tech-setup/). + + +### Create a cheatsheet on the board + +For in-person workshops, create a "cheatsheet" on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven't forgotten anything. Re-create and expand in future git lessons. +One strategy is: + +- a common section for basic commands: `init`, `config`, `clone`, `help`, `stash` +- info commands, can be run anytime: `status`, `log`, `diff`, `graph` +- A section for all the commands that move code from different states: + `add`, `commit`, etc. See the visual cheat sheet below. + +You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it's probably too confusing to use after this course. But, the idea +of commands moving from the "working dir", "staging area", "commits", +etc is good. + +```{figure} img/cheat-sheet.jpg +:alt: Example cheat sheet +:width: 100% + +Example cheat sheet. +``` + +We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to. + + +### Draw a graph on the board + +Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run `git graph`, then do the command, +then look at `git graph` again. + + +### Repeat the following points + +- Always check `git status`, `git diff`, and `git graph` (our alias) before and + after every command until you get used to things. These give you a clear view + into what is going on, the key to knowing what you are doing. Even + after you are used to things... anytime you do something you do + infrequently, it's good to check. + +- `git graph` is a direct representation of what we are drawing on the + board and should constantly be compared to it. + +- Once you `git add` something, it's almost impossible to lose it. + This is used all the time, for example once you commit or even add + it is hard to lose. Commit before you merge or rebase. And so on. + + +### Start from identical environment + +You probably have a highly optimized bash and git environment - one +that is different from students. Move `.gitconfig` and `.bashrc` out +of the way before you start so that your environment is identical to +what students have. diff --git a/branch/2023-version/_sources/index.md.txt b/branch/2023-version/_sources/index.md.txt new file mode 100644 index 00000000..851541d9 --- /dev/null +++ b/branch/2023-version/_sources/index.md.txt @@ -0,0 +1,95 @@ +# Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version + +This is the introductory lesson to version control using +[Git](https://git-scm.com/). It is assumed to be the very first thing +done in a course. + +Our philosophy is that we start from own local repository, branching and +merging (locally), and a brief introduction to pushing to remotes. In +the separate [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/), we teach more use of +remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with +Git to be able to work well. We try to avoid commands which might get +you into a confusing state. + +The goals of the module as a whole are that the user will feel +comfortable about staging changes, committing them, merging, and +branching. + +```{prereq} +- A reasonably recent version of Git (ideal is 2.28 or newer but we + recommend at least 2.23) is installed **and configured** ([installation + instructions](https://coderefinery.github.io/installation/)). But also on older + Git (2.0) the workshop will work and we will offer workarounds for Git below 2.28 + or 2.23. +- For one of the episodes we need a [GitHub](https://github.com) user + account (but alternatives exist, see below). +- Being comfortable with the command line. No expertise is required, but + the lesson will be mostly taken from the command line. For most commands, where reasonable, + we also offer the possibility to participate through the browser. +- To edit files on the local computer, learners should be familiar with + using a **text editor** on their system. If you are new to text editors, + we recommend to start with Nano or VS Code. +``` + +```{toctree} +:maxdepth: 1 +:caption: Core episodes + +motivation +basics +branches +conflicts +remotes +archaeology +level +what-to-avoid +``` + +```{toctree} +:maxdepth: 1 +:caption: Optional episodes + +staging-area +recovering +interrupted +aliases +under-the-hood +``` + +```{toctree} +:maxdepth: 1 +:caption: Reference + +reference +customizing +resources +exercises +guide +``` + +```{toctree} +:maxdepth: 1 +:caption: About + +All lessons +CodeRefinery +Reusing +``` + +```{admonition} Why GitHub? +In this introduction we will mention and use +[GitHub](https://github.com) but also +[GitLab](https://gitlab.com) and +[Bitbucket](https://bitbucket.org) allow similar workflows and +basically everything that we will discuss is transferable. With this +material and these exercises we do not implicitly endorse the company +[GitHub](https://github.com). We have chosen to demonstrate a +number of concepts using examples with +[GitHub](https://github.com) because it is currently the most +popular web platform for hosting Git repositories and the chance is +high that you will interact with +[GitHub](https://github.com)-based repositories even if you choose +to host your Git repository on another platform. +``` diff --git a/branch/2023-version/_sources/interrupted.md.txt b/branch/2023-version/_sources/interrupted.md.txt new file mode 100644 index 00000000..0516cad1 --- /dev/null +++ b/branch/2023-version/_sources/interrupted.md.txt @@ -0,0 +1,106 @@ +# Interrupted work + +```{objectives} +- Learn to switch context or abort work without panicking. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{keypoints} +- There is almost never reason to clone a fresh copy to complete a task that + you have in mind. +``` + + +## Frequent situation: interrupted work + +We all wish that we could write beautiful perfect code. But the real world is +much more chaotic: + +- You are in the middle of a "Jackson-Pollock-style" debugging spree with 27 modified files + and debugging prints everywhere. +- Your colleague comes in and wants you to fix/commit something right now. +- What to do? + +Git provides lots of ways to switch tasks without ruining everything. + + +## Option 1: Stashing + +The **stash** is the first and easiest place to temporarily "stash" +things. + +- `git stash` will put working directory and staging area changes + away. Your code will be same as last commit. +- `git stash pop` will return to the state you were before. Can give it a list. +- `git stash list` will list the current stashes. +- `git stash save NAME` is like the first, but will give it a name. + Useful if it might last a while. +- `git stash save [-p] [filename]` will stash certain files files + and/or by patches. +- `git stash drop` will drop the most recent stash (or whichever stash + you give). +- The stashes form a stack, so you can stash several batches of modifications. + + +(exercise-stashing)= + +### Exercise: Stashing + +````{exercise} Interrupted-1: Stash some uncommitted work +1. Make a change. +2. Check status/diff, stash the change with `git stash`, check status/diff again. +3. Make a separate, unrelated change which doesn't touch the same + lines. Commit this change. +4. Pop off the stash you saved with `git stash pop`, and check status/diff. +5. Optional: Do the same but stash twice. Also check `git stash list`. + Can you pop the stashes in the opposite order? +6. Advanced: What happens if stashes conflict with other changes? Make + a change and stash it. Modify the same line or one right above or + below. Pop the stash back. Resolve the conflict. Note there is no + extra commit. +7. Advanced: what does `git graph` show when you have something + stashed? + +```{solution} +5: Yes you can. With `git stash pop INDEX` you can decie which stash +index to pop. + +6: In this case Git will ask us to resolve the conflict the same way +when resolving conflicts between two branches. + +7: It shows an additional commit hash with `refs/stash`. +``` +```` + + +## Option 2: Create branches + +You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch. + +You basically know how to do this: + +```console +$ git switch --create temporary # create a branch and switch to it +$ git add PATHS # stage changes +$ git commit # commit them +$ git switch main # back to main, continue your work there ... +$ git switch temporary # continue again on "temporary" where you left off +``` + +Later you can merge it to main or rebase it on top of main and resume work. + + +## Storing various junk you don't need but don't want to get rid of + +It happens often that you do something and don't need it, but you don't want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still. diff --git a/branch/2023-version/_sources/level.md.txt b/branch/2023-version/_sources/level.md.txt new file mode 100644 index 00000000..83fdcfee --- /dev/null +++ b/branch/2023-version/_sources/level.md.txt @@ -0,0 +1,73 @@ +# Practical advice: how much Git is necessary? + +```{instructor-note} +- 20 min teaching/discussion +``` + + +## What level of branching complexity is necessary for each project? + + +### Simple personal projects + +- Typically start with just the `main` branch. +- Use branches for unfinished/untested ideas. +- Use branches when you are not sure about a change. +- Use tags to mark important milestones. + + +### Projects with few persons: you accept things breaking sometimes + +- It might be reasonable to commit to the `main` branch and feature branches. + + +### Projects with few persons: changes are reviewed by others + +- You create new feature branches for changes. +- Changes are reviewed before they are merged to the `main` branch + (more about that in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). +- The `main` branch is write-protected and can only be changed with pull requests or merge requests. + + +### When you distribute releases + +- If you want to patch releases, you probably need release branches. +- The `main` branch and release branches are read-only. +- Many [branching models](https://coderefinery.github.io/git-branch-design/05-branching-models/) exist. + +--- + +## How about staging and committing? + +- It is OK to start committing directly by doing `git commit SOMEFILE`. +- Commit early and often: rather create too many commits than too few. + You can always combine commits later. +- Once you commit, it is very, very hard to really lose your code. +- Always fully commit (or stash) before you do dangerous things, so that you know you are safe. + Otherwise it can be hard to recover. +- Later you can start using the staging area. +- Later start using `git add -p` and/or `git commit -p`. + +--- + +## How large should a commit be? + +- Better too small than too large (easier to combine than to split). +- Often I make a commit at the end of the day (this is a unit I would not like to lose). +- Smaller sized commits may be easier to review for others than huge commits. +- Imperfect commits are better than no commits. +- A commit should not contain unrelated changes to simplify review and possible + repair/adjustments/undo later (but again: imperfect commits are better than no commits). + +--- + +```{keypoints} +- There is no one size fits all - start simple and grow your project. +``` + +```{discussion} +How do you [plan to] use Git? + +- Advanced users or beginners, please provide your input in the online collaborative document. +``` + diff --git a/branch/2023-version/_sources/motivation.md.txt b/branch/2023-version/_sources/motivation.md.txt new file mode 100644 index 00000000..df854ef4 --- /dev/null +++ b/branch/2023-version/_sources/motivation.md.txt @@ -0,0 +1,166 @@ +# Motivation + +```{objectives} +- Make sure nobody leaves the workshop without starting to use some form of version control. +- Discuss the reasons why we advocate distributed version control. +``` + +```{instructor-note} +- 15 min teaching/demonstration +``` + + +## Git is all about keeping track of changes + +We will learn how to keep track of changes first in a terminal ([example +repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): + +```{figure} img/git-log-terminal.png +:alt: Screenshot of a git log in terminal +:width: 80% +``` + +Later also via web interface ([example +repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): + +```{figure} img/git-log-github.png +:alt: Screenshot of a git log on GitHub +:width: 80% +:class: with-border +``` + + +## Why do we need to keep track of versions? + +Version control is an answer to these questions (do you recognize some of them?): + +- "It broke ... hopefully I have a working version somewhere?" + +- "Can you please send me the latest version?" + +- "Where is the latest version?" + +- "Which version are you using?" + +- "Which version have the authors used in the paper I am trying to reproduce?" + +- "Found a bug! Since when was it there?" + +- "I am sure it used to work. When did it change?" + +- "My laptop is gone. Is my thesis now gone?" + + +## Features: roll-back, branching, merging, collaboration + +- **Roll-back**: you can always go back to a previous version and compare + +- **Branching and merging**: + - Work on different ideas at the same time + - Different people can work on the same code/project without interfering + - You can experiment with an idea and discard it if it turns out to be a bad idea + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +- **Collaboration**: review, compare, share, discuss + +- [Example network graph](https://github.com/coderefinery/git-intro/network) + + +## Reproducibility + +- How do you indicate which version of your code you have used in your paper? +- When you find a bug, how do you know **when precisely** this bug was introduced + (Are published results affected? Do you need to inform collaborators or users of your code?). + +With version control we can "annotate" code ([browse this example online](https://github.com/networkx/networkx/blame/main/networkx/algorithms/boundary.py)): + +```{figure} img/git-annotate.png +:alt: Example of a git-annotated code with code and history side-by-side +:width: 100% +:class: with-border + +Example of a git-annotated code with code and history side-by-side. +``` + + +## Talking about code + +Which of these two is more practical? +- "Clone the code, go to the file 'src/util.rs', and search for 'time_iso8601'". + Oh! But make sure you use the version from August 2023." +- Or I can send you a [permalink](https://github.com/NordicHPC/sonar/blob/75daafc86582feb06299d6a47c82112f39888152/src/util.rs#L40-L44): + +```{figure} img/code-portion.png +:alt: Screen-shot of a code portion +:width: 100% +:class: with-border + +Permalink that points to a code portion. +``` + + +## What we typically like to snapshot + +- Software (this is how it started but Git/GitHub can track a lot more) +- Scripts +- Documents (plain text files much better suitable than Word documents) +- Manuscripts (Git is great for collaborating/sharing LaTeX or [Quarto](https://quarto.org/) manuscripts) +- Configuration files +- Website sources +- Data + +````{discussion} + In this example somebody tried to keep track of versions without a version + control system tool like Git. Discuss the following directory listing. What + possible problems do you anticipate with this kind of "version control": + ```shell + myproject-2019.zip + myproject-2020-February.zip + myproject-2021-August.zip + myproject-2023-09-19-working.zip + myproject-2023-09-21.zip + myproject-2023-09-21-test.zip + myproject-2023-09-21-myversion.zip + myproject-2023-09-21-newfeature.zip + ... + ``` + + ```{solution} + - Giving a version to a collaborator and merging changes later with own + changes sounds like lots of work. + - What if you discover a bug and want to know since when the bug existed? + ``` +```` + + +## Difficulties of version control + +Despite the benefits, let's be honest, there are some difficulties: + +- One more thing to learn (it's probably worth it and will save you more time in the long run; basic career skill). +- Difficult if your collaborators don't want to use it (in the worst case, you can version control on your side and email them versions). +- Advanced things can be difficult, but basics are often enough (ask others for help when needed). + +--- + +```{discussion} Why Git and not another tool? +- **Easy to set up**: no server needed. +- **Very popular**: chances are high you will need to contribute to somebody else's code which is tracked with Git. +- **Distributed**: good backup, no single point of failure, you can track and + clean-up changes offline, simplifies collaboration model for open-source + projects. +- Important **platforms** such as [GitHub](https://github.com), [GitLab](https://gitlab.com), and [Bitbucket](https://bitbucket.org) + build on top of Git. + +However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +[Subversion](https://subversion.apache.org), +[Mercurial](https://www.mercurial-scm.org), [Pijul](https://pijul.org/), or others. +``` diff --git a/branch/2023-version/_sources/recovering.md.txt b/branch/2023-version/_sources/recovering.md.txt new file mode 100644 index 00000000..3c705f3e --- /dev/null +++ b/branch/2023-version/_sources/recovering.md.txt @@ -0,0 +1,260 @@ +# Undoing and recovering + +```{objectives} +- Learn to undo changes safely +- See when undone changes are permanently deleted and when they can be retrieved +``` + +```{instructor-note} +- 25 min teaching/type-along +- 25 min exercise +``` + +One of the main points of version control is that you can *go back in +time to recover*. Unlike this xkcd comic implies: + +In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn't a "commit" permanent? + +- You can modify old commit history. +- But if you have shared that history already, *modifying it can make + a huge mess*. + +```{admonition} It is almost always possible to recover +As long as you commit something once (or at least `git add` it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru... *until that guru becomes you*. +``` + +```{admonition} Nice resource to visually simulate Git operation +[git-sim](https://github.com/initialcommit-com/git-sim#video-animation-examples) +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command. +``` + +--- + +## Undoing your recent, uncommitted and unstaged changes (preserves history) + +```{note} +In case `git restore` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git restore`. +``` + +You do some work, and want to **undo your uncommitted and unstaged modifications**. +You can always do that with: + +- `git restore .` (the dot means "here and in all folders below") + +You can also undo things selectively: + +- `git restore -p` (decide which portions of changes to undo) or `git restore PATH` (decide which path/file) + +If you have staged changes, you have at least two options to undo the staging: +- `git restore --staged .` followed by `git status` and `git restore .` +- `git reset --hard HEAD` throws away everything that is not in last + commit (`HEAD` - this literal word, this isn't a placeholder) + +--- + +## Reverting commits (preserves history) + +Imagine we made a few commits. +We realize that the latest commit `e02efcd` was a mistake and we wish to undo it: +```console +$ git log --oneline + +e02efcd (HEAD -> main) not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +A safe way to undo the commit is to revert the commit with `git revert`: +```console +$ git revert e02efcd +``` + +This creates a **new commit** that does the opposite of the reverted commit. +The old commit remains in the history: +```console +$ git log --oneline + +d3fc63a (HEAD -> main) Revert "not sure this is a good idea" +e02efcd not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +You can revert any commit, no matter how old it is. It doesn't affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we'll learn about later). + +(exercise-revert)= + +### Exercise: Revert a commit + +```{exercise} Undoing-1: Revert a commit +- Create a commit (commit A). +- Revert the commit with `git revert` (commit B). +- Inspect the history with `git log --oneline`. +- Now try `git show` on both the reverted (commit A) and the newly created commit (commit B). +``` + + +## Adding to the previous commit (modifies history) + +Sometimes we commit but realize we forgot something. +We can amend to the last commit: + +```console +$ git commit --amend +``` + +This can also be used to modify the last commit message. + +Note that this **will change the commit hash**. This command **modifies the history**. +This means that we avoid this command on commits that we have shared with others. + +(exercise-amend)= + +### Exercise: Modify a previous commit + +````{exercise} Undoing-2: Modify a previous commit +1. Make an incomplete change to the recipe or a typo in your change, `git + add` and `git commit` the incomplete/unsatisfactory change. +2. Inspect the unsatisfactory but committed change with `git show`. Remember + or write down the commit hash. +3. Now complete/fix the change but instead of creating a new commit, add the + correction to the previous commit with `git add`, followed by `git commit + --amend`. What changed? + + ```{solution} + One thing that has changed now is the commit hash. Modifying the previous + commit has changed the history. This is OK to do on commits that other people + don't depend on yet. + ``` +```` + + +## Rewinding branches (modifies history) + +You can **reset branch history** to move your branch back to some +point in the past. + +* `git reset --hard HASH` will force a branch label to any other point. All + other changes are lost (but it is possible to recover if you force reset by mistake). +* Be careful if you do this - it can mess stuff up. Use `git graph` a + lot before and after. + + +(exercise-reset)= + +### Exercise: Git reset + +````{exercise} Undoing-3: Destroy our experimentation in this episode + After we have experimented with reverts and amending, let us destroy + all of that and get our repositories to a similar state. + + - First, we will look at our history (`git log`/`git graph`) and + find the last commit `HASH` before our tests. + - Then, we will `git reset --hard HASH` to that. + - Then, `git graph` again to see what happened. + + ```console + $ git log --oneline + + d3fc63a (HEAD -> main) Revert "not sure this is a good idea" + e02efcd not sure this is a good idea + b4af65b improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + + $ git reset --hard b4af65b + + HEAD is now at b4af65b improve the documentation + + $ git log --oneline + + b4af65b (HEAD -> main) improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + ``` +```` + +--- + +## Recovering from committing to the wrong branch + +It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes. + +Here we assume that we made a couple of commits but we realize they went to the +wrong branch. + +**Solution 1 using git cherry-pick**: +1. Make sure that the correct branch exists and if not, create it. Make sure to + create it from the commit hash where you wish you had created it from: `git + branch BRANCHNAME HASH` +2. Switch to the correct branch. +3. `git cherry-pick HASH` can be used to take a specific commit to the + current branch. Cherry-pick all commits that should have gone to the correct + branch, **from oldest to most recent**. +4. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + +**Solution 2 using `git reset --hard`** (makes sense if the correct branch should +contain all commits of the accidentally modified branch): +1. Create the correct branch, pointing at the latest commit: `git branch BRANCHNAME`. +2. Check with `git log` or `git graph` that both branches point to the same, latest, commit. +3. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + + +## Recovering from merging/pulling into the wrong branch + +`git merge`, `git rebase`, and `git pull` modify the **current** branch, never +the other branch. But sometimes we run this command on the wrong branch. + +1. Check with `git log` the commit hash that you would like to rewind the + wrongly modified branch to. +2. Rewind the branch that accidentally got wrong commits with `git reset --hard HASH` (see also above). + + +## Recovering from conflict after pulling changes + +Pulling changes with +`git pull` can create a conflict since `git pull` always also includes a `git merge` (more about this +in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). + +The recovery is same as described in {ref}`conflict-resolution`. Either +resolve conflicts or abort the merge with `git merge --abort`. + +--- + +````{challenge} Undoing-4: Test your understanding + 1. What happens if you accidentally remove a tracked file with `git rm`, is it gone forever? + 2. Is it OK to modify commits that nobody has seen yet? + 3. What situations would justify to modify the Git history and possibly remove commits? + + ```{solution} + 1. It is not gone forever since `git rm` creates a new commit. You can revert the commit to get the file back. + 2. If you haven't shared your commits with anyone it can be alright to modify them. + 3. If you have shared your commits with others (e.g. pushed them to GitHub), only extraordinary + conditions would justify modifying history. For example to remove sensitive or secret information. + ``` +```` diff --git a/branch/2023-version/_sources/reference.md.txt b/branch/2023-version/_sources/reference.md.txt new file mode 100644 index 00000000..b3e3d2e9 --- /dev/null +++ b/branch/2023-version/_sources/reference.md.txt @@ -0,0 +1,64 @@ +# Quick reference + +## Other cheatsheets + +* [Detailed 2-page Git + cheatsheet](https://aaltoscicomp.github.io/cheatsheets/git-the-way-you-need-it-cheatsheet.pdf) +* [Interactive Git cheatsheet](http://www.ndpsoftware.com/git-cheatsheet.html) + + +## Glossary + +* **working directory/ workspace**: the actual files you see and edit +* **staging area**: Place files go after `git add` and before `git + commit` +* **hash**: unique reference of any commit or state +* **branch**: One line of work. Different branches can exist at the + same time and split/merge. +* **HEAD**: Pointer to the most recent commit on the current branch. +* **remote**: Roughly, another server that holds .git. +* **origin**: Default name for a remote repository. +* **master**: Default name for main branch on Git. Depending on the configuration and service, + the default branch is sometimes **main**. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. +* **main**: Default name for main branch on GitLab and GitHub. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. + + +## Commands we use + +Setup: + +* `git config`: edit configuration options +* `git init -b main`: create new repository with `main` as the default branch + +See our status: + +* `git status`: see status of files - use often! +* `git log`: see history of commits and their messages, newest first +* `git graph`: see a detailed graph of commits. Create this command + with `git config --global alias.graph "log --all --graph --decorate --oneline"` +* `git diff`: show difference between working directory and last commit +* `git diff --staged`: show difference between staging area and last commit +* `git show COMMIT`: inspect individual commits + +General work: + +* `git add FILE`: + - Add a new file + - Add a file to staging +* `git commit`: record a version, add it to current branch +* `git commit --amend`: amend our last commit +* `git branch`: show which branch we're on +* `git branch NAME`: create a new branch called "name" +* `git restore FILE`: restore last committed/staged version of FILE, losing unstaged changes +* `git switch --create BRANCH-NAME`: create a new branch and switch to it +* `git revert HASH`: create a new commit which reverts commit HASH +* `git reset --soft HASH`: remove all commits after HASH, but keep their modifications as staged changes +* `git reset --hard HASH`: remove all commits after HASH, permanently throwing away their changes +* `git merge BRANCH-NAME`: merge branch BRANCH-NAME into current branch +* `git grep PATTERN`: search for patterns in tracked files +* `git annotate FILE`: find out when a specific line got introduced and by whom +* `git bisect`: find a commit which broke some functionality diff --git a/branch/2023-version/_sources/remotes.md.txt b/branch/2023-version/_sources/remotes.md.txt new file mode 100644 index 00000000..4143527f --- /dev/null +++ b/branch/2023-version/_sources/remotes.md.txt @@ -0,0 +1,318 @@ +# Sharing repositories online + +```{objectives} +- We get a feeling for remote repositories ([more later](https://coderefinery.github.io/git-collaborative/)). +- We are able to publish a repository on the web. +- We are able to fetch and track a repository from the web. +``` + +```{instructor-note} +- 15 min demonstration/type-along +- 25 min exercise +``` + + +## From our laptops to the web + +We have seen that **creating Git repositories and moving them around is +relatively simple** and that is great. + +So far, if you only worked in the command line, everything was local and all +snapshots, branches, and tags are saved under `.git`. + +If we remove `.git`, we remove all Git history of a project. + +```{discussion} +- What if the hard disk fails? +- What if somebody steals my laptop? +- How can we collaborate with others across the web? +``` + + +## Remotes + +We will learn how to work with remote repositories in detail in the +[collaborative distributed version control](https://coderefinery.github.io/git-collaborative/) lesson. + +In this section we only want to get a taste to prepare us for other lessons +where we will employ GitHub. Our goal is to publish our exercise guacamole recipe +which we prepared in the previous episodes on +the web. Don't worry, you will be able to remove it afterwards. + +````{admonition} If you don't have the recipe repository from previous episodes +Maybe you joined the workshop later or got stuck somewhere? **No problem**! + +**If you don't have the recipe repository from previous episodes**, you can +clone our version of the repository using (please **skip this if you have the recipe +repository on your computer already**): +```console +$ git clone https://github.com/coderefinery/recipe-before-merge.git recipe +$ cd recipe +$ git remote remove origin +``` + +Now you have a repository called `recipe` on your computer with a couple of +commits. Further down we will also clarify what `git clone` does. +```` + +To store your git data on another server, you use **remotes**. +A remote is a repository on its own, with its own branches +We can **push** changes to the remote and **pull** +from the remote. + +You might use remotes to: +- Back up your own work. +- To collaborate with other people. + +There are different types of remotes: +- If you have a server you can ssh to, you can use that as a remote. +- [GitHub](https://github.com) is a popular, closed-source commercial site. +- [GitLab](https://about.gitlab.com) is a popular, open-core + commercial site. Many universities have their own private GitLab servers + set up. +- [Bitbucket](https://bitbucket.org) is yet another popular commercial site. +- Another option is [NotABug](https://notabug.org). +- We also operate a [Nordic + research software repository + platform](https://coderefinery.org/repository/). + This is GitLab, free for researchers and allows private, + cross-university sharing. + +--- + +% This anchor used for linking from other lessons +(clone-method)= + +## Authenticating to GitHub: SSH or HTTPS? + +**How does Github know who you are?** This is hard and there are two +options. + +* **SSH** is the classic method, using Secure Shell remote connection + keys. +* **HTTPS** works with the **Git Credential Manager**, which is an + extra add-on that works easily in Windows and Mac. + +Read how to install them from the [installation +instructions](https://coderefinery.github.io/installation/ssh/). + +Test which one you should use: + +`````{tabs} + ````{group-tab} SSH + Try this command: + ```console + $ ssh -T git@github.com + ``` + + If it returns `Hi USERNAME! You've successfully authenticated, ...`, + then SSH is configured and the following steps will work with the SSH + cloning. + + See our [installation + instructions](https://coderefinery.github.io/installation/ssh/) to + set up SSH access. + + **From now on, if you know that SSH works, you should always select + SSH as the clone URL from GitHub, or translate the URL to start with + the right thing yourself:** `git@github.com:` (with the trailing + `:`). + ```` + ````{group-tab} HTTPS + Try this command: + ```console + $ git config --get credential.helper + ``` + + If this shows something, then the credential manager is probably + configured and HTTPS cloning will work (but you can't verify it until + you try using it). + + From now on, **if you know that HTTPS works, you should always select + HTTPS as the clone URL from Github, or translate the URL to start with + the right thing yourself:** `https://github.com/` + ```` +````` + +If you do not have these configured, please watch as we do this episode and you +can check the [installation +instructions](https://coderefinery.github.io/installation/ssh/) +before the next [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/), where we will need +one of these set up. + +--- + +## Publishing an existing repository from laptop to GitHub + +```{admonition} If you started in the browser and have nothing on your laptop yet +It is possible, that you already have a repository on GitHub if you followed +the examples and exercises in previous episodes in the browser. In this case, +please watch others publish their repository and try to clone your repository +to the laptop using instructions at the bottom of this page. +``` + +First log into GitHub, then follow the screenshots and descriptions below. + +```{figure} img/basics/new-repo-plus.png + :alt: Screenshot on GitHub before a new repository form is opened + :width: 100% + :class: with-border + + Click on the "plus" symbol on top right, then on "New repository". +``` + +Another way to create a new repository is to visit + directly. + +```{figure} img/remotes/new-bare-repo-form.png + :alt: Screenshot on GitHub just before a new repository is created + :width: 100% + :class: with-border + + Choose a repository name, add a short description, but please **do not check** "Add a + README file"**. For "Add .gitignore" and "Choose a license" also leave as "None". Finally "Create repository". +``` + +Once you click the green "Create repository", you will see a page similar to: +```{figure} img/remotes/bare-repo.png + :alt: Screenshot on GitHub after a bare repository was created + :width: 100% + :class: with-border +``` + +What this means is that we have now an empty project with either an HTTPS or an +SSH address: click on the HTTPS and SSH buttons to see what happens. + +We now want to follow the "**... or push an existing repository from the command line**: + +1. Now go to your guacamole repository on your computer. +2. Check that you are in the right place with `git status`. +3. Copy paste the three lines to the terminal and execute those, in my case (**you + need to replace the "USER" part and possibly also the repository name**): + + +`````{tabs} + ````{group-tab} SSH + See above for if SSH is the right option for you. + ```console + $ git remote add origin git@github.com:USER/recipe.git + ``` + ```` + ````{group-tab} HTTPS + See above for if HTTPS is the right option for you. + ```console + $ git remote add origin https://github.com/USER/recipe.git + ``` + ```` +````` + +Then: +```console +$ git branch -M main +$ git push -u origin main +``` + +The meaning of the above lines: +- Add a remote reference with the name "origin" +- Rename current branch to "main" +- Push branch "main" to "origin" + +You should now see: + +```text +Enumerating objects: 3, done. +Counting objects: 100% (3/3), done. +Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done. +Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 +To github.com:USER/recipe.git + * [new branch] main -> main +Branch 'main' set up to track remote branch 'main' from 'origin'. +``` + +**Reload your GitHub project website** and - taa-daa - your commits should now be +online! What just happened? **Think of publishing a repository as uploading +the `.git` part online**. + + +```{admonition} Troubleshooting +**error: remote origin already exists.** +- Explanation: You probably ran a `git remote add origin ...` command, then changed your + mind about HTTPS or SSH and then tried to run the other `git remote add + origin ...` command but "origin" then already exists. +- Recovery: + - First remove "origin" with `git remote remove origin` + - Then run the correct `git remote add origin ...` command + +**remote contains work that you do not have** +- Explanation: You probably clicked on "Add a README file" and now the + repository on GitHub is not empty but contains one commit and locally you + have a different history. Git now prevents you from accidentally overwriting + the history on GitHub. +- Recovery: + - Use `git push --force` instead of `git push`, which will force Git to overwrite the history on GitHub + - Note that this is a powerful but also possibly dangerous option but here it + helps us. If it's a brand new repo, it probably is fine to do this. For real + repositories, don't do this unless you are very sure what is happening. +``` + +--- + +## Cloning a repository from GitHub to laptop + +Now other people can clone this repository and contribute changes. In the +[collaborative distributed version control](https://coderefinery.github.io/git-collaborative/) lesson +we will learn how this works. + +At this point only a brief demo - if you copy the SSH or HTTPS address, you can clone repositories like this +(again adapt the `USER` in the "USER/repository.git" part): + + +`````{tabs} +````{group-tab} SSH +```console +$ git clone git@github.com:USER/recipe.git +``` + +**From now on, if you are using SSH, you should pay attention and make +sure your clone URLs start with `git@github.com:` now and in future +lessons.** +```` +````{group-tab} HTTPS +```console +$ git clone https://github.com/USER/recipe.git +``` + +**From now on, if you are using HTTPS, you should pay attention and make +sure your clone URLs start with `https://github.com/` now and in future +lessons.** +```` +````` + +This creates a directory called "recipe" unless it already exists. You can also specify the target directory +on your computer: + +`````{tabs} +````{group-tab} SSH +```console +$ git clone git@github.com:USER/recipe.git myrecipe +``` +```` +````{group-tab} HTTPS +```console +$ git clone https://github.com/user/recipe.git myrecipe +``` +```` +````` + +What just happened? **Think of cloning as downloading the `.git` part to your +computer**. After downloading the `.git` part, the default branch (the branch pointed to by HEAD) is +automatically checked out. + +```{keypoints} +- A repository can have one or multiple remotes (we will revisit these later). +- Local branches often track remote branches. +- A remote serves as a full backup of your work. +- We'll properly learn how to use these in the + [collaborative distributed version control](https://coderefinery.github.io/git-collaborative/). +``` diff --git a/branch/2023-version/_sources/resources.md.txt b/branch/2023-version/_sources/resources.md.txt new file mode 100644 index 00000000..53899032 --- /dev/null +++ b/branch/2023-version/_sources/resources.md.txt @@ -0,0 +1,12 @@ +# Other resources + +- [Learn Git branching](http://pcottle.github.io/learnGitBranching/) +- [The entire Pro Git book, written by Scott Chacon and Ben Straub](http://git-scm.com/book) +- [Learn git one commit at a time](http://gitready.com) +- [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) +- [Commit Often, Perfect Later, Publish Once: Git Best Practices](http://sethrobertson.github.io/GitBestPractices/) +- [PeepCode Git Internals](https://github.com/pluralsight/git-internals-pdf/releases) +- [Git Workflows for Pros: A Good Git Guide](https://www.toptal.com/git/git-workflows-for-pros-a-good-git-guide) +- [Branch-per-Feature](http://dymitruk.com/blog/2012/02/05/branch-per-feature/) +- [Git on XKCD](http://xkcd.com/1597/) +- [An efficient GIT workflow for mid/long term projects](http://fle.github.io/an-efficient-git-workflow-for-midlong-term-projects.html) diff --git a/branch/2023-version/_sources/staging-area.md.txt b/branch/2023-version/_sources/staging-area.md.txt new file mode 100644 index 00000000..94d0fe83 --- /dev/null +++ b/branch/2023-version/_sources/staging-area.md.txt @@ -0,0 +1,330 @@ +# Using the Git staging area + +```{objectives} +- Learn how to tell a story with your commit history. +- Demystify the Git staging area. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 10 min exercise +``` + + +## Commit history is telling a story + +Your *current code* is very important, but the *history* can be just +as important - it tells a story about how your code came to be. + +- Each individual line of code rarely stands alone. +- You often want to see all the related changes together. +- But you also hardly ever do one thing at once. + +Along with your code, Git creates a *history* for you, and if your +history is clear then you are a long way to organized code. + +````{discussion} + Here are five types of history. What are the advantages and + disadvantages of each, when you look at it later? + + **Example 1**: + ```shell + b135ec8 add features A, B, and C + ``` + + **Example 2** (newest commit is on top): + ```shell + 6f0d49f implement feature C + fee1807 implement feature B + 6fe2f23 implement feature A + ``` + + **Example 3**: + ```shell + ab990f4 saving three months of miscellaneous work I forgot to commit + ``` + + **Example 4** (newest commit is on top): + ```shell + bf39f9d more work on feature B + 45831a5 removing debug prints for feature A and add new file + bddb280 more work on feature B and make feature A compile again + 72d78e7 feature A did not work and started work on feature B + b135ec8 now feature A should work + 72e0211 another fix to make it compile + 61dd3a3 forgot file and bugfix + 49dc419 wip (work in progress) + ``` + + **Example 5** (newest commit is on top): + ```shell + 1949dc4 Work of 2020-04-07 + a361dd3 Work of 2020-04-06 + 1172e02 Work of 2020-04-03 + e772d78 Work of 2020-04-02 + ``` + + Discuss these examples. Can you anticipate problems? +```` + +We want to have nice commits. But we also want to "save often" +(checkpointing) - how can we have both? + +- We will now learn to create nice commits using `git commit --patch` and/or the staging area. +- Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits. +- The staging area isn't the only way to organize your history nicely, some alternatives are discussed at the end of the lesson. + + +## Interactive commits + +- The simplest ways to solve this is to do **interactive commits**: + the `git commit --patch` option (or `git commit -p` for short). +- It will present you with every change you have made individually, + and you can decide which ones to commit right now. +- Reference and key commands + - `git commit --patch` to start the interactive commit + - `y` to use the change + - `n` to skip the change + - `s` (split) if there are several changes grouped together, but + separated by a blank line, split them into separate choices. + - `q` aborts everything. + - `?` for more options. +- The `-p` option is also available on `commit`, `restore`, `checkout`, `reset`, and `add`. + + +(exercise-interactive-commits)= + +## Exercise: Interactive commits + +````{exercise} Staging-1: Perform an interactive commit +One option to help us create nice logical commits is to stage *interactively* +with `git commit --patch`: + +1. Make two changes in `instructions.txt`, at the top and bottom + of the file. + **Make sure that they are separated by at least several unmodified lines.** +2. Run `git commit --patch`. Using the keystrokes above, commit one of + the changes. +3. Do it again for the other change. +4. When you're done, inspect the situation with `git log`, `git status`, `git diff` and `git diff --staged`. +5. When would this be useful? + + ```{solution} + This can be useful if you have several modification in a file (or several + files) but you decide that it would be beneficial to save them as two (or + more) separate commits. + ``` +```` + + +## The staging area + +- The interactive commits above are great, but what if there are so + many changes that you can't sort them out in one shot? +- What if you make progress and want to record it somehow, but it's + not ready to be committed? +- The **staging area** is a place to record things before committing. + +```{instructor-note} +We give two examples and the instructor can pick one or both: +- Analogy using moving boxes +- Analogy using shopping receipts +``` + +```{discussion} + **Analogy using moving boxes** + + - You're moving and you have a box to pack your things in. + - You can put stuff into the box, but you can also take stuff out of the box. + - You wouldn't want to mix items from the bathroom, kitchen, and living room + into the same box. + - The box corresponds to the staging area of Git, where you can craft your commits. + - Committing is like sealing the box and sticking a label on it. + - You wouldn't want to label your box with "stuff", but rather give a more + descriptive label. + - See also + + + **Analogy using shopping receipts** + + - You need to go shopping and buy some stuff for work and for home. + You need two separate receipts. + - Bad idea: go through the store get home stuff, pay, start at the + beginning and go through the store again. This is inefficient and + annoying. + - What you actually do: + - Go through the store and put everything you need in your shopping + basket. + - Get to the check-out. Put your home stuff on the conveyor belt + (`git add`). Check both the belt (`git diff --staged`) and your + basket (`git diff`) to make sure you got all your home stuff. + - Pay (`git commit`) + - Repeat for work stuff. + + In order to keep organized, you have to use multiple locations to + stage things in sequence. +``` + + +## Staging area commands + +The staging area is a middle ground between what you have done to your files +(the **working directory**) and what you have last committed (the **HEAD commit**). +Just like the name implies, it lets you prepare (**stage**) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since **you can modify and stage several times before committing**. + +**git add** stages/prepares for the next commit: +```text + git add + [project*] <------------ project* + ^ + | modify with editor + | + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git commit** creates a new commit: +```text + + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + HEAD~2 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git reset \\--soft HEAD~1** (move HEAD back by one but keep changes and stage +them) would do the opposite of **git commit**. (in this case, `HEAD` +is literally this - not a replacement) + +Going back to the last staged version: +```text + git restore + [project*] ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Unstaging changes with **git restore \\--staged**: +```text + git restore --staged + ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Discarding unstaged changes: +```text + + project* + | + | git restore + v + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Comparing: +```text + git diff + [project*] <-----------> project* + ^ ^ + | git diff --staged | git diff HEAD + v v + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +```{figure} img/staging-basics.svg +:alt: Staging basics +:width: 100% + +The different states of the repository and the commands to move from one to +another. +``` + +(exercise-staging-area)= + +## Exercise: Using the staging area + +```{exercise} Staging-2: Use the staging area to make a commit in two steps +1. In your recipe example, make two different changes to + `ingredients.txt` and `instructions.txt` which do not go together. +2. Use `git add` to stage one of the changes. +3. Use `git status` to see what's going on, and use `git diff` and `git diff --staged` to see the changes. +4. Feel some regret and unstage the staged change. +``` + +```{discussion} +- When is it better to "save" a change as commit, when is it better to "save" + it with `git add`? +- Is it a problem to commit many small changes? +``` + +```{keypoints} +- The staging area helps us to create well-defined commits. +``` diff --git a/branch/2023-version/_sources/under-the-hood.md.txt b/branch/2023-version/_sources/under-the-hood.md.txt new file mode 100644 index 00000000..977968da --- /dev/null +++ b/branch/2023-version/_sources/under-the-hood.md.txt @@ -0,0 +1,185 @@ +# Git under the hood + +```{objectives} +- Verify that branches are pointers to commits and extremely lightweight. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{figure} img/stranger.jpg +:alt: Git under the hood +:width: 100% +``` + + +## Down the rabbit hole + +When working with Git, **you will never need to go inside .git**, but in this +exercise we will, in order to learn about how branches are implemented in Git. + +For this exercise create a new repository and commit a couple of changes. + +Now that we've made a couple of commits let us look at what is happening under +the hood. + +```console +$ cd .git +$ ls -l + +drwxr-xr-x - user 25 Aug 15:51 branches +.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG +.rw-r--r-- 92 user 25 Aug 15:51 config +.rw-r--r-- 73 user 25 Aug 15:51 description +.rw-r--r-- 21 user 25 Aug 15:51 HEAD +drwxr-xr-x - user 25 Aug 15:51 hooks +.rw-r--r-- 137 user 25 Aug 15:52 index +drwxr-xr-x - user 25 Aug 15:51 info +drwxr-xr-x - user 25 Aug 15:52 logs +drwxr-xr-x - user 25 Aug 15:52 objects +drwxr-xr-x - user 25 Aug 15:51 refs +``` + +Git stores everything under the .git folder in your repository. In fact, **the +.git directory is the Git repository.** + +Previously when you wrote the commit messages using your text editor, they +were in fact saved to `COMMIT_EDITMSG`. + +Each commit in Git is stored as a "blob". This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file. + +Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string). + +```{figure} img/commit-and-tree.png +:alt: A commit inside Git +:width: 100% + +States of a Git file. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a [directed acyclic +graph](http://eagain.net/articles/git-for-computer-scientists/) (do not worry +if the term is not familiar). + +```{figure} img/commits-and-parents.png +:alt: A commit and its parents +:width: 100% + +A commit and its parents. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +All branches and tags in Git are pointers to commits. + + +## Git is basically a content-addressed storage system + +- CAS: ["mechanism for storing information that can be retrieved based on its content, not its storage location"](https://en.wikipedia.org/wiki/Content-addressable_storage) +- Content address is the content digest (SHA-1 checksum) +- Stored data does not change - so when we modify commits, we always create new + commits. Git doesn't delete these right away, which is why it is *very hard + to lose data if you commit it once*. + +Let us poke a bit into raw objects! Start with: + +```console +$ git cat-file -p HEAD +``` + +Then explore the `tree` object, then the `file` object, etc. recursively using the hashes you see. + + +## Demonstration: experimenting with branches + +Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an "Aha!" moment and provide us a +good understanding of the underlying model. + +We are starting from the `main` branch and create an `idea` branch: + +```console +$ git status + +On branch main +nothing to commit, working tree clean +``` + +```console +$ git switch --create idea + +Switched to a new branch 'idea' +``` + +```console +$ git branch + +* idea + main +``` + +Now let us go in: + +```console +$ cd .git +$ cd refs/heads +$ ls -l + +.rw-r--r-- 41 user 25 Aug 15:54 idea +.rw-r--r-- 41 user 25 Aug 15:52 main +``` + +Let us check what the `idea` file looks like +(do not worry if the hash is different): +```console +$ cat idea + +045e3db14740c60684d745e5fb891ae71e335611 +``` + +Now let us replicate this file: +```console +$ cp idea idea-2 +$ cp idea idea-3 +$ cp idea idea-4 +$ cp idea idea-5 +``` + +Let us go up two levels and inspect the file `HEAD`: +```console +$ cd ../.. +$ cat HEAD + +ref: refs/heads/idea +``` + +Let us open this file and change it to: +``` +ref: refs/heads/idea-3 +``` + +**Now we are ready for the aha moment!** +First let us go back to the working area: +```console +$ cd .. +``` + +Now - on which branch are we? +```console +$ git branch + + idea + idea-2 +* idea-3 + idea-4 + idea-5 + main +``` + +```{discussion} +Discuss the findings with other course participants. +``` diff --git a/branch/2023-version/_sources/what-to-avoid.md.txt b/branch/2023-version/_sources/what-to-avoid.md.txt new file mode 100644 index 00000000..778d27d0 --- /dev/null +++ b/branch/2023-version/_sources/what-to-avoid.md.txt @@ -0,0 +1,50 @@ +# What to avoid + +The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas. + +**Postponing commits because the changes are "unfinished"/"ugly"**: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all. + +**Not updating your branch before starting new work**: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later. + +**Commit unrelated changes together**: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects. + +**Too ambitious branch which risks to never get completed**: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere. + +**Committing generated files**: See {ref}`gitignore`. + +**Over-engineering the branch layout and safeguards in small projects**: This +may prevent people from contributing (maybe even including yourself?). Add more restrictions and safeguards as +the project and the group of collaborators grows. + +**Commit messages that explain what has been changed but do not explain why it has been +changed**: This is as useful as code comments which describe the "obvious" such +as "this is a loop" instead of explaining why something is done this way. +But don't let perfect commit messages stop you from the most important point, committing often (first point). + +**Commit huge files**: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent `git rm` does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request. + +```{discussion} +Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements. +``` diff --git a/branch/2023-version/_static/_sphinx_javascript_frameworks_compat.js b/branch/2023-version/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/branch/2023-version/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/branch/2023-version/_static/basic.css b/branch/2023-version/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/branch/2023-version/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/branch/2023-version/_static/check-solid.svg b/branch/2023-version/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/branch/2023-version/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/2023-version/_static/clipboard.min.js b/branch/2023-version/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/branch/2023-version/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/branch/2023-version/_static/copybutton.css b/branch/2023-version/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/branch/2023-version/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/branch/2023-version/_static/copybutton.js b/branch/2023-version/_static/copybutton.js new file mode 100644 index 00000000..f3ecd034 --- /dev/null +++ b/branch/2023-version/_static/copybutton.js @@ -0,0 +1,241 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos, .gp'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/branch/2023-version/_static/copybutton_funcs.js b/branch/2023-version/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/branch/2023-version/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/branch/2023-version/_static/css/badge_only.css b/branch/2023-version/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/branch/2023-version/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff b/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff2 b/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff b/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff2 b/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/branch/2023-version/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/fontawesome-webfont.eot b/branch/2023-version/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/branch/2023-version/_static/css/fonts/fontawesome-webfont.svg b/branch/2023-version/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/branch/2023-version/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branch/2023-version/_static/css/fonts/fontawesome-webfont.ttf b/branch/2023-version/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/branch/2023-version/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff b/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff2 b/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/lato-bold-italic.woff b/branch/2023-version/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-bold-italic.woff differ diff --git a/branch/2023-version/_static/css/fonts/lato-bold-italic.woff2 b/branch/2023-version/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/lato-bold.woff b/branch/2023-version/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-bold.woff differ diff --git a/branch/2023-version/_static/css/fonts/lato-bold.woff2 b/branch/2023-version/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-bold.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/lato-normal-italic.woff b/branch/2023-version/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-normal-italic.woff differ diff --git a/branch/2023-version/_static/css/fonts/lato-normal-italic.woff2 b/branch/2023-version/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/branch/2023-version/_static/css/fonts/lato-normal.woff b/branch/2023-version/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-normal.woff differ diff --git a/branch/2023-version/_static/css/fonts/lato-normal.woff2 b/branch/2023-version/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/branch/2023-version/_static/css/fonts/lato-normal.woff2 differ diff --git a/branch/2023-version/_static/css/theme.css b/branch/2023-version/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/branch/2023-version/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/branch/2023-version/_static/doctools.js b/branch/2023-version/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/branch/2023-version/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/branch/2023-version/_static/documentation_options.js b/branch/2023-version/_static/documentation_options.js new file mode 100644 index 00000000..87fc516a --- /dev/null +++ b/branch/2023-version/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/branch/2023-version/_static/file.png b/branch/2023-version/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/branch/2023-version/_static/file.png differ diff --git a/branch/2023-version/_static/jquery.js b/branch/2023-version/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/branch/2023-version/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/2023-version/_static/js/html5shiv.min.js b/branch/2023-version/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/branch/2023-version/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/2023-version/_static/js/theme.js b/branch/2023-version/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/branch/2023-version/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/branch/2023-version/_static/minipres.js b/branch/2023-version/_static/minipres.js new file mode 100644 index 00000000..ad11c871 --- /dev/null +++ b/branch/2023-version/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/branch/2023-version/_static/minus.png b/branch/2023-version/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/branch/2023-version/_static/minus.png differ diff --git a/branch/2023-version/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/branch/2023-version/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 00000000..33566310 --- /dev/null +++ b/branch/2023-version/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/branch/2023-version/_static/plus.png b/branch/2023-version/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/branch/2023-version/_static/plus.png differ diff --git a/branch/2023-version/_static/pygments.css b/branch/2023-version/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/branch/2023-version/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/branch/2023-version/_static/searchtools.js b/branch/2023-version/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/branch/2023-version/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/branch/2023-version/_static/sphinx_highlight.js b/branch/2023-version/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/branch/2023-version/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/branch/2023-version/_static/sphinx_lesson.css b/branch/2023-version/_static/sphinx_lesson.css new file mode 100644 index 00000000..14b20c64 --- /dev/null +++ b/branch/2023-version/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/branch/2023-version/_static/sphinx_rtd_theme_ext_color_contrast.css b/branch/2023-version/_static/sphinx_rtd_theme_ext_color_contrast.css new file mode 100644 index 00000000..e68feb82 --- /dev/null +++ b/branch/2023-version/_static/sphinx_rtd_theme_ext_color_contrast.css @@ -0,0 +1,47 @@ +/* The following are for web accessibility of sphinx_rtd_theme: they + * solve some of the most frequent contrast issues. Remove when this + * solved: + * https://github.com/readthedocs/sphinx_rtd_theme/issues/971 + */ +/* background: #fcfcfc, note boxes #E7F2FA */ +a { color: #2573A7; } /* original #2980B9, #1F5C84; */ +body { color: #242424; } /* original #404040, #383838 */ +.wy-side-nav-search>a, .wy-side-nav-search .wy-dropdown>a { + color: #ffffff; +} /* original #fcfcfc */ +footer { color: #737373; } /* original gray=#808080*/ +footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { + color: #737373; +} /* original gray=#808080*/ +.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { + color: #AB2314; +} +/* Sidebar background */ +.wy-side-nav-search { background-color: #277CB4;} + +/* Same, but for pygments */ +.highlight .ch { color: #3E7A89; } /* #! line */ +.highlight .c1 { color: #3E7A89; } /* also comments */ +.highlight .nv { color: #AD3ECC; } /* variable */ +.highlight .gp { color: #B45608; } /* prompt character, $*/ +.highlight .si { color: #3975B1; } /* ${} variable text */ +.highlight .nc { color: #0C78A7; } + +/* Sphinx admonitions */ +/* warning */ +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { + background: #B15E16; } +/* important */ +.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { + background: #12826C; } +/* seealso, note, etc */ +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { + background: #277CB4; } +/* error, danger */ +.rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { + background: #e31704; +} + +/* Generic admonition titles */ +.wy-alert-title, .rst-content .admonition-title { + background: #277CB4; } diff --git a/branch/2023-version/_static/tabs.css b/branch/2023-version/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/branch/2023-version/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/branch/2023-version/_static/tabs.js b/branch/2023-version/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/branch/2023-version/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/branch/2023-version/_static/term_role_formatting.css b/branch/2023-version/_static/term_role_formatting.css new file mode 100644 index 00000000..0b66095c --- /dev/null +++ b/branch/2023-version/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/branch/2023-version/_static/togglebutton.css b/branch/2023-version/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/branch/2023-version/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/branch/2023-version/_static/togglebutton.js b/branch/2023-version/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/branch/2023-version/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/branch/2023-version/aliases/index.html b/branch/2023-version/aliases/index.html new file mode 100644 index 00000000..0d9da583 --- /dev/null +++ b/branch/2023-version/aliases/index.html @@ -0,0 +1,315 @@ + + + + + + + Aliases and configuration — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Aliases and configuration

+
+

Objectives

+
    +
  • Learn to use aliases for most common commands.

  • +
+
+

Are you getting tired of typing so much? In Git you can define aliases (shortcuts):

+
    +
  • These are great because they can save you time typing.

  • +
  • But it’s easy to forget them, get confused, or be inconsistent with your colleagues.

  • +
+

There is plenty of other configuration for Git, that can make it nicer.

+
+

Aliases

+
    +
  • Aliases offer a way to improve the usability of Git: for +example git ci instead of git commit.

  • +
  • Aliases are based on simple string replacement in the command.

  • +
  • Aliases can either be specific to a repository or global.

    +
      +
    • Global aliases help you do the things you are used to across Git projects.

    • +
    • Per-project aliases can also be created.

    • +
    +
  • +
  • Global aliases are stored in ~/.gitconfig.

  • +
+
+
+

Example alias: git graph

+

A very useful shortcut which we use a lot in our workshops:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ cd your_git_repository
+$ git graph
+
+
+
+
+

Using external commands

+

It is possible to call external commands using the exclamation mark character “!”. +In this example here we create a local alias which is +stored in .git/config and not synchronized with remotes:

+
$ cd your_git_repository
+$ git config alias.hi '!echo hello'
+$ git hi
+
+
+
+

Food for thought: When to alias?

+
    +
  • How many times should you wait before aliasing a command?

  • +
  • Do you believe a list of generic two-letter acronyms for common commands will +save your time?

  • +
+
+
+
+

List of aliases the instructors use

+

You are welcome to reuse, suggest, improve. +You can see your current aliases in ~/.gitconfig.

+
$ git config --global alias.ap "add --patch"
+$ git config --global alias.br branch
+$ git config --global alias.ci "commit -v"
+$ git config --global alias.cip "commit --patch -v"
+$ git config --global alias.cl "clone --recursive"
+$ git config --global alias.di diff
+$ git config --global alias.dic "diff --staged --color-words"
+$ git config --global alias.diw "diff --color-words"
+$ git config --global alias.dis "!git --no-pager diff --stat"
+$ git config --global alias.fe fetch
+$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ git config --global alias.rem remote
+$ git config --global alias.st status
+$ git config --global alias.su "submodule update --init --recursive"
+
+
+

Here is what they do:

+
    +
  • ap: add, selecting parts individually, interactively.

  • +
  • br: branch (obvious)

  • +
  • ci: commit (check in), with -v option for clarity

  • +
  • cip: commit, selecting parts individually, interactively.

  • +
  • cl: clone, init submodules (submodules are an advanced topic)

  • +
  • di: diff (obvious)

  • +
  • dic: diff of staging area vs last commit (what is about to be committed)

  • +
  • diw: a word diff, color. Useful for small changes.

  • +
  • dis: a “diffstat”: what files are changed, not contents

  • +
  • fe: fetch (obvious)

  • +
  • graph: show whole git graph (so useful, some of us call it l)

  • +
  • rem: remote (obvious)

  • +
  • st: status (obvious)

  • +
  • su: submodule update (advanced)

  • +
+

A useful setting for the p aliases:

+
$ git config --global interactive.singlekey true
+
+
+
+
+

Advanced aliases

+

These are advanced aliases and configuration options. We won’t explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages!

+
$ git config --global alias.cif "commit -v -p --fixup"
+$ git config --global alias.rb "rebase --autosquash"
+$ git config --global alias.rbi "rebase --interactive --autosquash"
+$ git config --global alias.rbis "rebase --interactive --autosquash --autostash"
+$ git config --global alias.rbs "rebase --autosquash --autostash"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard"
+$ git config --global alias.new "log HEAD..HEAD@{upstream}"
+$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}"
+$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}"
+$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all"
+$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD"
+$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat"
+
+
+
+
+

Advanced Git configuration

+

Besides aliases, you can do plenty of other configuration of git. +Here are some of the most common ones:

+
$ git config --global interactive.singlekey true
+$ git config --global core.pager "less -RS"
+$ git config --global core.excludesfile ~/.gitignore
+$ git config --global merge.conflictstyle diff3
+$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]"
+$ git config --global diff.mnemonicPrefix true
+
+
+

Do you get tired of typing and copying and pasting your remote names +all the time, like git@github.com:myusername? You can create remote +aliases like this:

+
$ git config --global url.git@github.com:.insteadOf gh:
+$ git config --global url.git@github.com:/username/.insteadOf ghu:
+
+
+

Then, when you add a remote ghu:recipe, it will automatically be +translated to git@github.com:/username/recipe using a simple prefix +matching.

+
+

Keypoints

+
    +
  • If you are frustrated about remembering a command, you should create an alias.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/archaeology/index.html b/branch/2023-version/archaeology/index.html new file mode 100644 index 00000000..00d46b4c --- /dev/null +++ b/branch/2023-version/archaeology/index.html @@ -0,0 +1,518 @@ + + + + + + + Inspecting history — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Inspecting history

+
+

Objectives

+
    +
  • Be able find a line of code, find out why it was introduced and when.

  • +
  • Be able to quickly find the commit that changed a behavior.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 30 min exercise

  • +
+
+
+

Preparation

+

Please make sure that you do not clone repositories inside an already tracked folder:

+
$ git status
+
+
+

If you are inside an existing Git repository, step out of it. +You need to find a different location since we will clone a new repository.

+

If you see this message, this is good in this case:

+
fatal: not a git repository (or any of the parent directories): .git
+
+
+
+
+

Our toolbox for history inspection

+
+

Instructor note

+

First the instructor demonstrates few commands on a real life example +repository https://github.com/networkx/networkx (mentioned in the amazing site The +Programming Historian). +Later we will practice these in an archaeology exercise (below).

+
+
+

Warm-up: “Git History” browser

+

As a warm-up we can try the “Git History” browser +on the README.rst file of the networkx repository:

+ +
+
+

Searching text patterns in the repository

+
+

With git grep you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or some error message printed:

+
$ git grep TEXT
+$ git grep "some text with spaces"
+
+
+

In the networkx repository you can try:

+
$ git clone https://github.com/networkx/networkx
+$ cd networkx
+$ git grep -i fixme
+
+
+

While git grep searches the current state of the repository, +it is also possible to search through all changes with git log -S sometext +which can be useful to find where something got removed.

+
+
+
+

Inspecting individual commits

+
+

We have seen this one before already. Using git show we can inspect an individual commit if +we know its hash:

+
$ git show HASH
+
+
+

For instance:

+
$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7
+
+
+
+
+
+

Line-by-line code annotation with metadata

+

With git annotate you can see line by line who and when the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility.

+
+
$ git annotate FILE
+
+
+

Example:

+
$ git annotate networkx/convert_matrix.py
+
+
+

If you annotate in a terminal and the file is longer than the screen, Git by default uses the program less to +scroll the output. +Use /sometext <ENTER> to find “sometext” and you can cycle through the results with n (next) and N (last). +You can also use page up/down to scroll. You can quit with q.

+
+
+

Discussion

+

Discuss how these relatively trivial changes affect the annotation:

+
    +
  • Wrapping long lines of text/code into shorter lines

  • +
  • Auto-formatting tools such as black

  • +
  • Editors that automatically remove trailing whitespace

  • +
+
+
+
+

Inspecting code in the past

+
+

We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code:

+
$ git switch --create BRANCHNAME HASH
+
+
+

Example (lines starting with “#” are only comments):

+
$ # create branch called "older-code" from hash 347e6292419b
+$ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9
+
+$ # now you can navigate and inspect the code as it was back then
+$ # ...
+
+$ # after we are done we can switch back to "main"
+$ git switch main
+
+$ # if we like we can delete the "older-code" branch
+$ git branch -d older-code
+
+
+

On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

+
$ git checkout -b BRANCHNAME SOMEHASH
+
+
+
+
+
+
+

Exercise: Basic archaeology commands

+
+

History-1: Explore basic archaeology commands

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Clone this repository: +https://github.com/networkx/networkx.git. +Then step into the new directory and create an exercise branch from the networkx-2.6.3 tag/release:

    +
    $ git clone https://github.com/networkx/networkx.git
    +$ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+
+
+
+

Finding out when something broke/changed with git bisect

+
+

“But I am sure it used to work! Strange.”

+
+

Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke.

+
+

How would you solve this?

+

Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now.

+
    +
  • How would you find the commit which changed it?

  • +
  • Why could it be useful to know the commit that changed it?

  • +
+
+

We will probably arrive at a solution which is similar to git bisect:

+
    +
  • First find out a commit in past when it worked.

    +
    $ git bisect start
    +$ git bisect good f0ea950  # this is a commit that worked
    +$ git bisect bad main      # last commit is broken
    +
    +
    +
  • +
  • Now compile and/or run and/or test and decide whether “good” or “bad”.

  • +
  • This is how you can tell Git that this was a working commit:

    +
    $ git bisect good
    +
    +
    +
  • +
  • And this is how you can tell Git that this was not a working commit:

    +
    $ git bisect bad
    +
    +
    +
  • +
  • Then bisect/iterate your way until you find the commit that broke it.

  • +
  • If you want to go back to start, type git bisect reset.

  • +
  • This can even be automatized with git bisect run SCRIPT. +For this you write a script that returns zero/non-zero (success/failure).

  • +
+
+
+

Optional exercise: Git bisect

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+

Keypoints

+
    +
  • git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project.

  • +
  • git switch --create NAME HASH is the recommended mechanism to inspect old code.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/basics/index.html b/branch/2023-version/basics/index.html new file mode 100644 index 00000000..915af9a7 --- /dev/null +++ b/branch/2023-version/basics/index.html @@ -0,0 +1,815 @@ + + + + + + + Basics — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Basics

+
+

Objectives

+
    +
  • Learn to create Git repositories and make commits.

  • +
  • Get a grasp of the structure of a repository.

  • +
  • Learn how to inspect the project history.

  • +
  • Learn how to write useful commit log messages.

  • +
+
+
+

Instructor note

+
    +
  • 35 min teaching/type-along

  • +
  • 40 min exercise

  • +
+
+
+

What is Git, and what is a Git repository?

+
    +
  • Git is a version control system: can record/save snapshots and track the content of a folder as it changes over time.

  • +
  • Every time we commit a snapshot, Git records a snapshot of the entire project, saves it, and assigns it a version.

  • +
  • These snapshots are kept inside a sub-folder called .git.

  • +
  • If we remove .git, we remove the repository and history (but keep the working directory!).

  • +
  • The directory .git uses relative paths - you can move the whole repository somewhere else and it will still work.

  • +
  • Git doesn’t do anything unless you ask it to (it does not record anything automatically).

  • +
  • Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces).

  • +
+
+
+

Recording a snapshot with Git

+
    +
  • Git takes snapshots only if we request it.

  • +
  • We will record changes in two steps (we will later explain why this is a recommended practice).

  • +
  • Example (we don’t need to type yet):

    +
    $ git add FILE.txt
    +$ git commit
    +
    +$ git add FILE.txt ANOTHERFILE.txt
    +$ git commit
    +
    +
    +
  • +
  • We first focus (git add, we “stage” the change), then record (git commit):

  • +
+
+Git staging +
+

Git staging and committing.

+
+
+
+

Question for the more advanced participants

+

What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end.

+
+
+
+

Configuring Git command line

+

Before we start using Git on the command line, we need to configure Git. +This is also part of the +installation instructions +but we need to make sure we all have +set name, email address, editor, and +default branch:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+$ git config --global core.editor nano
+$ git config --global init.defaultBranch main
+
+
+

Verify with:

+
$ git config --list
+
+
+
+

Instructor note

+

Instructors, give learners enough time to do the above configuration steps.

+
+
+
+

Type-along: Tracking a guacamole recipe with Git

+

We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list)

+

The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language.

+
+

Instructor note

+

Instructors, please encourage now that participants type along.

+
+
+

Note

+

It is possible to go through this lesson in the command line or in the browser +(on GitHub).

+
    +
  • We recommend to start with the command line but later to also try in the browser.

  • +
  • If you get really stuck in the command line, try following in the browser and +later you can try to return to the command line.

  • +
+
+
+
+

Creating a repository

+

One of the basic principles of Git is that it is easy to create repositories:

+
+
$ mkdir recipe
+$ cd recipe
+$ git init -b main
+
+
+

That’s it! With git init -b main have now created an empty Git repository +where main is the default branch (more about branches later).

+

We will use git status a lot to check out what is going on:

+
$ git status
+
+On branch main
+
+No commits yet
+
+nothing to commit (create/copy files and use "git add" to track)
+
+
+

We will make sense of this information during this workshop.

+
+
+
+

Adding files and committing changes

+

Let us now create two files.

+

One file is called ingredients.txt and contains:

+
* 2 avocados
+* 1 chili
+* 1 lime
+* 2 tsp salt
+
+
+

The second file is called instructions.txt and contains:

+
* chop avocados
+* chop onion
+* chop chili
+* squeeze lime
+* add salt
+* and mix well
+
+
+
+

As mentioned above, in Git you can always check the status of files in your repository using +git status. It is always a safe command to run and in general a good idea to +do when you are trying to figure out what to do next:

+
$ git status
+
+On branch main
+
+No commits yet
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    ingredients.txt
+    instructions.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+
+

The two files are untracked in the repository (directory). You want to add the files (focus the camera) +to the list of files tracked by Git. Git does not track +any files automatically and you need make a conscious decision to add a file. Let’s do what +Git hints at, and add the files, one by one:

+
$ git add ingredients.txt
+$ git status
+
+On branch main
+
+No commits yet
+
+Changes to be committed:
+  (use "git rm --cached <file>..." to unstage)
+    new file:   ingredients.txt
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    instructions.txt
+
+
+

Now this change is staged and ready to be committed. +Let us now commit the change to the repository:

+
$ git commit -m "adding ingredients"
+
+[main (root-commit) f146d25] adding ingredients
+ 1 file changed, 4 insertions(+)
+ create mode 100644 ingredients.txt
+
+
+

Right after we query the status to get this useful command into our muscle memory:

+
$ git status
+
+
+

Now stage and commit also the other file:

+
$ git add instructions.txt
+$ git commit -m "adding instructions"
+
+
+

We will add a third file to the repository, README.md, containing:

+
# recipe
+
+This is an exercise repository.
+
+
+

Now stage and commit also the README.md file:

+
$ git add README.md
+$ git commit -m "adding README"
+
+
+

What does the -m flag mean? Let us check the help page for that command:

+
$ git help commit
+
+
+

You should see a very long help page as the tool is very versatile (press q to quit). +Do not worry about this now but keep in mind that you can always read the help files +when in doubt. Searching online can also be useful, but choosing search terms +to find relevant information takes some practice and discussions in some +online threads may be confusing. +Note that help pages also work when you don’t have a network connection!

+
+
+
+

Exercise: Record changes

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+
+
+

Git history and log

+
+

If you haven’t yet, please try now git log:

+
$ git log
+
+commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main)
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:47 2023 +0200
+
+    don't forget to enjoy
+
+commit 79161b6e67c62ad4688a58c1e54183334611a390
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:32 2023 +0200
+
+    add half an onion
+
+commit a3394e39535343c4dae3bb4f703741a31aa8b78a
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:47:14 2023 +0200
+
+    adding README
+
+commit 369624674e63de48055a65bf63055bd59c985d22
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:46:58 2023 +0200
+
+    adding instructions
+
+commit f146d25b94569a15e94d7f0da6f15d7554f76c49
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:35:52 2023 +0200
+
+    adding ingredients
+
+
+
+
    +
  • We can browse the development and access each state that we have committed.

  • +
  • The long hashes uniquely label a state of the code.

  • +
  • They are not just integers counting 1, 2, 3, 4, … (why?).

  • +
  • Output is in reverse chronological order, i.e. newest commits on top.

  • +
  • We will use them when comparing versions and when going back in time.

  • +
  • git log --oneline only shows the first 7 characters of the commit hash and is good to get an overview.

  • +
  • If the first characters of the hash are unique it is not necessary to type the entire hash.

  • +
  • git log --stat is nice to show which files have been modified.

  • +
+
+
+

Optional exercises: Comparing changes

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+
+
+

Writing useful commit messages

+

Using git log --oneline or browsing a repository on the web, we better +understand that the first line of the commit message is very important.

+

Good example:

+
increase threshold alpha to 2.0
+
+the motivation for this change is
+to enable ...
+...
+this is based on a discussion in #123
+
+
+

Convention: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

Ignoring files and paths with .gitignore

+
+

Discussion

+
    +
  • Should we add and track all files in a project?

  • +
  • How about generated files?

  • +
  • Why is it considered a bad idea to commit compiled binaries to version control?

  • +
  • What types of generated files do you know?

  • +
+
+

Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files. Example:

+
# ignore compiled python 2 files
+*.pyc
+# ignore compiled python 3 files
+__pycache__
+
+
+

An example taken from the official Git documentation:

+
# ignore objects and archives, anywhere in the tree.
+*.[oa]
+# ignore generated html files,
+*.html
+# except foo.html which is maintained by hand
+!foo.html
+# ignore everything under build directory
+build/
+
+
+
    +
  • .gitignore should be part of the repository because we want to make sure that all developers see the same behavior.

  • +
  • All files should be either tracked or ignored.

  • +
  • .gitignore uses something called a +shell glob syntax for +determining file patterns to ignore. You can read more about the syntax in the +documentation.

  • +
  • You can have .gitignore files in lower level directories and they affect the paths below.

  • +
+
+
+

Graphical user interfaces

+

We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI):

+ +
+
+

Summary

+

Now we know how to save snapshots:

+
$ git add FILE(S)
+$ git commit
+
+
+

And this is what we do as we program.

+

Every state is then saved and later we will learn how to go back to these “checkpoints” +and how to undo things.

+
$ git init -b main  # initialize new repository (main is default branch)
+$ git add           # add files or stage file(s)
+$ git commit        # commit staged file(s)
+$ git status        # see what is going on
+$ git log           # see history
+$ git diff          # show unstaged/uncommitted modifications
+$ git show          # show the change for a specific commit
+$ git mv            # move/rename tracked files
+$ git rm            # remove tracked files
+
+
+

Git is not ideal for large binary files +(for this consider git-annex).

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • It takes only one command to initialize a Git repository: git init -b main.

  • +
  • Commits should be used to tell a story.

  • +
  • Git uses the .git folder to store the snapshots.

  • +
  • Don’t be afraid to stage and commit often. Better too often than not often enough.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/branches/index.html b/branch/2023-version/branches/index.html new file mode 100644 index 00000000..5e00f590 --- /dev/null +++ b/branch/2023-version/branches/index.html @@ -0,0 +1,736 @@ + + + + + + + Branching and merging — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Branching and merging

+
+

Objectives

+
    +
  • Be able to create and merge branches.

  • +
  • Know the difference between a branch and a tag.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Motivation for branches

+

In the previous section we tracked a guacamole recipe with Git.

+

Up until now our repository had only one branch with one commit coming +after the other:

+
+Linear Git repository +
+

Linear Git repository.

+
+
+
    +
  • Commits are depicted here as little boxes with abbreviated hashes.

  • +
  • Here the branch main points to a commit.

  • +
  • “HEAD” is the current position (remember the recording head of tape +recorders?). When we say HEAD, we mean those literal letters - +this isn’t a placeholder for something else.

  • +
  • When we talk about branches, we often mean all parent commits, not only the commit pointed to.

  • +
+

Now we want to do this:

+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+

Software development is often not linear:

+
    +
  • We typically need at least one version of the code to “work” (to compile, to give expected results, …).

  • +
  • At the same time we work on new features, often several features concurrently. +Often they are unfinished.

  • +
  • We need to be able to separate different lines of work really well.

  • +
+

The strength of version control is that it permits the researcher to isolate +different tracks of work, which can later be merged to create a composite +version that contains all changes:

+
+Isolated tracks of work +
+

Isolated tracks of work.

+
+
+
    +
  • We see branching points and merging points.

  • +
  • Main line development is often called main or master.

  • +
  • Other than this convention there is nothing special about main or master, it is a branch like any other.

  • +
  • Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow).

  • +
+

A group of commits that create a single narrative are called a branch. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. “fast sequence extraction” or “Python interface” or “fixing bug in +matrix inversion algorithm”.

+
+

An important alias

+

We will now define an alias in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). This is extensively used in the rest of this +and other lessons:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+
+
+

Instructor note

+

Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative.

+
+

Let us inspect the project history using the git graph alias:

+
$ git graph
+
+* e7cf023 (HEAD -> main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • We have a couple commits and only +one development line (branch) and this branch is called main.

  • +
  • Commits are states characterized by a 40-character hash (checksum).

  • +
  • git graph print abbreviations of these checksums.

  • +
  • Branches are pointers that point to a commit.

  • +
  • Branch main points to a commit (in this example it is e7cf023efe382340e5284c278c6ae2c087dd3ff7 but on your computer +the hash will be different).

  • +
  • HEAD is another pointer, it points to where we are right now (currently main)

  • +
+

In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards.

+
+
+

Creating and working with branches

+
+

Instructor note

+

We do the following part together. Encourage participants to type along.

+
+
+

It is possible to create and merge branches directly on GitHub

+
    +
  • However, we do not have screenshots for that in this episode

  • +
  • But if you prefer to work in the browser, please try it

  • +
  • Please contribute screenshots to this lesson

  • +
+
+

Let’s create a branch called experiment where we add cilantro to ingredients.txt +(text after “#” are comments and not part of the command).

+
$ git branch experiment main  # creates branch "experiment" from "main"
+$ git switch experiment       # switch to branch "experiment"
+$ git branch                  # list all local branches and show on which branch we are
+
+
+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+
    +
  • Verify that you are on the experiment branch (note that git graph also +makes it clear what branch you are on: HEAD -> branchname):

    +
    $ git branch
    +
    +* experiment
    +  main
    +
    +
    +

    This command shows where we are, it does not create a branch.

    +
  • +
  • Then add 2 tbsp cilantro on top of the ingredients.txt:

    +
    * 2 tbsp cilantro
    +* 2 avocados
    +* 1 chili
    +* 1 lime
    +* 2 tsp salt
    +* 1/2 onion
    +
    +
    +
  • +
  • Stage this and commit it with the message “let us try with some cilantro”.

  • +
  • Then reduce the amount of cilantro to 1 tbsp, stage and commit again with “maybe little bit less cilantro”.

  • +
+

We have created two new commits:

+
$ git graph
+
+* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro
+* f6ec7b7 let us try with some cilantro
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • The branch experiment is two commits ahead of main.

  • +
  • We commit our changes to this branch.

  • +
+
+
+

Exercise: Create and commit to branches

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+../_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+../_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+
+
+

Exercise: Merging branches

+

It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge experiment into main.

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+
+

If you got stuck in the above exercises or joined later

+

If you got stuck in the above exercises or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git switch experiment
+$ git switch less-salt
+$ git switch main
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

First we make sure we are on the branch we wish to merge into:

+
$ git branch
+
+  experiment
+  less-salt
+* main
+
+
+

Then we merge experiment into main:

+
$ git merge experiment
+
+
+
+../_images/git-merge-1.svg
+

We can verify the result:

+
$ git graph
+
+*   81fcc0c (HEAD -> main) Merge branch 'experiment'
+|\
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+* | b4af65b improve the documentation
+|/
+| * bf28166 (less-salt) reduce amount of salt
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents.

+

To view the branches that are merged into the current branch we can use the command:

+
$ git branch --merged
+
+  experiment
+* main
+
+
+

We are also happy with the work on the less-salt branch. Let us merge that +one, too, into main:

+
$ git branch  # make sure you are on main
+$ git merge less-salt
+
+
+
+Commit graph after merge
+

Commit graph after merge.

+
+
+

We can verify the result in the terminal:

+
$ git graph
+
+*   4e03d4b (HEAD -> main) Merge branch 'less-salt'
+|\
+| * bf28166 (less-salt) reduce amount of salt
+* |   81fcc0c Merge branch 'experiment'
+|\ \
+| * | bcb8b78 (experiment) maybe little bit less cilantro
+| * | f6ec7b7 let us try with some cilantro
+| |/
+* / b4af65b improve the documentation
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Observe how Git nicely merged the changed amount of salt and the new ingredient in the same file +without us merging it manually:

+
$ cat ingredients.txt
+
+* 1 tbsp cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually settle merge conflicts (we will do that later).

+
+
+

Deleting branches safely

+

Both feature branches are merged:

+
$ git branch --merged
+
+  experiment
+  less-salt
+* main
+
+
+

This means we can delete the branches:

+
$ git branch -d experiment
+$ git branch -d less-salt
+
+
+

This is the result:

+
+Commit graph after merged branches were deleted
+

Commit graph after merged branches were deleted.

+
+
+

We observe that when deleting branches, +only the pointers (“sticky notes”) disappeared, not the commits.

+

Git will not let you delete a branch which has not been reintegrated unless you +insist using git branch -D. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them.

+
+
+

Optional exercises with branches

+

The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section.

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +../_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+
+
+

Tags

+
    +
  • A tag is a pointer to a commit but in contrast to a branch it does not ever +move when creating new commits later.

  • +
  • It can be useful to think of branches as sticky notes and of tags as +commemorative plaques.

  • +
  • We use tags to record particular states or milestones of a project at a given +point in time, like for instance versions (have a look at semantic versioning, +v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a).

  • +
  • There are two basic types of tags: annotated and lightweight.

  • +
  • Use annotated tags since they contain the author and can be cryptographically signed using +GPG, timestamped, and a message attached.

  • +
+

Let’s add an annotated tag to our current state of the guacamole recipe:

+
$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet"
+
+
+

As you may have found out already, git show is a very versatile command. Try this:

+
$ git show nobel-2023
+
+
+

For more information about tags see for example +the Pro Git book chapter on the +subject.

+
+
+
+

Summary

+

Let us pause for a moment and recapitulate what we have just learned:

+
$ git branch               # see where we are
+$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+$ git merge NAME           # merge branch NAME (to current branch)
+$ git branch -d NAME       # delete branch NAME
+$ git branch -D NAME       # delete unmerged branch NAME
+
+
+

Since the following command combo is so frequent:

+
$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+
+
+

There is a shortcut for it:

+
$ git switch --create NAME  # create branch NAME and switch to it
+
+
+
+

Typical workflows

+

With this there are two typical workflows:

+
$ git switch --create new-feature  # create branch, switch to it
+$ git commit                       # work, work, work, ..., and test
+$ git switch main                  # once feature is ready, switch to main
+$ git merge new-feature            # merge work to main
+$ git branch -d new-feature        # remove branch
+
+
+

Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging:

+
$ git switch --create wild-idea    # create branch, switch to it, work, work, work ...
+$ git switch main                  # realize it was a bad idea, back to main
+$ git branch -D wild-idea          # it is gone, off to a new idea
+
+
+
+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • A branch is a division unit of work, to be merged with other units of work.

  • +
  • A tag is a pointer to a moment in the history of a project.

  • +
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/conflicts/index.html b/branch/2023-version/conflicts/index.html new file mode 100644 index 00000000..d5e3ba0e --- /dev/null +++ b/branch/2023-version/conflicts/index.html @@ -0,0 +1,599 @@ + + + + + + + Conflict resolution — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Conflict resolution

+
+

Objectives

+
    +
  • Understand merge conflicts sufficiently well to be able to fix them.

  • +
+
+
+

Instructor note

+
    +
  • 20 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Conflicts in Git and why they are good

+

Imagine we start with the following text file:

+
1 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch A somebody modifies:

+
2 tbsp cilantro
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch B somebody else modifies:

+
1/2 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1 onion
+
+
+

When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro:

+
?????????????????
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1 onion
+
+
+

Git is very good at resolving modifications when merging branches and +in most cases a git merge runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see Optional exercises with branches) without you even noticing.

+

But sometimes the same portion of the code/text is modified on two branches +in two different ways and Git issues a conflict. +Then you need to tell Git which version to keep (resolve it).

+

There are several ways to do that as we will see.

+

Please remember:

+
    +
  • It is good that Git conflicts exist: Git will not silently overwrite one of +two differing modifications.

  • +
  • Conflicts may look scary, but are not that bad after a little bit of +practice. Also they are luckily rare.

  • +
  • Don’t be afraid of Git because of conflicts. You may not meet some conflicts +using other systems because you simply can’t do the kinds of things you do +in Git.

  • +
  • You can take human measures to reduce them.

  • +
+
+
+

The human side of conflicts

+
    +
  • What does it mean if two people do the same thing in two different ways?

  • +
  • What if you work on the same file but do two different things in the different sections?

  • +
  • What if you do something, don’t tell someone from 6 months, and then try to combine it with other people’s work?

  • +
  • How are conflicts avoided in other work? (Only one person working at once? +Declaring what you are doing before you start, if there is any chance someone +else might do the same thing, helps.)

  • +
  • Minor conflicts (two people revise spelling) vs semantic (two people rewrite +a function to add two different new features). How did Git solve these in +branching/merging easily?

  • +
+
+

Now we can go to show how Git controls when there is actually a conflict.

+
+
+

Preparing a conflict

+
+

Instructor note

+

We do the following together as type-along/demo.

+
+
+

If you got stuck previously or joined later

+

If you got stuck previously or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together.

+
    +
  • Create two branches from main: one called like-cilantro, one called dislike-cilantro:

    +
    $ git branch like-cilantro main
    +$ git branch dislike-cilantro main
    +
    +
    +
  • +
  • On the two branches make different modifications to the amount of the same ingredient:

  • +
  • On the branch like-cilantro we have the following change:

    +
    $ git diff main like-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6cacd50 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
  • And on the branch dislike-cilantro we have the following change:

    +
    $ git diff main dislike-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6484462 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 1/2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
+
+
+

Merging conflicting changes

+

What do you expect will happen when we try to merge these two branches into +main?

+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+

The first merge will work:

+
$ git switch main
+$ git status
+$ git merge like-cilantro
+
+Updating 4e03d4b..3caa632
+Fast-forward
+ ingredients.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+
+

But the second will fail:

+
$ git merge dislike-cilantro
+
+Auto-merging ingredients.txt
+CONFLICT (content): Merge conflict in ingredients.txt
+Automatic merge failed; fix conflicts and then commit the result.
+
+
+

Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit:

+
$ git status
+
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+  (use "git merge --abort" to abort the merge)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+	both modified:   ingredients.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+
+
+

Git won’t decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward.

+

Let us inspect the conflicting file:

+
$ cat ingredients.txt
+
+<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

Git inserted resolution markers (the <<<<<<<, >>>>>>>, and =======).

+

Try also git diff:

+
$ git diff
+
+
+
diff --cc ingredients.txt
+index 6cacd50,6484462..0000000
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@@ -1,4 -1,4 +1,10 @@@
+++<<<<<<< HEAD
+ +* 2 tbsp cilantro
+++=======
++ * 1/2 tbsp cilantro
+++>>>>>>> dislike-cilantro
+  * 2 avocados
+  * 1 chili
+  * 1 lime
+
+
+

git diff now only shows the conflicting part, nothing else.

+
+
+

Conflict resolution

+
<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+
+
+

We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged.

+
+

Steps to resolve a conflict

+
    +
  • Check status with git status and git diff.

  • +
  • Decide what you keep (the one, the other, or both or something +else). Edit the file to do this.

    +
      +
    • Remove the resolution markers, if not already done.

    • +
    • The file(s) should now look exactly how you want them.

    • +
    +
  • +
  • Check status with git status and git diff.

  • +
  • Tell Git that you have resolved the conflict with git add ingredients.txt +(if you use the Emacs editor with a certain plugin the editor may stage the +change for you after you have removed the conflict markers).

  • +
  • Verify the result with git status.

  • +
  • Finally commit the merge with only git commit. Everything is pre-filled.

  • +
+
+
+
+

Exercise: Create and resolve a conflict

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+
+
+

Optional exercises with conflict resolution

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+
+

Using “ours” or “theirs” strategy

+
    +
  • Sometimes you know that you want to keep “ours” version (version on the branch you are on) +or “theirs” (version on the merged branch).

  • +
  • Then you do not have to resolve conflicts manually.

  • +
  • See merge strategies.

  • +
+

Example (merge and in doubt take the changes from current branch):

+
$ git merge -s recursive -Xours less-avocados
+
+
+

Or (merge and in doubt take the changes from less-avocados branch):

+
$ git merge -s recursive -Xtheirs less-avocados
+
+
+
+
+
+

Aborting a conflicting merge

+

Sometimes you get a merge conflict but realize that you can’t solve it without +talking to a colleague (who created the other change) first. What to do?

+

You can abort the merge and postponing conflict resolution by resetting the +repository to HEAD (last committed state):

+
$ git merge --abort
+
+
+

The repository looks then exactly as it was before the merge.

+
+
+
+

Avoiding conflicts

+
    +
  • Human measures

    +
      +
    • Think and plan to which branch you will commit to.

    • +
    • Do not put unrelated changes on the same branch.

    • +
    +
  • +
  • Collaboration measures

    +
      +
    • Open an issue and discuss with collaborators before starting a long-living +branch.

    • +
    +
  • +
  • Project layout measures

    +
      +
    • Modifying global data often causes conflicts.

    • +
    • Modular programming reduces this risk.

    • +
    +
  • +
  • Technical measures

    +
      +
    • Share your changes early and often - this is one of the happy, +rare circumstances when everyone doing the selfish thing (e.g. git push as +early as practical) results in best case for everyone!

    • +
    • Pull/rebase often to keep up to date with upstream.

    • +
    • Resolve conflicts early.

    • +
    +
  • +
+
+

Discussion

+

Discuss how Git handles conflicts compared to services like Google Drive.

+
+
+

Keypoints

+
    +
  • Conflicts often appear because of not enough communication or not optimal +branching strategy.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/customizing/index.html b/branch/2023-version/customizing/index.html new file mode 100644 index 00000000..ff6dfcc3 --- /dev/null +++ b/branch/2023-version/customizing/index.html @@ -0,0 +1,185 @@ + + + + + + + Customizing Git — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Customizing Git

+
+

Shell prompt

+
+

Instructor note

+

Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like.

+
+

You can make your shell display contextual information about +your Git state even at all times.

+

Here are few example projects that make this possible and easy:

+ +
+
+

More useful “diff” output

+

Delta is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +“diff” output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/exercises/index.html b/branch/2023-version/exercises/index.html new file mode 100644 index 00000000..7d1f4d2e --- /dev/null +++ b/branch/2023-version/exercises/index.html @@ -0,0 +1,923 @@ + + + + + + + List of exercises — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

List of exercises

+
+

Summary

+

Basics:

+ +

Branching and merging:

+ +

Conflict resolution:

+ +

Inspecting history:

+ +

Using the Git staging area:

+ +

Undoing and recovering:

+ +

Interrupted work:

+ +
+
+

Full list

+

This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests.

+
+

Motivation

+

In motivation.md:

+ +
+
+

Basics

+

In basics.md:

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+

In basics.md:

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+

In basics.md:

+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+

In basics.md:

+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+

In basics.md:

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+
+

Branching and merging

+

In branches.md:

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+../_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+../_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+

In branches.md:

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+

In branches.md:

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +../_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+

In branches.md:

+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+

In branches.md:

+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+
+

Conflict resolution

+

In conflicts.md:

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+

In conflicts.md:

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+

In conflicts.md:

+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+

Inspecting history

+

In archaeology.md:

+
+

History-1: Explore basic archaeology commands

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Clone this repository: +https://github.com/networkx/networkx.git. +Then step into the new directory and create an exercise branch from the networkx-2.6.3 tag/release:

    +
    $ git clone https://github.com/networkx/networkx.git
    +$ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+

In archaeology.md:

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+
+

Using the Git staging area

+

In staging-area.md:

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+

In staging-area.md:

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+
+

Undoing and recovering

+

In recovering.md:

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+

In recovering.md:

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+

In recovering.md:

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+

In recovering.md:

+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+

Interrupted work

+

In interrupted.md:

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/genindex/index.html b/branch/2023-version/genindex/index.html new file mode 100644 index 00000000..fcf37d8f --- /dev/null +++ b/branch/2023-version/genindex/index.html @@ -0,0 +1,155 @@ + + + + + + Index — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branch/2023-version/guide/index.html b/branch/2023-version/guide/index.html new file mode 100644 index 00000000..5e906b98 --- /dev/null +++ b/branch/2023-version/guide/index.html @@ -0,0 +1,430 @@ + + + + + + + Instructor guide — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor guide

+
+

Schedule Day 1

+

Times here are in CE(S)T.

+
    +
  • 08:50 - 09:00 (10 min) Soft start and icebreaker question

  • +
  • 09:00 - 09:20 (20 min) Welcome and practical information

  • +
  • 09:20 - 09:35 (15 min) Motivation

  • +
  • 09:35 - 09:50 (15 min) Basics - configuration and first commits

  • +
  • 09:50 - 10:00 (10 min) Break

  • +
  • 10:00 - 10:20 (20 min) Exercise

    +
      +
    • Record changes

    • +
    • Optional exercises

    • +
    +
  • +
  • 10:20 - 10:40 (20 min) Basics - history, commit log, ignoring

  • +
  • 10:40 - 11:00 (20 min) Exercise

    +
      +
    • One or all optional exercises

    • +
    +
  • +
  • 11:00 - 12:00: Lunch break

  • +
  • 12:00 - 12:15 (15 min) Branching and merging

  • +
  • 12:15 - 12:35 (20 min) Exercise

    +
      +
    • Branch-1

    • +
    • Branch-2

    • +
    +
  • +
  • 12:35 - 12:50 (15 min) Summarize/discuss branching and merging

  • +
  • 12:50 - 13:00 (10 min) Break

  • +
  • 13:00 - 13:20 (20 min) Conflict resolution

  • +
  • 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow?

  • +
+
+
+

Schedule Day 2

+

Times here are in CE(S)T.

+
    +
  • 08:50 - 09:00 (10 min) Soft start and icebreaker question

  • +
  • 09:00 - 09:10 (10 min) Recap and Q&A from day 1

  • +
  • 09:10 - 09:25 (15 min) Sharing repositories online

  • +
  • 09:25 - 09:50 (25 min) Exercise

    +
      +
    • Set up SSH keys

    • +
    • Pushing our guacamole recipe repository to GitHub

    • +
    • Clone repository

    • +
    +
  • +
  • 09:50 - 10:00 (10 min) Break

  • +
  • 10:00 - 10:15 (15 min) Inspecting history

  • +
  • 10:15 - 10:45 (30 min) Exercise

    +
      +
    • History-1

    • +
    • History-2 is optional

    • +
    +
  • +
  • 10:45 - 11:00 (15 min) Summarize/discuss inspecting history

  • +
  • 11:00 - 12:00: Lunch break

  • +
  • 12:00 - 12:15 (15 min) Undoing and recovering

  • +
  • 12:15 - 12:40 (25 min) Exercises

    +
      +
    • Undoing-1

    • +
    • Undoing-2

    • +
    • Undoing-3

    • +
    +
  • +
  • 12:40 - 11:50 (10 min) Summarize undoing and recovering and discussion and mention that staging area exists

  • +
  • 12:50 - 13:00 (10 min) Break

  • +
  • 13:00 - 13:20 (20 min) How much Git is necessary?

  • +
  • 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow?

  • +
+
+
+

Installation reminders for each day

+
    +
  • Day 1: Git configuration

  • +
  • Day 2: SSH set up (if you don’t, sharing repositories online will be demo)

  • +
+
+
+

Why we teach this lesson

+

Everyone should be using a version control system for their work, even if they’re working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories.

+

Specific motivations:

+
    +
  • Code easily becomes a disaster without version control

  • +
  • Mistakes happen - Git offers roll-back functionality and easy backup mechanism

  • +
  • One often needs to work on multiple things in parallel - branches solve that problem

  • +
  • Git enables people to collaborate on code or text without stepping on each other’s toes

  • +
  • Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, +and if bugs are found one can find out exactly when it was introduced

  • +
+

Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices (e.g. how to use the staging area), which is useful for more experienced users.

+
+
+

Intended learning outcomes

+

By the end of this lesson, learners should:

+
    +
  • realize that version control is very important and Git is a valuable tool to learn and use

  • +
  • understand that Git is configurable and know how to set basic configurations

  • +
  • be able to set up Git repositories and make commits

  • +
  • understand that information on commits, branches etc. are stored under .git/, and have a +mental model of how that relates to the working directory

  • +
  • have a mental model of the different states a file can have in Git (untracked, modified, staged, unmodified)

  • +
  • know how to write good commit messages

  • +
  • have an idea of how the staging area can be used to craft good commits

  • +
  • know how to undo commits using git revert and discard changes using git restore

  • +
  • understand that git restore can be dangerous if changes have not been staged

  • +
  • know how to create branches and switch between branches

  • +
  • have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way

  • +
  • know how to merge branches and understand what that means in terms of combining different modifications

  • +
  • know how to resolve conflicts, or to abort conflicting merges

  • +
  • realize that conflicts are generally a good thing since they prevent incorrect merges

  • +
  • be able to set up a repository on GitHub and connect it with local repository

  • +
  • push changes to a remote repository

  • +
  • know a few ways to search through a repository and its history

  • +
+
+
+

How to teach this lesson

+
+

Take first editor steps slowly

+

Some participants will be new to using a terminal text editor so please open, +edit, and close the editor (Nano) slowly in first type-along sessions and +exercises to avoid that participants will fall behind the instructor. At one +point a student did not follow the file edits of the instructor, and to correct +the mistake they had to do a manual merge, which they were not ready for.

+
+
+

How to use the exercises

+

Most episodes have standard exercises followed by optional (often more advanced) exercises +for more experienced learners so they don’t get bored waiting for the newcomers. +The instructor should briefly introduce the exercises and mention that after finishing the +standard exercise (and indicating that using the green sticky) the learners can move on to the +optional ones if they wish. When at least half of the learners have raised the green sticky +the instructor should go through the standard exercise to describe its most important take-home messages. +It’s also fine to briefly go though important points from the optional exercises, but don’t spend +too much time on it since everyone will not have attempted them.

+
+
+

“Test your understanding” exercises

+

Some episodes have a “test your understanding” exercise at the end which is intended as formative assessment, +i.e. an activity that provides feedback to instructors and learners on whether learning objectives are being met. +The instructor should end each episode by posing the “test your understanding” multiple-choice question, +giving learners a minute to think about it, and then asking for the right answer or asking learners to raise their +hands to signal which answer they think is correct.

+
+
+

Inspecting history

+

Key lesson is how to find when something is broken or what commit has broken +the code.

+

It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that git annotate +and git show are available on GitHub and GitLab.

+

When discussing git annotate and git bisect the “when” is more important +than “who”. It is not to blame anybody but rather to find out whether published +results are affected.

+

Discuss how one would find out this information without version control.

+

Questions to involve participants:

+
    +
  • Have you ever found a bug in your code and wondered whether it has affected published results?

  • +
  • Have you ever wondered when, and by whom, a particular line of code was introduced?

  • +
  • Have you ever found out that a code behaves differently than it used to but you are not sure when +precisely this changed?

  • +
+

Confusion during git bisect exercise:

+

Learners may get stuck in the git bisect exercise if they incorrectly assign a commit +as bad or good. +To leave the bisect mode and return to the commit before git bisect start was issued, +one can do

+
$ git bisect reset
+
+
+

and start over if needed.

+
+
+

Live better than reading the website material

+

It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier.

+
+
+

Log your history in a separate window

+

The screencasting (shell window cheatsheet) hints have been moved to +the presenting +manual.

+
+
+

Create a cheatsheet on the board

+

For in-person workshops, create a “cheatsheet” on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven’t forgotten anything. Re-create and expand in future git lessons. +One strategy is:

+
    +
  • a common section for basic commands: init, config, clone, help, stash

  • +
  • info commands, can be run anytime: status, log, diff, graph

  • +
  • A section for all the commands that move code from different states: +add, commit, etc. See the visual cheat sheet below.

  • +
+

You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it’s probably too confusing to use after this course. But, the idea +of commands moving from the “working dir”, “staging area”, “commits”, +etc is good.

+
+Example cheat sheet +
+

Example cheat sheet.

+
+
+

We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to.

+
+
+

Draw a graph on the board

+

Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run git graph, then do the command, +then look at git graph again.

+
+
+

Repeat the following points

+
    +
  • Always check git status, git diff, and git graph (our alias) before and +after every command until you get used to things. These give you a clear view +into what is going on, the key to knowing what you are doing. Even +after you are used to things… anytime you do something you do +infrequently, it’s good to check.

  • +
  • git graph is a direct representation of what we are drawing on the +board and should constantly be compared to it.

  • +
  • Once you git add something, it’s almost impossible to lose it. +This is used all the time, for example once you commit or even add +it is hard to lose. Commit before you merge or rebase. And so on.

  • +
+
+
+

Start from identical environment

+

You probably have a highly optimized bash and git environment - one +that is different from students. Move .gitconfig and .bashrc out +of the way before you start so that your environment is identical to +what students have.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/index.html b/branch/2023-version/index.html new file mode 100644 index 00000000..e4cbe6ea --- /dev/null +++ b/branch/2023-version/index.html @@ -0,0 +1,244 @@ + + + + + + + Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version

+

This is the introductory lesson to version control using +Git. It is assumed to be the very first thing +done in a course.

+

Our philosophy is that we start from own local repository, branching and +merging (locally), and a brief introduction to pushing to remotes. In +the separate collaborative Git +lesson, we teach more use of +remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with +Git to be able to work well. We try to avoid commands which might get +you into a confusing state.

+

The goals of the module as a whole are that the user will feel +comfortable about staging changes, committing them, merging, and +branching.

+
+

Prerequisites

+
    +
  • A reasonably recent version of Git (ideal is 2.28 or newer but we +recommend at least 2.23) is installed and configured (installation +instructions). But also on older +Git (2.0) the workshop will work and we will offer workarounds for Git below 2.28 +or 2.23.

  • +
  • For one of the episodes we need a GitHub user +account (but alternatives exist, see below).

  • +
  • Being comfortable with the command line. No expertise is required, but +the lesson will be mostly taken from the command line. For most commands, where reasonable, +we also offer the possibility to participate through the browser.

  • +
  • To edit files on the local computer, learners should be familiar with +using a text editor on their system. If you are new to text editors, +we recommend to start with Nano or VS Code.

  • +
+
+ + + + +
+

Why GitHub?

+

In this introduction we will mention and use +GitHub but also +GitLab and +Bitbucket allow similar workflows and +basically everything that we will discuss is transferable. With this +material and these exercises we do not implicitly endorse the company +GitHub. We have chosen to demonstrate a +number of concepts using examples with +GitHub because it is currently the most +popular web platform for hosting Git repositories and the chance is +high that you will interact with +GitHub-based repositories even if you choose +to host your Git repository on another platform.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/interrupted/index.html b/branch/2023-version/interrupted/index.html new file mode 100644 index 00000000..2229c9c5 --- /dev/null +++ b/branch/2023-version/interrupted/index.html @@ -0,0 +1,269 @@ + + + + + + + Interrupted work — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interrupted work

+
+

Objectives

+
    +
  • Learn to switch context or abort work without panicking.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+

Keypoints

+
    +
  • There is almost never reason to clone a fresh copy to complete a task that +you have in mind.

  • +
+
+
+

Frequent situation: interrupted work

+

We all wish that we could write beautiful perfect code. But the real world is +much more chaotic:

+
    +
  • You are in the middle of a “Jackson-Pollock-style” debugging spree with 27 modified files +and debugging prints everywhere.

  • +
  • Your colleague comes in and wants you to fix/commit something right now.

  • +
  • What to do?

  • +
+

Git provides lots of ways to switch tasks without ruining everything.

+
+
+

Option 1: Stashing

+

The stash is the first and easiest place to temporarily “stash” +things.

+
    +
  • git stash will put working directory and staging area changes +away. Your code will be same as last commit.

  • +
  • git stash pop will return to the state you were before. Can give it a list.

  • +
  • git stash list will list the current stashes.

  • +
  • git stash save NAME is like the first, but will give it a name. +Useful if it might last a while.

  • +
  • git stash save [-p] [filename] will stash certain files files +and/or by patches.

  • +
  • git stash drop will drop the most recent stash (or whichever stash +you give).

  • +
  • The stashes form a stack, so you can stash several batches of modifications.

  • +
+
+

Exercise: Stashing

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+
+

Option 2: Create branches

+

You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch.

+

You basically know how to do this:

+
$ git switch --create temporary  # create a branch and switch to it
+$ git add PATHS                  # stage changes
+$ git commit                     # commit them
+$ git switch main                # back to main, continue your work there ...
+$ git switch temporary           # continue again on "temporary" where you left off
+
+
+

Later you can merge it to main or rebase it on top of main and resume work.

+
+
+

Storing various junk you don’t need but don’t want to get rid of

+

It happens often that you do something and don’t need it, but you don’t want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/lesson.pdf b/branch/2023-version/lesson.pdf new file mode 100644 index 00000000..083de564 Binary files /dev/null and b/branch/2023-version/lesson.pdf differ diff --git a/branch/2023-version/level/index.html b/branch/2023-version/level/index.html new file mode 100644 index 00000000..2b17d83a --- /dev/null +++ b/branch/2023-version/level/index.html @@ -0,0 +1,249 @@ + + + + + + + Practical advice: how much Git is necessary? — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Practical advice: how much Git is necessary?

+
+

Instructor note

+
    +
  • 20 min teaching/discussion

  • +
+
+
+

What level of branching complexity is necessary for each project?

+
+

Simple personal projects

+
    +
  • Typically start with just the main branch.

  • +
  • Use branches for unfinished/untested ideas.

  • +
  • Use branches when you are not sure about a change.

  • +
  • Use tags to mark important milestones.

  • +
+
+
+

Projects with few persons: you accept things breaking sometimes

+
    +
  • It might be reasonable to commit to the main branch and feature branches.

  • +
+
+
+

Projects with few persons: changes are reviewed by others

+
    +
  • You create new feature branches for changes.

  • +
  • Changes are reviewed before they are merged to the main branch +(more about that in the collaborative Git lesson).

  • +
  • The main branch is write-protected and can only be changed with pull requests or merge requests.

  • +
+
+
+

When you distribute releases

+
    +
  • If you want to patch releases, you probably need release branches.

  • +
  • The main branch and release branches are read-only.

  • +
  • Many branching models exist.

  • +
+
+
+
+
+

How about staging and committing?

+
    +
  • It is OK to start committing directly by doing git commit SOMEFILE.

  • +
  • Commit early and often: rather create too many commits than too few. +You can always combine commits later.

  • +
  • Once you commit, it is very, very hard to really lose your code.

  • +
  • Always fully commit (or stash) before you do dangerous things, so that you know you are safe. +Otherwise it can be hard to recover.

  • +
  • Later you can start using the staging area.

  • +
  • Later start using git add -p and/or git commit -p.

  • +
+
+
+
+

How large should a commit be?

+
    +
  • Better too small than too large (easier to combine than to split).

  • +
  • Often I make a commit at the end of the day (this is a unit I would not like to lose).

  • +
  • Smaller sized commits may be easier to review for others than huge commits.

  • +
  • Imperfect commits are better than no commits.

  • +
  • A commit should not contain unrelated changes to simplify review and possible +repair/adjustments/undo later (but again: imperfect commits are better than no commits).

  • +
+
+
+

Keypoints

+
    +
  • There is no one size fits all - start simple and grow your project.

  • +
+
+
+

Discussion

+

How do you [plan to] use Git?

+
    +
  • Advanced users or beginners, please provide your input in the online collaborative document.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/motivation/index.html b/branch/2023-version/motivation/index.html new file mode 100644 index 00000000..3b3e157a --- /dev/null +++ b/branch/2023-version/motivation/index.html @@ -0,0 +1,323 @@ + + + + + + + Motivation — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Motivation

+
+

Objectives

+
    +
  • Make sure nobody leaves the workshop without starting to use some form of version control.

  • +
  • Discuss the reasons why we advocate distributed version control.

  • +
+
+
+

Instructor note

+
    +
  • 15 min teaching/demonstration

  • +
+
+
+

Git is all about keeping track of changes

+

We will learn how to keep track of changes first in a terminal (example +repository):

+
+Screenshot of a git log in terminal +
+

Later also via web interface (example +repository):

+
+Screenshot of a git log on GitHub +
+
+
+

Why do we need to keep track of versions?

+

Version control is an answer to these questions (do you recognize some of them?):

+
    +
  • “It broke … hopefully I have a working version somewhere?”

  • +
  • “Can you please send me the latest version?”

  • +
  • “Where is the latest version?”

  • +
  • “Which version are you using?”

  • +
  • “Which version have the authors used in the paper I am trying to reproduce?”

  • +
  • “Found a bug! Since when was it there?”

  • +
  • “I am sure it used to work. When did it change?”

  • +
  • “My laptop is gone. Is my thesis now gone?”

  • +
+
+
+

Features: roll-back, branching, merging, collaboration

+
    +
  • Roll-back: you can always go back to a previous version and compare

  • +
  • Branching and merging:

    +
      +
    • Work on different ideas at the same time

    • +
    • Different people can work on the same code/project without interfering

    • +
    • You can experiment with an idea and discard it if it turns out to be a bad idea

    • +
    +
  • +
+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+ +
+
+

Reproducibility

+
    +
  • How do you indicate which version of your code you have used in your paper?

  • +
  • When you find a bug, how do you know when precisely this bug was introduced +(Are published results affected? Do you need to inform collaborators or users of your code?).

  • +
+

With version control we can “annotate” code (browse this example online):

+
+Example of a git-annotated code with code and history side-by-side +
+

Example of a git-annotated code with code and history side-by-side.

+
+
+
+
+

Talking about code

+

Which of these two is more practical?

+
    +
  • “Clone the code, go to the file ‘src/util.rs’, and search for ‘time_iso8601’”. +Oh! But make sure you use the version from August 2023.”

  • +
  • Or I can send you a permalink:

  • +
+
+Screen-shot of a code portion +
+

Permalink that points to a code portion.

+
+
+
+
+

What we typically like to snapshot

+
    +
  • Software (this is how it started but Git/GitHub can track a lot more)

  • +
  • Scripts

  • +
  • Documents (plain text files much better suitable than Word documents)

  • +
  • Manuscripts (Git is great for collaborating/sharing LaTeX or Quarto manuscripts)

  • +
  • Configuration files

  • +
  • Website sources

  • +
  • Data

  • +
+
+

Discussion

+

In this example somebody tried to keep track of versions without a version +control system tool like Git. Discuss the following directory listing. What +possible problems do you anticipate with this kind of “version control”:

+
myproject-2019.zip
+myproject-2020-February.zip
+myproject-2021-August.zip
+myproject-2023-09-19-working.zip
+myproject-2023-09-21.zip
+myproject-2023-09-21-test.zip
+myproject-2023-09-21-myversion.zip
+myproject-2023-09-21-newfeature.zip
+...
+
+
+ +
+
+
+

Difficulties of version control

+

Despite the benefits, let’s be honest, there are some difficulties:

+
    +
  • One more thing to learn (it’s probably worth it and will save you more time in the long run; basic career skill).

  • +
  • Difficult if your collaborators don’t want to use it (in the worst case, you can version control on your side and email them versions).

  • +
  • Advanced things can be difficult, but basics are often enough (ask others for help when needed).

  • +
+
+
+

Why Git and not another tool?

+
    +
  • Easy to set up: no server needed.

  • +
  • Very popular: chances are high you will need to contribute to somebody else’s code which is tracked with Git.

  • +
  • Distributed: good backup, no single point of failure, you can track and +clean-up changes offline, simplifies collaboration model for open-source +projects.

  • +
  • Important platforms such as GitHub, GitLab, and Bitbucket +build on top of Git.

  • +
+

However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +Subversion, +Mercurial, Pijul, or others.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/objects.inv b/branch/2023-version/objects.inv new file mode 100644 index 00000000..bc260a89 Binary files /dev/null and b/branch/2023-version/objects.inv differ diff --git a/branch/2023-version/recovering/index.html b/branch/2023-version/recovering/index.html new file mode 100644 index 00000000..e53d4034 --- /dev/null +++ b/branch/2023-version/recovering/index.html @@ -0,0 +1,428 @@ + + + + + + + Undoing and recovering — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Undoing and recovering

+
+

Objectives

+
    +
  • Learn to undo changes safely

  • +
  • See when undone changes are permanently deleted and when they can be retrieved

  • +
+
+
+

Instructor note

+
    +
  • 25 min teaching/type-along

  • +
  • 25 min exercise

  • +
+
+

One of the main points of version control is that you can go back in +time to recover. Unlike this xkcd comic implies: https://xkcd.com/1597/

+

In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn’t a “commit” permanent?

+
    +
  • You can modify old commit history.

  • +
  • But if you have shared that history already, modifying it can make +a huge mess.

  • +
+
+

It is almost always possible to recover

+

As long as you commit something once (or at least git add it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru… until that guru becomes you.

+
+
+

Nice resource to visually simulate Git operation

+

git-sim +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command.

+
+
+
+

Undoing your recent, uncommitted and unstaged changes (preserves history)

+
+

Note

+

In case git restore does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git restore.

+
+

You do some work, and want to undo your uncommitted and unstaged modifications. +You can always do that with:

+
    +
  • git restore . (the dot means “here and in all folders below”)

  • +
+

You can also undo things selectively:

+
    +
  • git restore -p (decide which portions of changes to undo) or git restore PATH (decide which path/file)

  • +
+

If you have staged changes, you have at least two options to undo the staging:

+
    +
  • git restore --staged . followed by git status and git restore .

  • +
  • git reset --hard HEAD throws away everything that is not in last +commit (HEAD - this literal word, this isn’t a placeholder)

  • +
+
+
+
+

Reverting commits (preserves history)

+

Imagine we made a few commits. +We realize that the latest commit e02efcd was a mistake and we wish to undo it:

+
$ git log --oneline
+
+e02efcd (HEAD -> main) not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

A safe way to undo the commit is to revert the commit with git revert:

+
$ git revert e02efcd
+
+
+

This creates a new commit that does the opposite of the reverted commit. +The old commit remains in the history:

+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

You can revert any commit, no matter how old it is. It doesn’t affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we’ll learn about later).

+
+

Exercise: Revert a commit

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+
+
+
+

Adding to the previous commit (modifies history)

+

Sometimes we commit but realize we forgot something. +We can amend to the last commit:

+
$ git commit --amend
+
+
+

This can also be used to modify the last commit message.

+

Note that this will change the commit hash. This command modifies the history. +This means that we avoid this command on commits that we have shared with others.

+
+

Exercise: Modify a previous commit

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+
+
+
+

Rewinding branches (modifies history)

+

You can reset branch history to move your branch back to some +point in the past.

+
    +
  • git reset --hard HASH will force a branch label to any other point. All +other changes are lost (but it is possible to recover if you force reset by mistake).

  • +
  • Be careful if you do this - it can mess stuff up. Use git graph a +lot before and after.

  • +
+
+

Exercise: Git reset

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+
+
+
+
+

Recovering from committing to the wrong branch

+

It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes.

+

Here we assume that we made a couple of commits but we realize they went to the +wrong branch.

+

Solution 1 using git cherry-pick:

+
    +
  1. Make sure that the correct branch exists and if not, create it. Make sure to +create it from the commit hash where you wish you had created it from: git branch BRANCHNAME HASH

  2. +
  3. Switch to the correct branch.

  4. +
  5. git cherry-pick HASH can be used to take a specific commit to the +current branch. Cherry-pick all commits that should have gone to the correct +branch, from oldest to most recent.

  6. +
  7. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  8. +
+

Solution 2 using git reset --hard (makes sense if the correct branch should +contain all commits of the accidentally modified branch):

+
    +
  1. Create the correct branch, pointing at the latest commit: git branch BRANCHNAME.

  2. +
  3. Check with git log or git graph that both branches point to the same, latest, commit.

  4. +
  5. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  6. +
+
+
+

Recovering from merging/pulling into the wrong branch

+

git merge, git rebase, and git pull modify the current branch, never +the other branch. But sometimes we run this command on the wrong branch.

+
    +
  1. Check with git log the commit hash that you would like to rewind the +wrongly modified branch to.

  2. +
  3. Rewind the branch that accidentally got wrong commits with git reset --hard HASH (see also above).

  4. +
+
+
+

Recovering from conflict after pulling changes

+

Pulling changes with +git pull can create a conflict since git pull always also includes a git merge (more about this +in the collaborative Git lesson).

+

The recovery is same as described in Conflict resolution. Either +resolve conflicts or abort the merge with git merge --abort.

+
+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/reference/index.html b/branch/2023-version/reference/index.html new file mode 100644 index 00000000..b91a6c28 --- /dev/null +++ b/branch/2023-version/reference/index.html @@ -0,0 +1,230 @@ + + + + + + + Quick reference — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Quick reference

+
+

Other cheatsheets

+ +
+
+

Glossary

+
    +
  • working directory/ workspace: the actual files you see and edit

  • +
  • staging area: Place files go after git add and before git commit

  • +
  • hash: unique reference of any commit or state

  • +
  • branch: One line of work. Different branches can exist at the +same time and split/merge.

  • +
  • HEAD: Pointer to the most recent commit on the current branch.

  • +
  • remote: Roughly, another server that holds .git.

  • +
  • origin: Default name for a remote repository.

  • +
  • master: Default name for main branch on Git. Depending on the configuration and service, +the default branch is sometimes main. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

  • +
  • main: Default name for main branch on GitLab and GitHub. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

  • +
+
+
+

Commands we use

+

Setup:

+
    +
  • git config: edit configuration options

  • +
  • git init -b main: create new repository with main as the default branch

  • +
+

See our status:

+
    +
  • git status: see status of files - use often!

  • +
  • git log: see history of commits and their messages, newest first

  • +
  • git graph: see a detailed graph of commits. Create this command +with git config --global alias.graph "log --all --graph --decorate --oneline"

  • +
  • git diff: show difference between working directory and last commit

  • +
  • git diff --staged: show difference between staging area and last commit

  • +
  • git show COMMIT: inspect individual commits

  • +
+

General work:

+
    +
  • git add FILE:

    +
      +
    • Add a new file

    • +
    • Add a file to staging

    • +
    +
  • +
  • git commit: record a version, add it to current branch

  • +
  • git commit --amend: amend our last commit

  • +
  • git branch: show which branch we’re on

  • +
  • git branch NAME: create a new branch called “name”

  • +
  • git restore FILE: restore last committed/staged version of FILE, losing unstaged changes

  • +
  • git switch --create BRANCH-NAME: create a new branch and switch to it

  • +
  • git revert HASH: create a new commit which reverts commit HASH

  • +
  • git reset --soft HASH: remove all commits after HASH, but keep their modifications as staged changes

  • +
  • git reset --hard HASH: remove all commits after HASH, permanently throwing away their changes

  • +
  • git merge BRANCH-NAME: merge branch BRANCH-NAME into current branch

  • +
  • git grep PATTERN: search for patterns in tracked files

  • +
  • git annotate FILE: find out when a specific line got introduced and by whom

  • +
  • git bisect: find a commit which broke some functionality

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/remotes/index.html b/branch/2023-version/remotes/index.html new file mode 100644 index 00000000..1e0e9828 --- /dev/null +++ b/branch/2023-version/remotes/index.html @@ -0,0 +1,439 @@ + + + + + + + Sharing repositories online — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Sharing repositories online

+
+

Objectives

+
    +
  • We get a feeling for remote repositories (more later).

  • +
  • We are able to publish a repository on the web.

  • +
  • We are able to fetch and track a repository from the web.

  • +
+
+
+

Instructor note

+
    +
  • 15 min demonstration/type-along

  • +
  • 25 min exercise

  • +
+
+
+

From our laptops to the web

+

We have seen that creating Git repositories and moving them around is +relatively simple and that is great.

+

So far, if you only worked in the command line, everything was local and all +snapshots, branches, and tags are saved under .git.

+

If we remove .git, we remove all Git history of a project.

+
+

Discussion

+
    +
  • What if the hard disk fails?

  • +
  • What if somebody steals my laptop?

  • +
  • How can we collaborate with others across the web?

  • +
+
+
+
+

Remotes

+

We will learn how to work with remote repositories in detail in the +collaborative distributed version control lesson.

+

In this section we only want to get a taste to prepare us for other lessons +where we will employ GitHub. Our goal is to publish our exercise guacamole recipe +which we prepared in the previous episodes on +the web. Don’t worry, you will be able to remove it afterwards.

+
+

If you don’t have the recipe repository from previous episodes

+

Maybe you joined the workshop later or got stuck somewhere? No problem!

+

If you don’t have the recipe repository from previous episodes, you can +clone our version of the repository using (please skip this if you have the recipe +repository on your computer already):

+
$ git clone https://github.com/coderefinery/recipe-before-merge.git recipe
+$ cd recipe
+$ git remote remove origin
+
+
+

Now you have a repository called recipe on your computer with a couple of +commits. Further down we will also clarify what git clone does.

+
+

To store your git data on another server, you use remotes. +A remote is a repository on its own, with its own branches +We can push changes to the remote and pull +from the remote.

+

You might use remotes to:

+
    +
  • Back up your own work.

  • +
  • To collaborate with other people.

  • +
+

There are different types of remotes:

+
    +
  • If you have a server you can ssh to, you can use that as a remote.

  • +
  • GitHub is a popular, closed-source commercial site.

  • +
  • GitLab is a popular, open-core +commercial site. Many universities have their own private GitLab servers +set up.

  • +
  • Bitbucket is yet another popular commercial site.

  • +
  • Another option is NotABug.

  • +
  • We also operate a Nordic +research software repository +platform. +This is GitLab, free for researchers and allows private, +cross-university sharing.

  • +
+
+
+
+

Authenticating to GitHub: SSH or HTTPS?

+

How does Github know who you are? This is hard and there are two +options.

+
    +
  • SSH is the classic method, using Secure Shell remote connection +keys.

  • +
  • HTTPS works with the Git Credential Manager, which is an +extra add-on that works easily in Windows and Mac.

  • +
+

Read how to install them from the installation +instructions.

+

Test which one you should use:

+
+

Try this command:

+
$ ssh -T git@github.com
+
+
+

If it returns Hi USERNAME! You've successfully authenticated, ..., +then SSH is configured and the following steps will work with the SSH +cloning.

+

See our installation +instructions to +set up SSH access.

+

From now on, if you know that SSH works, you should always select +SSH as the clone URL from GitHub, or translate the URL to start with +the right thing yourself: git@github.com: (with the trailing +:).

+
+

If you do not have these configured, please watch as we do this episode and you +can check the installation +instructions +before the next collaborative Git +lesson, where we will need +one of these set up.

+
+
+
+

Publishing an existing repository from laptop to GitHub

+
+

If you started in the browser and have nothing on your laptop yet

+

It is possible, that you already have a repository on GitHub if you followed +the examples and exercises in previous episodes in the browser. In this case, +please watch others publish their repository and try to clone your repository +to the laptop using instructions at the bottom of this page.

+
+

First log into GitHub, then follow the screenshots and descriptions below.

+
+Screenshot on GitHub before a new repository form is opened +
+

Click on the “plus” symbol on top right, then on “New repository”.

+
+
+

Another way to create a new repository is to visit +https://github.com/new directly.

+
+Screenshot on GitHub just before a new repository is created +
+

Choose a repository name, add a short description, but please do not check “Add a +README file”**. For “Add .gitignore” and “Choose a license” also leave as “None”. Finally “Create repository”.

+
+
+

Once you click the green “Create repository”, you will see a page similar to:

+
+Screenshot on GitHub after a bare repository was created +
+

What this means is that we have now an empty project with either an HTTPS or an +SSH address: click on the HTTPS and SSH buttons to see what happens.

+

We now want to follow the “… or push an existing repository from the command line:

+
    +
  1. Now go to your guacamole repository on your computer.

  2. +
  3. Check that you are in the right place with git status.

  4. +
  5. Copy paste the three lines to the terminal and execute those, in my case (you +need to replace the “USER” part and possibly also the repository name):

  6. +
+
+

See above for if SSH is the right option for you.

+
$ git remote add origin git@github.com:USER/recipe.git
+
+
+
+

Then:

+
$ git branch -M main
+$ git push -u origin main
+
+
+

The meaning of the above lines:

+
    +
  • Add a remote reference with the name “origin”

  • +
  • Rename current branch to “main”

  • +
  • Push branch “main” to “origin”

  • +
+

You should now see:

+
Enumerating objects: 3, done.
+Counting objects: 100% (3/3), done.
+Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
+Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
+To github.com:USER/recipe.git
+ * [new branch]      main -> main
+Branch 'main' set up to track remote branch 'main' from 'origin'.
+
+
+

Reload your GitHub project website and - taa-daa - your commits should now be +online! What just happened? Think of publishing a repository as uploading +the .git part online.

+
+

Troubleshooting

+

error: remote origin already exists.

+
    +
  • Explanation: You probably ran a git remote add origin ... command, then changed your +mind about HTTPS or SSH and then tried to run the other git remote add origin ... command but “origin” then already exists.

  • +
  • Recovery:

    +
      +
    • First remove “origin” with git remote remove origin

    • +
    • Then run the correct git remote add origin ... command

    • +
    +
  • +
+

remote contains work that you do not have

+
    +
  • Explanation: You probably clicked on “Add a README file” and now the +repository on GitHub is not empty but contains one commit and locally you +have a different history. Git now prevents you from accidentally overwriting +the history on GitHub.

  • +
  • Recovery:

    +
      +
    • Use git push --force instead of git push, which will force Git to overwrite the history on GitHub

    • +
    • Note that this is a powerful but also possibly dangerous option but here it +helps us. If it’s a brand new repo, it probably is fine to do this. For real +repositories, don’t do this unless you are very sure what is happening.

    • +
    +
  • +
+
+
+
+
+

Cloning a repository from GitHub to laptop

+

Now other people can clone this repository and contribute changes. In the +collaborative distributed version control lesson +we will learn how this works.

+

At this point only a brief demo - if you copy the SSH or HTTPS address, you can clone repositories like this +(again adapt the USER in the “USER/repository.git” part):

+
+
$ git clone git@github.com:USER/recipe.git
+
+
+

From now on, if you are using SSH, you should pay attention and make +sure your clone URLs start with git@github.com: now and in future +lessons.

+
+

This creates a directory called “recipe” unless it already exists. You can also specify the target directory +on your computer:

+
+
$ git clone git@github.com:USER/recipe.git myrecipe
+
+
+
+

What just happened? Think of cloning as downloading the .git part to your +computer. After downloading the .git part, the default branch (the branch pointed to by HEAD) is +automatically checked out.

+
+

Keypoints

+
    +
  • A repository can have one or multiple remotes (we will revisit these later).

  • +
  • Local branches often track remote branches.

  • +
  • A remote serves as a full backup of your work.

  • +
  • We’ll properly learn how to use these in the +collaborative distributed version control.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/resources/index.html b/branch/2023-version/resources/index.html new file mode 100644 index 00000000..0eee650e --- /dev/null +++ b/branch/2023-version/resources/index.html @@ -0,0 +1,169 @@ + + + + + + + Other resources — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branch/2023-version/search/index.html b/branch/2023-version/search/index.html new file mode 100644 index 00000000..afb62b02 --- /dev/null +++ b/branch/2023-version/search/index.html @@ -0,0 +1,169 @@ + + + + + + Search — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/branch/2023-version/searchindex.js b/branch/2023-version/searchindex.js new file mode 100644 index 00000000..184e25b5 --- /dev/null +++ b/branch/2023-version/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["aliases", "archaeology", "basics", "branches", "conflicts", "customizing", "exercises", "guide", "index", "interrupted", "level", "motivation", "recovering", "reference", "remotes", "resources", "staging-area", "under-the-hood", "what-to-avoid"], "filenames": ["aliases.md", "archaeology.md", "basics.md", "branches.md", "conflicts.md", "customizing.md", "exercises.md", "guide.md", "index.md", "interrupted.md", "level.md", "motivation.md", "recovering.md", "reference.md", "remotes.md", "resources.md", "staging-area.md", "under-the-hood.md", "what-to-avoid.md"], "titles": ["Aliases and configuration", "Inspecting history", "Basics", "Branching and merging", "Conflict resolution", "Customizing Git", "List of exercises", "Instructor guide", "Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version", "Interrupted work", "Practical advice: how much Git is necessary?", "Motivation", "Undoing and recovering", "Quick reference", "Sharing repositories online", "Other resources", "Using the Git staging area", "Git under the hood", "What to avoid"], "terms": {"learn": [0, 2, 3, 9, 11, 12, 14, 15, 16, 17], "most": [0, 4, 7, 8, 9, 12, 13, 16, 18], "common": [0, 7, 12, 18], "ar": [0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 18], "you": [0, 2, 5, 6, 7, 8, 11, 12, 13, 16, 17, 18], "get": [0, 2, 4, 6, 7, 8, 12, 14, 16, 18], "tire": 0, "type": [0, 1, 3, 4, 6, 7, 9, 12, 14, 16, 17], "so": [0, 1, 2, 3, 6, 7, 9, 10, 13, 14, 16, 17, 18], "much": [0, 5, 7, 8, 9, 11], "In": [0, 1, 2, 3, 4, 6, 8, 9, 11, 12, 13, 14, 16, 17, 18], "can": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 16, 17, 18], "defin": [0, 3, 16], "shortcut": [0, 3], "These": [0, 2, 7], "great": [0, 2, 11, 14, 16], "becaus": [0, 2, 4, 8, 9, 18], "thei": [0, 2, 3, 6, 7, 10, 12, 16, 17], "save": [0, 2, 6, 9, 11, 14, 16, 17], "time": [0, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 17], "But": [0, 1, 2, 3, 4, 7, 8, 9, 11, 12, 16, 18], "": [0, 1, 2, 3, 4, 6, 7, 11, 14, 16], "easi": [0, 2, 5, 7, 11, 12], "forget": [0, 2, 3, 6, 12], "them": [0, 2, 3, 4, 6, 7, 8, 9, 11, 12, 14, 16], "confus": [0, 2, 3, 7, 8], "inconsist": 0, "your": [0, 1, 4, 5, 8, 9, 10, 11, 16, 17, 18], "colleagu": [0, 4, 9], "There": [0, 2, 3, 4, 6, 7, 9, 10, 14], "i": [0, 1, 4, 5, 6, 7, 8, 9, 13, 14, 18], "plenti": 0, "other": [0, 2, 3, 4, 6, 7, 8, 9, 11, 12, 14, 16, 17], "make": [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 18], "nicer": 0, "offer": [0, 7, 8], "wai": [0, 1, 2, 3, 4, 6, 7, 9, 12, 14, 16, 18], "improv": [0, 2, 3, 5, 6, 12, 18], "usabl": 0, "ci": 0, "instead": [0, 1, 2, 4, 12, 14, 18], "commit": [0, 4, 7, 8, 9, 13, 14, 15, 17, 18], "base": [0, 2, 8, 17], "simpl": [0, 7, 8, 14], "string": [0, 1, 17], "replac": [0, 2, 14, 16], "either": [0, 2, 6, 9, 12, 14], "specif": [0, 1, 2, 6, 7, 12, 13], "repositori": [0, 3, 4, 6, 7, 8, 9, 11, 12, 13, 16, 17, 18], "global": [0, 2, 3, 4, 6, 13], "help": [0, 2, 4, 6, 7, 11, 14, 16, 18], "do": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 14, 16, 17, 18], "thing": [0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 14, 16, 18], "across": [0, 14], "project": [0, 1, 2, 3, 4, 5, 7, 11, 14, 15, 16, 18], "per": [0, 15], "also": [0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 14, 16, 17, 18], "creat": [0, 1, 10, 11, 12, 13, 14, 16, 17], "store": [0, 2, 6, 7, 14, 16, 17], "gitconfig": [0, 7], "A": [0, 2, 3, 4, 6, 7, 8, 10, 12, 14, 15, 16, 17], "veri": [0, 2, 3, 4, 7, 8, 10, 11, 14, 16, 17], "which": [0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18], "we": [0, 1, 2, 3, 4, 6, 9, 12, 14, 16, 17, 18], "lot": [0, 2, 6, 9, 11, 12, 18], "our": [0, 2, 3, 7, 8, 13], "workshop": [0, 2, 7, 8, 11, 14], "config": [0, 2, 3, 4, 6, 7, 13, 14, 17], "log": [0, 1, 3, 6, 12, 13, 14, 16, 17], "all": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 16, 17, 18], "decor": [0, 3, 13], "onelin": [0, 1, 2, 3, 6, 12, 13], "cd": [0, 1, 2, 3, 4, 6, 14, 17], "your_git_repositori": 0, "It": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 14, 16, 18], "possibl": [0, 1, 2, 5, 6, 8, 10, 11, 14], "call": [0, 1, 2, 3, 4, 6, 13, 14], "exclam": 0, "mark": [0, 4, 10], "charact": [0, 2, 3, 17], "thi": [0, 2, 3, 4, 5, 8, 9, 10, 11, 13, 14, 16, 17, 18], "here": [0, 1, 2, 3, 5, 6, 7, 12, 14, 16], "local": [0, 2, 3, 6, 7, 8, 12, 14], "synchron": 0, "remot": [0, 3, 4, 7, 8, 13], "hi": [0, 14], "echo": 0, "hello": 0, "how": [0, 2, 3, 4, 5, 6, 9, 11, 12, 14, 16, 17], "mani": [0, 2, 7, 10, 14, 16, 18], "should": [0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 16, 18], "wait": [0, 7, 18], "befor": [0, 1, 2, 3, 4, 6, 7, 9, 10, 12, 13, 14, 16, 18], "believ": 0, "gener": [0, 2, 6, 7, 13, 18], "two": [0, 2, 3, 4, 9, 11, 12, 14, 17], "letter": [0, 3], "acronym": 0, "welcom": [0, 7], "reus": [0, 8, 14], "suggest": [0, 2], "see": [0, 1, 2, 3, 4, 6, 7, 8, 12, 13, 14, 16, 17, 18], "current": [0, 1, 3, 4, 6, 8, 9, 12, 13, 14, 16], "ap": 0, "add": [0, 2, 3, 4, 6, 7, 9, 10, 12, 13, 14, 16, 18], "patch": [0, 6, 9, 10, 16], "br": 0, "branch": [0, 1, 2, 7, 8, 13, 14, 15, 18], "v": [0, 4, 8, 16], "cip": 0, "cl": 0, "clone": [0, 1, 3, 4, 6, 7, 9, 11], "recurs": [0, 4, 17], "di": 0, "diff": [0, 4, 7, 9, 13, 16], "dic": 0, "stage": [0, 2, 3, 4, 7, 8, 9, 12, 13], "color": 0, "word": [0, 3, 5, 6, 11, 12], "diw": 0, "pager": [0, 5], "stat": [0, 2, 6], "fe": 0, "fetch": [0, 14], "rem": 0, "st": 0, "statu": [0, 1, 2, 4, 6, 7, 9, 12, 13, 14, 16, 17], "su": 0, "submodul": 0, "updat": [0, 4, 7, 18], "init": [0, 2, 6, 7, 13], "what": [0, 3, 4, 6, 7, 8, 9, 12, 14, 16, 17], "select": [0, 12, 14, 16], "part": [0, 2, 3, 4, 14], "individu": [0, 2, 13, 16], "interact": [0, 8, 13], "obviou": [0, 18], "check": [0, 1, 2, 4, 6, 7, 9, 12, 14, 16, 17, 18], "option": [0, 7, 12, 13, 14, 16], "clariti": 0, "an": [0, 1, 2, 4, 7, 9, 11, 12, 15, 17, 18], "topic": 0, "area": [0, 2, 7, 8, 9, 10, 13, 17], "last": [0, 1, 4, 6, 9, 12, 13, 16], "about": [0, 2, 3, 4, 5, 6, 7, 12, 14, 16, 17], "small": [0, 2, 10, 16, 18], "chang": [0, 3, 7, 8, 9, 13, 14, 16, 17, 18], "diffstat": 0, "file": [0, 1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18], "content": [0, 2, 4, 6], "show": [0, 1, 3, 4, 7, 9, 12, 13, 14], "whole": [0, 2, 7, 8], "some": [0, 1, 2, 3, 4, 7, 11, 12, 13, 16, 18], "u": [0, 1, 2, 3, 4, 6, 9, 12, 14, 16, 17], "l": [0, 17], "set": [0, 2, 3, 7, 11, 14], "p": [0, 9, 10, 12, 16, 17], "singlekei": 0, "true": [0, 18], "won": [0, 4], "t": [0, 2, 3, 4, 6, 7, 11, 12, 16, 17, 18], "explain": [0, 2, 4, 6, 7, 16, 18], "bore": [0, 7], "have": [0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 16, 17, 18], "want": [0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 14, 16], "go": [0, 1, 2, 3, 4, 6, 7, 11, 12, 13, 14, 16, 17], "deeper": 0, "try": [0, 1, 2, 3, 4, 6, 8, 9, 11, 12, 14], "figur": [0, 2, 4], "out": [0, 2, 3, 4, 6, 7, 11, 13, 14, 16], "might": [0, 3, 4, 8, 9, 10, 12, 14], "manual": [0, 3, 4, 6, 7, 17], "page": [0, 1, 2, 6, 13, 14, 18], "cif": 0, "fixup": 0, "rb": 0, "rebas": [0, 7, 9, 12], "autosquash": 0, "rbi": 0, "autostash": 0, "rec": 0, "upstream": [0, 4], "head": [0, 2, 3, 4, 6, 12, 13, 14, 16, 17], "ignor": [0, 7, 18], "o": 0, "exclud": 0, "standard": [0, 7], "new": [0, 1, 2, 3, 4, 6, 7, 8, 10, 12, 13, 14, 16, 17, 18], "newd": 0, "newdi": 0, "reca": 0, "n10": 0, "recd": 0, "besid": 0, "ones": [0, 7, 16], "core": [0, 2, 14], "less": [0, 1, 3, 4, 6, 9], "r": [0, 11, 17], "excludesfil": 0, "gitignor": [0, 14, 18], "merg": [0, 5, 7, 8, 9, 10, 13, 14, 18], "conflictstyl": 0, "diff3": 0, "wordregex": 0, "za": 0, "z0": 0, "9_": 0, "space": [0, 1], "mnemonicprefix": 0, "copi": [0, 2, 9, 14], "past": [0, 6, 12, 14], "name": [0, 1, 2, 3, 9, 13, 14, 16], "like": [0, 1, 2, 3, 4, 5, 6, 9, 10, 12, 14, 16, 17], "github": [0, 1, 2, 4, 5, 6, 7, 11, 12, 13], "com": [0, 1, 2, 3, 4, 5, 6, 7, 12, 14], "myusernam": 0, "url": [0, 14], "insteadof": 0, "gh": 0, "usernam": [0, 14], "ghu": 0, "Then": [0, 1, 3, 4, 6, 12, 14, 17], "recip": [0, 3, 4, 6, 7, 12, 16], "automat": [0, 1, 2, 4, 6, 14], "translat": [0, 14], "prefix": 0, "match": 0, "If": [0, 1, 2, 6, 8, 10, 12], "frustrat": 0, "rememb": [0, 2, 3, 4, 6, 12], "Be": [1, 3, 12], "abl": [1, 2, 3, 4, 6, 7, 8, 14], "why": [1, 2, 3, 6, 17, 18], "wa": [1, 2, 3, 4, 6, 7, 11, 12, 14, 18], "introduc": [1, 6, 7, 11, 13], "quickli": 1, "behavior": [1, 2], "30": [1, 3, 7], "min": [1, 2, 3, 4, 7, 9, 10, 11, 12, 14, 16, 17], "teach": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 16, 17], "along": [1, 3, 4, 7, 9, 12, 14, 16, 17], "pleas": [1, 2, 3, 4, 7, 10, 11, 14, 18], "sure": [1, 2, 3, 6, 7, 10, 11, 12, 14, 16], "insid": [1, 2, 17], "alreadi": [1, 2, 3, 4, 6, 7, 9, 12, 14, 18], "track": [1, 3, 6, 12, 13, 14], "folder": [1, 2, 6, 12, 17], "exist": [1, 2, 4, 6, 7, 8, 10, 11, 12, 13], "step": [1, 2, 3, 14], "need": [1, 2, 3, 4, 6, 7, 8, 10, 12, 14, 16, 17], "differ": [1, 2, 3, 4, 6, 7, 11, 13, 14, 16, 17], "locat": [1, 16, 17], "sinc": [1, 2, 3, 4, 6, 7, 11, 12, 16, 18], "messag": [1, 3, 6, 7, 12, 13, 17, 18], "good": [1, 2, 3, 6, 7, 8, 9, 11, 12, 15, 17], "case": [1, 3, 4, 6, 7, 9, 11, 12, 14, 16], "fatal": 1, "ani": [1, 2, 3, 4, 6, 11, 12, 13], "parent": [1, 3, 6, 17], "directori": [1, 2, 3, 4, 6, 7, 9, 11, 13, 14, 16, 17], "first": [1, 2, 3, 4, 6, 8, 9, 11, 12, 13, 14, 17, 18], "demonstr": [1, 3, 5, 6, 7, 8, 11, 14], "few": [1, 3, 5, 6, 7, 9, 12, 17, 18], "real": [1, 9, 14], "life": 1, "exampl": [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 14, 16], "http": [1, 2, 3, 4, 5, 6, 7, 11, 12, 16], "networkx": [1, 6], "mention": [1, 2, 3, 6, 7, 8], "amaz": 1, "site": [1, 14], "The": [1, 2, 3, 6, 7, 8, 9, 10, 12, 14, 15, 17, 18], "program": [1, 2, 4], "historian": 1, "later": [1, 2, 6, 9, 10, 11, 12, 14, 15, 16, 18], "practic": [1, 2, 3, 4, 6, 7, 8, 11, 15], "below": [1, 2, 3, 4, 6, 7, 8, 9, 12, 14], "As": [1, 2, 3, 6, 12], "readm": [1, 2, 3, 6, 12, 14], "rst": 1, "visit": [1, 2, 14], "brows": [1, 2, 6, 11], "githistori": 1, "xyz": 1, "blob": [1, 17], "main": [1, 2, 3, 4, 6, 9, 10, 12, 13, 14, 17], "left": [1, 2, 3, 4, 6, 9], "right": [1, 2, 3, 4, 6, 7, 9, 14, 16, 17], "kei": [1, 7, 14, 16], "too": [1, 2, 3, 7, 10, 18], "With": [1, 2, 3, 6, 8, 9, 11], "grep": [1, 5, 6, 13], "contain": [1, 2, 3, 6, 10, 12, 14, 17], "regular": [1, 3], "express": 1, "where": [1, 2, 3, 4, 6, 8, 9, 11, 12, 14, 16], "variabl": 1, "error": [1, 6, 14], "print": [1, 3, 6, 9, 16], "fixm": 1, "while": [1, 3, 6, 9], "state": [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 16, 17], "through": [1, 2, 7, 8, 16], "sometext": 1, "got": [1, 2, 6, 12, 13, 14, 16], "remov": [1, 2, 3, 4, 6, 12, 13, 14, 16, 18], "same": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 16], "q": [1, 2, 7, 16], "repo": [1, 12, 14], "3anetworkx": 1, "2fnetworkx": 1, "seen": [1, 2, 6, 12, 14], "one": [1, 2, 3, 4, 6, 7, 8, 9, 10, 14, 15, 16], "know": [1, 2, 3, 4, 6, 7, 9, 10, 11, 14, 16], "its": [1, 7, 14, 17], "hash": [1, 2, 3, 6, 9, 12, 13, 17], "For": [1, 2, 3, 6, 7, 8, 12, 14, 17], "instanc": [1, 3, 4, 6], "759d589bdfa61aff99e0535938f14f67b01c83f7": 1, "who": [1, 4, 7, 8, 14], "modifi": [1, 2, 4, 7, 9, 16, 17], "precis": [1, 7, 11], "each": [1, 2, 6, 16, 17], "incredibli": 1, "reproduc": [1, 7], "convert_matrix": 1, "py": [1, 6], "termin": [1, 3, 7, 11, 12, 14], "longer": [1, 18], "than": [1, 2, 3, 4, 6, 10, 11, 12, 18], "screen": 1, "default": [1, 2, 13, 14], "scroll": 1, "output": [1, 2, 6], "enter": [1, 6], "cycl": 1, "result": [1, 3, 4, 6, 7, 11], "n": [1, 4, 6, 16], "next": [1, 2, 3, 6, 14, 16], "down": [1, 6, 12, 14], "quit": [1, 2], "blame": [1, 7], "screenshot": [1, 2, 3, 6, 14], "rel": [1, 2, 14], "trivial": 1, "affect": [1, 2, 7, 11, 12], "wrap": 1, "long": [1, 2, 3, 4, 9, 11, 12, 15, 16], "shorter": 1, "auto": [1, 4, 6], "format": 1, "tool": [1, 4, 7, 16], "black": 1, "editor": [1, 2, 4, 6, 8, 16, 17], "trail": [1, 14], "whitespac": 1, "point": [1, 3, 6, 11, 12, 14, 18], "recommend": [1, 2, 7, 8], "mechan": [1, 7, 17], "old": [1, 6, 12], "switch": [1, 2, 3, 4, 6, 7, 9, 12, 13, 17], "branchnam": [1, 3, 6, 12], "start": [1, 2, 3, 4, 6, 8, 10, 11, 16, 17, 18], "onli": [1, 2, 3, 4, 6, 10, 12, 14, 16], "comment": [1, 3, 18], "older": [1, 3, 4, 8, 12], "from": [1, 2, 3, 4, 6, 8, 11, 16, 17, 18], "347e6292419b": 1, "347e6292419bd0e4bff077fe971f983932d7a0e9": 1, "now": [1, 2, 3, 4, 6, 7, 9, 11, 12, 14, 16, 17], "navig": [1, 6], "back": [1, 2, 3, 6, 7, 9, 12, 14, 16, 17, 18], "after": [1, 2, 3, 4, 6, 7, 9, 13, 14], "done": [1, 2, 3, 4, 6, 7, 8, 12, 14, 16, 18], "delet": [1, 4, 6, 12, 17], "d": [1, 3], "On": [1, 2, 3, 4, 6, 12, 17], "version": [1, 2, 3, 4, 6, 7, 12, 13, 14, 16], "23": [1, 6, 8], "checkout": [1, 3, 4, 6, 12, 16], "b": [1, 2, 4, 6, 12, 13, 16], "somehash": [1, 6], "347e629": 1, "onc": [1, 3, 4, 6, 7, 10, 12, 14, 15, 16, 17, 18], "let": [1, 2, 3, 4, 6, 11, 12, 16, 17, 18], "valu": [1, 6], "futur": [1, 2, 6, 7, 14], "depend": [1, 6, 12, 13], "ok": [1, 6, 10, 11, 12, 18], "complet": [1, 6, 9, 12, 18], "fulli": [1, 6, 10], "6": [1, 4, 6, 9], "3": [1, 7, 14, 16, 17], "tag": [1, 6, 10, 14, 17], "releas": [1, 2, 6], "abov": [1, 2, 4, 6, 9, 12, 14, 16], "logic": [1, 6, 16], "degree_correl": [1, 6], "ad": [1, 3, 4, 6, 18], "actual": [1, 4, 6, 13, 16], "bring": [1, 6], "provid": [1, 6, 7, 9, 10, 17], "encourag": [1, 2, 3, 6], "give": [1, 2, 3, 4, 6, 7, 9, 11, 16], "algorithm": [1, 3, 6], "threshold": [1, 2, 6], "rdi": [1, 6], "mayb": [1, 3, 6, 14, 18], "number": [1, 4, 6, 8], "follow": [1, 2, 3, 4, 6, 11, 12, 14], "90544b4fa": [1, 6], "unless": [1, 2, 3, 4, 6, 14], "compact": [1, 6], "access": [1, 2, 6, 14], "just": [1, 2, 3, 6, 8, 10, 14, 16], "am": [1, 11], "work": [1, 2, 4, 7, 11, 12, 13, 14, 16, 17, 18], "strang": 1, "sometim": [1, 3, 4, 12, 13, 18], "realiz": [1, 3, 4, 7, 12], "problem": [1, 3, 7, 11, 14, 16, 18], "500": [1, 6], "ago": 1, "doe": [1, 2, 3, 4, 6, 9, 12, 14, 17, 18], "could": [1, 2, 6, 9], "probabl": [1, 2, 6, 7, 9, 10, 11, 14, 18], "arriv": [1, 2, 6], "similar": [1, 2, 6, 8, 12, 14], "f0ea950": 1, "broken": [1, 7], "compil": [1, 2, 3, 16], "run": [1, 2, 3, 4, 6, 7, 11, 12, 14, 16], "test": [1, 11, 14, 18], "decid": [1, 4, 6, 12, 16], "whether": [1, 4, 7], "tell": [1, 2, 3, 4, 6], "And": [1, 2, 3, 4, 6, 7], "iter": 1, "until": [1, 3, 6, 7, 12, 14], "reset": [1, 4, 6, 7, 13, 16], "even": [1, 3, 4, 5, 7, 8, 18], "script": [1, 6, 11], "write": [1, 6, 7, 9, 10, 12, 14], "return": [1, 2, 7, 9, 14], "zero": 1, "non": 1, "success": [1, 2, 15], "failur": [1, 11], "begin": [1, 6, 16], "coderefineri": [1, 3, 4, 6, 7, 8, 14], "motiv": [1, 2, 7, 8], "sourc": [1, 6, 11, 14], "bug": [1, 3, 6, 7, 11], "difficult": [1, 2, 6, 11, 18], "visual": [1, 3, 4, 7], "offend": [1, 6], "often": [1, 2, 3, 4, 6, 7, 9, 10, 11, 13, 14, 15, 16, 18], "more": [1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18], "half": [1, 2, 3, 6, 7, 12], "debug": [1, 3, 6, 9, 16], "background": [1, 6], "get_pi": [1, 6], "approxim": [1, 6], "pi": [1, 6], "term": [1, 2, 6, 7, 15, 17], "nilakantha": [1, 6], "seri": [1, 6], "produc": [1, 6], "14": [1, 2, 6], "57": [1, 6], "python": [1, 2, 3, 6], "At": [1, 3, 6, 7, 14], "within": [1, 2, 6], "correctli": [1, 6], "task": [1, 6, 9], "comput": [1, 3, 6, 8, 14], "spoiler": [1, 6], "alert": [1, 6], "found": [1, 3, 6, 7, 11], "bonu": [1, 6], "correct": [1, 2, 6, 7, 12, 14], "hint": [1, 2, 6, 7], "tail": [1, 6], "tild": [1, 6], "power": [1, 14], "combin": [1, 4, 7, 10, 18], "grasp": 2, "structur": [2, 3, 7], "inspect": [2, 3, 4, 8, 12, 13, 16, 17], "35": [2, 7], "40": [2, 3, 7, 17], "control": [2, 3, 4, 7, 12, 14], "system": [2, 4, 7, 8, 11], "over": [2, 7, 16, 18], "everi": [2, 6, 7, 16], "entir": [2, 4, 15], "assign": [2, 7], "kept": 2, "sub": 2, "keep": [2, 3, 4, 7, 13, 16], "move": [2, 3, 4, 6, 7, 12, 14, 16], "somewher": [2, 11, 14], "els": [2, 3, 4, 9, 11, 18], "still": [2, 4, 6, 7, 9], "doesn": [2, 6, 9, 12, 17], "anyth": [2, 7], "ask": [2, 6, 7, 9, 11, 12], "multipl": [2, 7, 14, 16], "web": [2, 8, 11], "take": [2, 4, 12, 16], "request": [2, 10, 18], "don": [2, 3, 4, 6, 7, 11, 12, 18], "yet": [2, 6, 7, 12], "txt": [2, 3, 4, 6, 16], "anotherfil": 2, "focu": 2, "think": [2, 3, 4, 6, 7, 14], "outcom": 2, "edit": [2, 3, 4, 6, 7, 8, 13], "again": [2, 3, 4, 6, 7, 9, 10, 12, 14, 16], "sever": [2, 3, 4, 6, 9, 16, 17], "end": [2, 3, 6, 7, 10, 16, 18], "perform": 2, "focus": 2, "scene": 2, "press": 2, "shutter": 2, "instal": [2, 4, 6, 8, 14], "instruct": [2, 3, 4, 6, 8, 12, 14, 16], "email": [2, 11], "address": [2, 14, 16], "yournam": 2, "nano": [2, 7, 8], "defaultbranch": 2, "verifi": [2, 3, 4, 14, 17], "list": [2, 3, 8, 9, 11, 12, 17, 18], "learner": [2, 7, 8], "enough": [2, 4, 8, 11], "initi": 2, "delici": 2, "inspir": [2, 3, 7, 11], "smith": 2, "carpentri": 2, "mail": 2, "cook": 2, "everybodi": 2, "relat": [2, 4, 6, 7, 16], "mai": [2, 3, 4, 7, 10, 12, 18], "written": [2, 15], "e": [2, 3, 4, 6, 7, 12], "g": [2, 3, 4, 6, 7, 12], "anoth": [2, 3, 7, 8, 13, 14, 16, 17], "languag": 2, "lesson": [2, 3, 6, 8, 10, 12, 13, 14, 16], "realli": [2, 3, 7, 9, 10, 18], "stuck": [2, 6, 7, 14], "One": [2, 6, 7, 11, 12, 13, 16], "principl": 2, "mkdir": 2, "That": 2, "empti": [2, 14], "No": [2, 4, 6, 8, 14], "noth": [2, 3, 4, 6, 17], "sens": [2, 12], "inform": [2, 3, 5, 6, 7, 11, 12, 17], "dure": [2, 4, 6, 7, 18], "descript": [2, 14, 16, 17], "click": [2, 6, 14], "plu": [2, 14], "symbol": [2, 6, 14], "top": [2, 3, 4, 6, 9, 11, 14, 16], "directli": [2, 10, 14], "choos": [2, 8, 14], "short": [2, 14, 16], "final": [2, 4, 14], "overview": 2, "md": [2, 3, 6], "ingredi": [2, 3, 4, 6, 12, 16], "avocado": [2, 3, 4, 6], "chili": [2, 3, 4, 6], "lime": [2, 3, 4, 6], "tsp": [2, 3, 4, 6], "salt": [2, 3, 4, 6], "second": [2, 4], "chop": 2, "onion": [2, 3, 4, 6, 12], "squeez": [2, 6], "mix": [2, 6, 16], "well": [2, 3, 4, 6, 8, 16], "alwai": [2, 7, 10, 11, 14, 17], "safe": [2, 4, 6, 10, 12], "idea": [2, 3, 6, 7, 10, 11, 12, 16, 17, 18], "when": [2, 3, 7, 9, 11, 12, 13, 16, 17, 18], "untrack": [2, 7], "includ": [2, 12, 18], "present": [2, 7, 16, 17], "camera": 2, "consciou": 2, "decis": 2, "rm": [2, 6, 12, 18], "cach": 2, "unstag": [2, 4, 6, 13, 16], "readi": [2, 3, 7, 16, 17, 18], "m": [2, 3, 6, 14], "root": 2, "f146d25": [2, 3, 6, 12], "insert": [2, 4], "mode": [2, 6, 7], "100644": [2, 4, 6], "queri": 2, "muscl": 2, "memori": 2, "third": 2, "flag": [2, 3, 6], "mean": [2, 3, 4, 6, 7, 12, 14], "versatil": [2, 3], "worri": [2, 14, 17], "mind": [2, 3, 9, 14], "read": [2, 10, 14], "doubt": [2, 4], "search": [2, 6, 7, 11, 13], "onlin": [2, 7, 8, 10, 11], "find": [2, 3, 7, 11, 12, 13, 17], "relev": [2, 6], "thread": 2, "network": [2, 11], "connect": [2, 7, 14], "specifi": [2, 7, 14], "adjust": [2, 10], "howev": [2, 3, 11], "up": [2, 3, 4, 6, 7, 11, 12, 14, 17, 18], "three": [2, 3, 6, 14, 16], "enjoi": [2, 3, 6, 12], "identifi": [2, 6], "index": [2, 4, 6, 9, 17], "4422a31": [2, 6], "ba8854f": [2, 6], "7811273": [2, 6], "2b11074": [2, 6], "separ": [2, 3, 6, 8, 9, 16], "happen": [2, 3, 4, 6, 7, 9, 12, 14, 17], "leav": [2, 4, 6, 7, 11, 14], "open": [2, 4, 6, 7, 11, 14, 17], "associ": [2, 6], "made": [2, 3, 6, 12, 16, 17], "chanc": [2, 4, 6, 7, 8, 11], "ve": [2, 6, 14, 17], "convinc": [2, 6], "self": [2, 6], "were": [2, 3, 6, 7, 9, 17], "justifi": [2, 6, 12], "close": [2, 4, 6, 7, 14], "experi": [2, 3, 6, 11, 12], "modif": [2, 4, 6, 7, 9, 12, 13, 16], "pen": [2, 6], "By": [2, 6, 7], "preview": [2, 6], "goal": [2, 3, 6, 8, 14, 17], "haven": [2, 6, 7, 12], "e7cf023efe382340e5284c278c6ae2c087dd3ff7": [2, 3], "author": [2, 3, 11, 17], "radovan": 2, "bast": 2, "norepli": 2, "date": [2, 4], "sun": 2, "sep": 2, "17": 2, "19": [2, 11], "12": [2, 7], "47": 2, "2023": [2, 3, 11], "0200": 2, "79161b6e67c62ad4688a58c1e54183334611a390": 2, "32": 2, "a3394e39535343c4dae3bb4f703741a31aa8b78a": 2, "18": 2, "369624674e63de48055a65bf63055bd59c985d22": 2, "46": 2, "58": 2, "f146d25b94569a15e94d7f0da6f15d7554f76c49": 2, "52": [2, 17], "arbitrari": 2, "hash1": [2, 6], "hash2": [2, 6], "develop": [2, 3, 6, 7], "uniqu": [2, 13], "label": [2, 3, 6, 12, 16], "code": [2, 3, 4, 6, 7, 8, 9, 10, 12, 16, 18], "integ": 2, "count": [2, 14], "revers": 2, "chronolog": 2, "order": [2, 6, 9, 16, 17], "newest": [2, 13, 16], "7": [2, 6, 9], "necessari": [2, 7, 8], "nice": [2, 3, 6, 16], "been": [2, 3, 6, 7, 9, 18], "look": [2, 3, 4, 5, 6, 7, 12, 16, 17], "between": [2, 3, 4, 6, 7, 9, 13, 16], "under": [2, 6, 7, 8, 14], "side": [2, 5, 6, 11], "further": [2, 6, 14], "difftool": [2, 6], "requir": [2, 3, 4, 6, 8], "window": [2, 6, 14], "linux": [2, 6], "meld": [2, 6], "maco": [2, 6], "opendiff": [2, 6], "notic": [2, 3, 4, 6, 18], "deepen": [2, 6], "both": [2, 3, 4, 6, 12, 16], "manag": [2, 3, 4, 6, 14], "troubl": [2, 6], "shoot": [2, 6], "better": [2, 9, 10, 11, 16, 18], "import": [2, 7, 10, 11, 16, 18], "increas": [2, 4, 18], "alpha": 2, "0": [2, 3, 8, 14, 17], "enabl": [2, 7], "123": 2, "convent": [2, 3], "summar": [2, 7], "paragraph": 2, "detail": [2, 3, 13, 14], "free": [2, 14], "form": [2, 3, 7, 9, 11, 17], "someth": [2, 3, 4, 6, 7, 9, 12, 14, 18], "ha": [2, 3, 6, 7, 12, 18], "cross": [2, 14], "refer": [2, 6, 7, 14, 16, 17, 18], "issu": [2, 4, 7, 16], "bad": [2, 3, 4, 7, 9, 11, 16], "fix": [2, 3, 4, 6, 9, 12, 16], "oop": 2, "whatthecommit": 2, "english": 2, "understood": 2, "15": [2, 7, 9, 11, 14, 17], "year": [2, 7], "someon": [2, 4, 18], "Or": [2, 3, 4, 11, 18], "me": [2, 3, 11], "50": [2, 7], "peopl": [2, 4, 6, 7, 11, 12, 14, 18], "decad": 2, "my": [2, 5, 6, 11, 14], "favourit": 2, "style": [2, 9], "choic": [2, 7, 16], "scipi": 2, "numpi": 2, "panda": 2, "julia": 2, "ggplot2": 2, "flask": 2, "design": 2, "consid": 2, "easili": [2, 4, 7, 9, 14, 16], "changelog": 2, "review": [2, 11, 18], "especi": [2, 18], "perfect": [2, 9, 15, 18], "enemi": 2, "binari": 2, "reason": [2, 8, 9, 10, 11], "platform": [2, 8, 11, 14], "thu": 2, "contribut": [2, 3, 11, 14, 18], "meaning": 2, "although": 2, "touch": [2, 6, 9, 12], "pyc": 2, "__pycache__": 2, "taken": [2, 8], "offici": 2, "document": [2, 3, 6, 10, 11, 12], "archiv": 2, "anywher": 2, "tree": [2, 7, 17], "oa": 2, "html": [2, 7], "except": 2, "foo": 2, "maintain": 2, "hand": [2, 7], "everyth": [2, 4, 8, 9, 12, 14, 16, 17], "build": [2, 11], "shell": [2, 7, 14], "glob": 2, "syntax": [2, 5], "determin": 2, "pattern": [2, 13], "lower": 2, "level": [2, 5, 17], "via": [2, 11], "websit": [2, 11, 14], "gui": 2, "desktop": 2, "sourcetre": 2, "parti": 2, "checkpoint": [2, 16], "undo": [2, 7, 8, 10, 18], "uncommit": 2, "mv": 2, "renam": [2, 14], "ideal": [2, 7, 8], "larg": [2, 18], "annex": 2, "would": [2, 3, 4, 6, 7, 10, 12, 16], "myfil": [2, 6], "recent": [2, 6, 8, 9, 13], "stori": [2, 3], "afraid": [2, 4, 7], "20": [3, 4, 7, 10], "previou": [3, 11, 17], "section": [3, 4, 6, 7, 14], "guacamol": [3, 6, 7, 14], "git": [3, 7, 9, 13, 14, 15, 18], "had": [3, 7, 12], "come": [3, 9, 18], "linear": [3, 6], "depict": 3, "littl": [3, 4, 6], "box": [3, 4, 16], "abbrevi": 3, "posit": 3, "record": [3, 7, 13, 16, 17], "tape": 3, "sai": 3, "those": [3, 4, 6, 14], "liter": [3, 12, 16], "isn": [3, 12, 16], "placehold": [3, 12], "talk": [3, 4], "imag": [3, 11, 17], "us": [3, 8, 9, 10, 11, 12, 14, 17, 18], "gopher": [3, 11], "softwar": [3, 11, 14], "least": [3, 6, 7, 8, 9, 12, 16], "expect": [3, 4, 6], "featur": [3, 4, 9, 10, 15, 16, 18], "concurr": 3, "unfinish": [3, 10, 18], "line": [3, 4, 7, 8, 9, 13, 14, 16], "strength": 3, "permit": 3, "research": [3, 8, 14], "isol": 3, "composit": 3, "master": [3, 13], "special": 3, "direct": [3, 7, 17], "acycl": [3, 17], "graph": [3, 4, 6, 9, 11, 12, 13, 17], "arrow": 3, "avoid": [3, 6, 7, 8, 12], "group": [3, 16, 18], "singl": [3, 6, 11, 12], "narr": 3, "strategi": [3, 7, 9], "sequenc": [3, 16], "extract": 3, "interfac": [3, 11], "matrix": 3, "invers": 3, "without": [3, 4, 7, 9, 11], "command": [3, 4, 7, 8, 12, 14], "alias": [3, 8], "given": 3, "extens": 3, "rest": 3, "ensur": 3, "collabor": [3, 4, 6, 7, 8, 10, 12, 14, 18], "histori": [3, 4, 8, 11, 13, 14, 18], "e7cf023": [3, 6, 12], "79161b6": [3, 6, 12], "a3394e3": [3, 6, 12], "3696246": [3, 6, 12], "coupl": [3, 6, 12, 14, 17], "character": 3, "checksum": [3, 17], "pointer": [3, 13, 17], "afterward": [3, 14], "togeth": [3, 4, 6, 16, 18], "particip": [3, 7, 8, 17], "episod": [3, 7], "prefer": [3, 11], "browser": [3, 8], "cilantro": [3, 4, 6], "text": [3, 4, 7, 8, 11, 17], "2019": [3, 4, 11, 12], "clear": [3, 4, 7, 16], "tbsp": [3, 4], "reduc": [3, 4, 6], "amount": [3, 4, 6], "bit": [3, 4, 6, 9, 17], "bcb8b78": [3, 6], "f6ec7b7": [3, 6], "ahead": 3, "safer": [3, 6], "explicitli": [3, 6], "shown": [3, 6], "bf28166": [3, 6], "graphic": [3, 6, 7], "represent": [3, 6, 7], "situat": [3, 6, 12, 16], "b4af65b": [3, 6, 12], "comparison": [3, 6], "turn": [3, 11], "appli": [3, 4, 6], "skip": [3, 4, 14, 16], "origin": [3, 4, 13, 14], "helper": [3, 4, 6, 14], "un": [3, 4], "wish": [3, 7, 9, 12], "81fcc0c": 3, "intern": [3, 15], "attempt": [3, 7], "incorpor": 3, "To": [3, 4, 6, 7, 8, 14], "view": [3, 4, 5, 6, 7], "happi": [3, 4], "4e03d4b": [3, 4], "observ": [3, 4, 6], "cat": [3, 4, 17], "overlap": 3, "user": [3, 7, 8, 10, 11, 14, 17, 18], "settl": 3, "conflict": [3, 5, 7, 8, 9, 18], "sticki": [3, 7], "disappear": 3, "reintegr": 3, "insist": 3, "lost": [3, 12], "hard": [3, 6, 7, 10, 12, 13, 14, 17], "advanc": [3, 6, 7, 9, 10, 11], "absolut": 3, "postpon": [3, 4, 18], "month": [3, 4, 16, 18], "resolv": [3, 7, 9, 12], "examin": [3, 6], "discuss": [3, 6, 7, 8, 12], "ancestor": [3, 4, 6], "did": [3, 4, 6, 7, 11, 16], "diverg": [3, 6], "altern": [3, 6, 8, 16], "replai": [3, 6], "explicit": [3, 6], "public": [3, 6, 7], "alter": [3, 6], "contrast": 3, "ever": [3, 7, 16], "commemor": 3, "plaqu": 3, "particular": [3, 7], "mileston": [3, 10], "semant": [3, 4], "v1": 3, "easier": [3, 10, 18], "64441c1934def7d91ff0b66af0795749d5f1954a": 3, "basic": [3, 7, 8, 9, 11, 18], "annot": [3, 6, 7, 11, 13], "lightweight": [3, 17], "cryptograph": 3, "sign": 3, "gpg": 3, "timestamp": 3, "attach": 3, "nobel": 3, "banquet": 3, "pro": [3, 15, 17], "book": [3, 15, 17], "chapter": 3, "subject": 3, "paus": 3, "moment": [3, 17], "recapitul": 3, "unmerg": [3, 4], "combo": [3, 6], "frequent": 3, "wild": 3, "throw": [3, 12, 13], "awai": [3, 9, 12, 13, 17], "gone": [3, 6, 11, 12], "off": [3, 6, 9], "job": [3, 6], "divis": 3, "unit": [3, 10], "understand": [4, 17], "suffici": 4, "imagin": [4, 12], "somebodi": [4, 11, 14], "smooth": 4, "appear": 4, "fast": 4, "forward": 4, "portion": [4, 11, 12], "silent": 4, "overwrit": [4, 14], "scari": 4, "luckili": 4, "rare": [4, 16], "meet": 4, "simpli": 4, "kind": [4, 11], "measur": 4, "person": [4, 7], "declar": 4, "minor": 4, "revis": 4, "spell": 4, "rewrit": 4, "function": [4, 7, 13], "solv": [4, 6, 7, 16], "demo": [4, 7, 14], "decreas": 4, "dislik": [4, 6], "e83294b": 4, "6cacd50": 4, "4": [4, 16, 17], "6484462": 4, "3caa632": 4, "fail": [4, 6, 14], "path": [4, 9, 12, 18], "marker": [4, 6], "cc": [4, 17], "0000000": 4, "10": [4, 7, 9, 16, 17], "care": [4, 12], "exactli": [4, 6, 7], "emac": 4, "certain": [4, 9], "plugin": 4, "pre": 4, "fill": 4, "repeat": [4, 6, 16], "almost": [4, 6, 7, 9], "banch": [4, 6], "5": [4, 9, 16, 17], "link": [4, 6, 17], "assum": [4, 6, 8, 12], "meant": [4, 6], "anticip": [4, 6, 11, 16], "inde": [4, 6], "ye": [4, 6, 9], "slightli": [4, 6], "continu": [4, 6, 9], "disagre": [4, 6], "stop": [4, 6, 18], "middl": [4, 6, 9, 16], "backup": [4, 6, 7, 11, 14], "addit": [4, 6, 9, 18], "temporari": [4, 6, 9], "clean": [4, 6, 11, 17], "f": [4, 6], "configur": [4, 6, 7, 8, 11, 13, 14], "keepbackup": [4, 6], "fals": [4, 6], "xour": 4, "xtheir": 4, "plan": [4, 10], "put": [4, 9, 16], "unrel": [4, 6, 9, 10, 16, 18], "live": [4, 16], "layout": [4, 18], "data": [4, 9, 11, 14, 17], "caus": 4, "modular": 4, "risk": [4, 18], "technic": 4, "share": [4, 6, 7, 8, 11, 12], "earli": [4, 7, 10, 18], "circumst": 4, "everyon": [4, 7], "selfish": 4, "push": [4, 6, 7, 8, 12, 14], "best": [4, 15], "pull": [4, 10, 14, 18], "handl": 4, "compar": [4, 7, 11, 16], "servic": [4, 13], "googl": 4, "drive": 4, "commun": 4, "optim": [4, 7], "context": [5, 9], "awar": 5, "displai": 5, "contextu": 5, "jimeh": 5, "bash": [5, 7], "ohmyz": 5, "sh": 5, "zsh": 5, "oh": [5, 11], "fish": 5, "magicmonti": 5, "delta": [5, 14], "highlight": 5, "allow": [5, 8, 14], "mainli": 6, "instructor": [6, 8], "event": 6, "cover": 6, "subset": 6, "interest": 6, "own": [6, 8, 11, 12, 14], "sound": [6, 9, 11], "discov": [6, 11], "note": [6, 18], "abort": [6, 7, 9, 12, 16], "toolbox": 6, "broke": [6, 11, 13], "bottom": [6, 14, 16], "unmodifi": [6, 7, 16], "keystrok": [6, 16], "re": [6, 7, 13, 16], "benefici": [6, 16], "feel": [6, 7, 8, 14, 16], "regret": [6, 16], "newli": [6, 12], "incomplet": [6, 12], "typo": [6, 12], "unsatisfactori": [6, 12], "amend": [6, 12, 13], "d3fc63a": [6, 12], "e02efcd": [6, 12], "accident": [6, 12, 14, 18], "forev": [6, 12], "nobodi": [6, 11, 12], "possibli": [6, 12, 14], "anyon": [6, 12], "alright": [6, 12], "extraordinari": [6, 12], "condit": [6, 12], "sensit": [6, 12], "secret": [6, 12], "pop": [6, 9], "twice": [6, 9], "opposit": [6, 9, 12, 16], "extra": [6, 9, 14], "deci": [6, 9], "ref": [6, 9, 17], "ce": 7, "08": 7, "09": [7, 11], "00": [7, 14], "soft": [7, 13, 16], "icebreak": 7, "question": [7, 11, 18], "break": 7, "11": 7, "lunch": 7, "13": 7, "resolut": [7, 8, 12], "feedback": 7, "tomorrow": 7, "recap": 7, "25": [7, 12, 14, 17], "ssh": 7, "45": 7, "recov": [7, 8, 10], "alon": [7, 16], "industri": 7, "high": [7, 8, 11, 18], "encount": 7, "becom": [7, 12], "disast": 7, "mistak": [7, 12], "roll": 7, "parallel": 7, "toe": 7, "exact": 7, "major": 7, "extent": 7, "comfort": [7, 8], "lack": 7, "mental": 7, "model": [7, 10, 11, 15, 17], "oper": [7, 14], "never": [7, 9, 12, 17, 18], "newcom": 7, "experienc": 7, "valuabl": 7, "etc": [7, 17], "craft": [7, 16], "revert": [7, 13], "discard": [7, 11, 16], "restor": [7, 12, 13, 16], "danger": [7, 10, 14], "prevent": [7, 14, 18], "incorrect": 7, "session": 7, "fall": 7, "behind": 7, "student": 7, "briefli": 7, "finish": 7, "indic": [7, 11], "green": [7, 14], "rais": 7, "describ": [7, 12, 18], "home": [7, 16], "fine": [7, 14], "though": 7, "spend": 7, "assess": 7, "activ": [7, 18], "object": 7, "being": 7, "met": 7, "pose": 7, "minut": 7, "answer": [7, 11], "signal": 7, "emphas": 7, "effici": [7, 15], "avail": [7, 16], "gitlab": [7, 8, 11, 13, 14], "bisect": [7, 13], "anybodi": 7, "rather": [7, 10, 16], "publish": [7, 11, 15], "involv": 7, "wonder": 7, "whom": [7, 13], "behav": 7, "incorrectli": 7, "earlier": 7, "screencast": 7, "modul": [7, 8], "forgotten": 7, "expand": 7, "stash": [7, 10], "info": [7, 17], "anytim": 7, "cheat": 7, "sheet": 7, "www": 7, "ndpsoftwar": 7, "far": [7, 14], "cours": [7, 8, 17], "dir": 7, "diagram": 7, "sampl": 7, "alia": [7, 13], "infrequ": 7, "constantli": 7, "imposs": 7, "lose": [7, 9, 10, 13, 17], "highli": 7, "bashrc": 7, "introductori": 8, "philosophi": 8, "brief": [8, 14], "workflow": [8, 15], "stick": [8, 16], "obsess": 8, "2": [8, 13, 17], "28": 8, "newer": 8, "workaround": 8, "account": 8, "Being": 8, "expertis": 8, "mostli": 8, "familiar": [8, 17], "advic": 8, "interrupt": 8, "hood": 8, "quick": [8, 18], "custom": 8, "resourc": 8, "exercis": [8, 14, 17], "guid": [8, 15], "bitbucket": [8, 11, 14], "transfer": 8, "materi": 8, "implicitli": 8, "endors": 8, "compani": 8, "chosen": 8, "concept": 8, "popular": [8, 11, 14], "host": 8, "panick": 9, "fresh": 9, "beauti": 9, "world": 9, "chaotic": [9, 18], "jackson": 9, "pollock": 9, "spree": 9, "27": 9, "everywher": [9, 18], "ruin": 9, "easiest": 9, "place": [9, 13, 14, 16], "temporarili": 9, "filenam": 9, "drop": 9, "whichev": 9, "stack": [9, 12], "batch": 9, "resum": 9, "overlook": 9, "week": [9, 18], "typic": 10, "untest": 10, "protect": 10, "somefil": 10, "otherwis": 10, "split": [10, 13, 16, 18], "dai": 10, "smaller": 10, "size": [10, 18], "huge": [10, 12, 18], "imperfect": 10, "simplifi": [10, 11], "repair": 10, "fit": 10, "grow": [10, 18], "beginn": 10, "input": 10, "advoc": 11, "distribut": [11, 14], "recogn": 11, "hopefulli": [11, 17], "send": 11, "latest": [11, 12], "paper": 11, "laptop": 11, "thesi": 11, "interf": 11, "src": 11, "util": 11, "time_iso8601": 11, "august": 11, "permalink": 11, "plain": 11, "suitabl": 11, "manuscript": 11, "latex": 11, "quarto": 11, "tri": [11, 14], "myproject": 11, "zip": 11, "2020": [11, 16], "februari": 11, "2021": 11, "21": [11, 17], "myvers": 11, "newfeatur": 11, "despit": 11, "benefit": 11, "honest": 11, "worth": 11, "career": 11, "skill": 11, "worst": 11, "server": [11, 13, 14], "offlin": 11, "subvers": 11, "mercuri": 11, "pijul": 11, "undon": 12, "perman": [12, 13], "retriev": [12, 17], "unlik": 12, "xkcd": [12, 15], "comic": 12, "impli": [12, 16], "1597": 12, "mess": 12, "matter": 12, "overflow": 12, "guru": 12, "sim": 12, "resouc": 12, "dot": 12, "remain": 12, "ll": [12, 14], "forgot": [12, 16], "forc": [12, 14], "stuff": [12, 16], "went": 12, "cherri": 12, "pick": [12, 16], "oldest": 12, "wrongli": 12, "recoveri": [12, 14], "workspac": 13, "roughli": 13, "hold": 13, "consist": 13, "setup": 13, "around": 14, "snapshot": 14, "disk": 14, "steal": 14, "tast": 14, "prepar": [14, 16], "emploi": 14, "join": 14, "clarifi": 14, "commerci": 14, "univers": 14, "privat": 14, "notabug": 14, "nordic": 14, "classic": 14, "method": 14, "secur": 14, "credenti": 14, "mac": 14, "successfulli": 14, "yourself": [14, 18], "watch": 14, "licens": [14, 17], "none": 14, "button": 14, "execut": 14, "enumer": 14, "100": 14, "221": 14, "byte": 14, "kib": 14, "total": 14, "pack": [14, 16], "reload": 14, "taa": 14, "daa": 14, "upload": 14, "explan": 14, "ran": 14, "brand": 14, "adapt": 14, "pai": [14, 16], "attent": 14, "target": 14, "myrecip": 14, "download": 14, "revisit": 14, "serv": 14, "full": 14, "properli": 14, "scott": 15, "chacon": 15, "ben": 15, "straub": 15, "peepcod": 15, "mid": 15, "demystifi": 16, "came": [16, 18], "stand": 16, "hardli": 16, "organ": 16, "five": 16, "advantag": 16, "disadvantag": 16, "b135ec8": 16, "c": 16, "6f0d49f": 16, "implement": [16, 17], "fee1807": 16, "6fe2f23": 16, "ab990f4": 16, "miscellan": 16, "bf39f9d": 16, "45831a5": 16, "bddb280": 16, "72d78e7": 16, "72e0211": 16, "61dd3a3": 16, "bugfix": 16, "49dc419": 16, "wip": 16, "progress": 16, "1949dc4": 16, "04": 16, "07": 16, "a361dd3": 16, "06": 16, "1172e02": 16, "03": 16, "e772d78": 16, "02": 16, "spread": 16, "simplest": 16, "y": 16, "blank": 16, "sort": 16, "shot": 16, "somehow": 16, "analogi": 16, "shop": 16, "receipt": 16, "wouldn": 16, "item": 16, "bathroom": 16, "kitchen": 16, "room": 16, "correspond": 16, "seal": 16, "dev": 16, "sublimegeek": 16, "im": 16, "1anh": 16, "bui": 16, "ineffici": 16, "annoi": 16, "basket": 16, "conveyor": 16, "belt": 16, "ground": 16, "importantli": 16, "complex": 16, "flexibl": 16, "extrem": 17, "drwxr": 17, "xr": 17, "x": 17, "aug": 17, "51": 17, "rw": 17, "499": 17, "commit_editmsg": 17, "92": 17, "73": 17, "hook": 17, "137": 17, "fact": 17, "previous": 17, "wrote": 17, "referenc": 17, "sha": 17, "1": 17, "hexadecim": 17, "BY": 17, "ca": 17, "digest": 17, "poke": 17, "raw": 17, "explor": 17, "lift": 17, "aha": 17, "underli": 17, "41": 17, "54": 17, "045e3db14740c60684d745e5fb891ae71e335611": 17, "replic": 17, "cp": 17, "gotcha": 18, "ugli": 18, "ish": 18, "harder": 18, "Not": 18, "wors": 18, "meantim": 18, "largest": 18, "counterpoint": 18, "big": 18, "phase": 18, "ambiti": 18, "engin": 18, "safeguard": 18, "restrict": 18, "loop": 18, "significantli": 18, "subsequ": 18, "detect": 18, "autom": 18, "season": 18, "miss": 18}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"alias": 0, "configur": [0, 2], "object": [0, 1, 2, 3, 4, 9, 11, 12, 14, 16, 17], "exampl": 0, "alia": [0, 3], "git": [0, 1, 2, 4, 5, 6, 8, 10, 11, 12, 16, 17], "graph": [0, 7], "us": [0, 1, 2, 4, 5, 6, 7, 13, 16], "extern": 0, "command": [0, 1, 2, 6, 13, 16], "food": 0, "thought": 0, "when": [0, 1, 4, 6, 10], "list": [0, 6], "instructor": [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 16, 17], "advanc": [0, 2], "keypoint": [0, 1, 2, 3, 4, 9, 10, 14, 16], "inspect": [1, 6, 7], "histori": [1, 2, 6, 7, 12, 16], "note": [1, 2, 3, 4, 5, 9, 10, 11, 12, 14, 16, 17], "prepar": [1, 4], "our": [1, 4, 6, 12, 14], "toolbox": 1, "warm": 1, "up": 1, "browser": [1, 2, 6, 14], "search": 1, "text": 1, "pattern": 1, "repositori": [1, 2, 14], "individu": 1, "commit": [1, 2, 3, 6, 10, 12, 16], "line": [1, 2, 6], "code": [1, 11], "annot": 1, "metadata": 1, "discuss": [1, 2, 4, 10, 11, 14, 16, 17, 18], "past": 1, "exercis": [1, 2, 3, 4, 6, 7, 9, 12, 16], "basic": [1, 2, 6, 17], "archaeologi": [1, 6], "1": [1, 2, 3, 4, 6, 7, 9, 12, 16], "explor": [1, 6], "solut": [1, 2, 3, 4, 6, 9, 11, 12, 16], "find": [1, 6], "out": 1, "someth": 1, "broke": 1, "chang": [1, 2, 4, 6, 10, 11, 12], "bisect": [1, 6], "how": [1, 7, 8, 10], "would": 1, "you": [1, 3, 4, 9, 10, 14], "solv": 1, "thi": [1, 6, 7, 12], "option": [1, 2, 3, 4, 6, 8, 9], "2": [1, 2, 3, 4, 6, 7, 9, 12, 16], "bad": [1, 6], "what": [2, 10, 11, 18], "i": [2, 3, 10, 11, 12, 16, 17], "record": [2, 6], "snapshot": [2, 11], "question": 2, "more": [2, 5], "particip": 2, "type": 2, "along": 2, "track": [2, 8, 11], "guacamol": 2, "recip": [2, 14], "creat": [2, 3, 4, 6, 7, 9], "ad": [2, 12], "file": 2, "log": [2, 7], "compar": [2, 6], "show": [2, 6], "3": [2, 3, 4, 6, 12], "visual": [2, 6, 12], "diff": [2, 5, 6], "tool": [2, 6, 11], "4": [2, 3, 6, 12], "write": 2, "messag": 2, "ignor": 2, "path": 2, "gitignor": 2, "graphic": 2, "user": 2, "interfac": 2, "summari": [2, 3, 6], "5": [2, 3, 6], "test": [2, 3, 6, 7, 12], "your": [2, 3, 6, 7, 12, 14], "understand": [2, 3, 6, 7, 12], "branch": [3, 4, 6, 9, 10, 11, 12, 17], "merg": [3, 4, 6, 11, 12], "motiv": [3, 6, 11], "an": [3, 6, 14, 16], "import": 3, "work": [3, 6, 8, 9], "It": [3, 12], "possibl": [3, 12], "directli": 3, "github": [3, 8, 14], "If": [3, 4, 14], "got": [3, 4], "stuck": [3, 4], "abov": 3, "join": [3, 4], "later": [3, 4], "delet": 3, "safe": 3, "perform": [3, 6, 16], "fast": [3, 6], "forward": [3, 6], "rebas": [3, 4, 6], "instead": [3, 6], "tag": 3, "typic": [3, 11], "workflow": 3, "conflict": [4, 6, 12], "resolut": [4, 6], "why": [4, 7, 8, 11], "thei": 4, "ar": [4, 10], "good": 4, "The": [4, 16], "human": 4, "side": 4, "previous": 4, "step": [4, 6, 7, 16], "resolv": [4, 6], "anoth": [4, 6, 11], "mergetool": [4, 6], "theirs": 4, "strategi": 4, "abort": 4, "avoid": [4, 18], "custom": 5, "shell": 5, "prompt": 5, "output": 5, "full": 6, "stage": [6, 10, 16], "area": [6, 16], "interact": [6, 16], "make": [6, 16], "two": [6, 16], "undo": [6, 12], "recov": [6, 12], "revert": [6, 12], "modifi": [6, 12], "previou": [6, 12, 14], "destroi": [6, 12], "experiment": [6, 12], "episod": [6, 8, 12, 14], "interrupt": [6, 9], "stash": [6, 9], "some": [6, 9], "uncommit": [6, 9, 12], "guid": 7, "schedul": 7, "dai": 7, "instal": 7, "remind": 7, "each": [7, 10], "we": [7, 8, 11, 13], "teach": 7, "lesson": 7, "intend": 7, "learn": 7, "outcom": 7, "take": 7, "first": 7, "editor": 7, "slowli": 7, "live": 7, "better": 7, "than": 7, "read": 7, "websit": 7, "materi": 7, "separ": 7, "window": 7, "cheatsheet": [7, 13], "board": 7, "draw": 7, "repeat": 7, "follow": 7, "point": 7, "start": [7, 14], "from": [7, 12, 14], "ident": 7, "environ": 7, "introduct": 8, "version": [8, 11], "control": [8, 11], "want": [8, 9], "go": 8, "back": [8, 11], "time": 8, "prerequisit": 8, "core": 8, "refer": [8, 13], "about": [8, 10, 11], "frequent": 9, "situat": 9, "store": 9, "variou": 9, "junk": 9, "don": [9, 14], "t": [9, 14], "need": [9, 11], "get": 9, "rid": 9, "practic": 10, "advic": 10, "much": 10, "necessari": 10, "level": 10, "complex": 10, "project": 10, "simpl": 10, "person": 10, "few": 10, "accept": 10, "thing": 10, "break": 10, "sometim": 10, "review": 10, "other": [10, 13, 15], "distribut": 10, "releas": 10, "larg": 10, "should": 10, "all": 11, "keep": 11, "do": 11, "featur": 11, "roll": 11, "collabor": 11, "reproduc": 11, "talk": 11, "like": 11, "difficulti": 11, "almost": 12, "alwai": 12, "nice": 12, "resourc": [12, 15], "simul": 12, "oper": 12, "recent": 12, "unstag": 12, "preserv": 12, "rewind": 12, "reset": 12, "wrong": 12, "pull": 12, "after": 12, "quick": 13, "glossari": 13, "share": 14, "onlin": 14, "laptop": 14, "web": 14, "remot": 14, "have": 14, "authent": 14, "ssh": 14, "http": 14, "publish": 14, "exist": 14, "noth": 14, "yet": 14, "troubleshoot": 14, "clone": 14, "tell": 16, "stori": 16, "under": 17, "hood": 17, "down": 17, "rabbit": 17, "hole": 17, "content": 17, "address": 17, "storag": 17, "system": 17, "demonstr": 17, "experi": 17}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Aliases and configuration": [[0, "aliases-and-configuration"]], "Objectives": [[0, "objectives-0"], [1, "objectives-0"], [2, "objectives-0"], [3, "objectives-0"], [4, "objectives-0"], [9, "objectives-0"], [11, "objectives-0"], [12, "objectives-0"], [14, "objectives-0"], [16, "objectives-0"], [17, "objectives-0"]], "Aliases": [[0, "aliases"]], "Example alias: git graph": [[0, "example-alias-git-graph"]], "Using external commands": [[0, "using-external-commands"]], "Food for thought: When to alias?": [[0, "discussion-0"]], "List of aliases the instructors use": [[0, "list-of-aliases-the-instructors-use"]], "Advanced aliases": [[0, "advanced-aliases"]], "Advanced Git configuration": [[0, "advanced-git-configuration"]], "Keypoints": [[0, "keypoints-0"], [1, "keypoints-0"], [2, "keypoints-0"], [3, "keypoints-0"], [4, "keypoints-0"], [9, "keypoints-0"], [10, "keypoints-0"], [14, "keypoints-0"], [16, "keypoints-0"]], "Inspecting history": [[1, "inspecting-history"], [6, "inspecting-history"], [7, "inspecting-history"]], "Instructor note": [[1, "instructor-note-0"], [1, "instructor-note-1"], [2, "instructor-note-0"], [2, "instructor-note-1"], [2, "instructor-note-2"], [3, "instructor-note-0"], [3, "instructor-note-1"], [3, "instructor-note-2"], [4, "instructor-note-0"], [4, "instructor-note-1"], [5, "instructor-note-0"], [9, "instructor-note-0"], [10, "instructor-note-0"], [11, "instructor-note-0"], [12, "instructor-note-0"], [14, "instructor-note-0"], [16, "instructor-note-0"], [16, "instructor-note-1"], [17, "instructor-note-0"]], "Preparation": [[1, "prerequisites-0"]], "Our toolbox for history inspection": [[1, "our-toolbox-for-history-inspection"]], "Warm-up: \u201cGit History\u201d browser": [[1, "warm-up-git-history-browser"]], "Searching text patterns in the repository": [[1, "searching-text-patterns-in-the-repository"]], "Inspecting individual commits": [[1, "inspecting-individual-commits"]], "Line-by-line code annotation with metadata": [[1, "line-by-line-code-annotation-with-metadata"]], "Discussion": [[1, "discussion-0"], [2, "discussion-1"], [4, "discussion-1"], [10, "discussion-0"], [11, "discussion-0"], [14, "discussion-0"], [16, "discussion-0"], [16, "discussion-1"], [16, "discussion-2"], [17, "discussion-0"], [18, "discussion-0"]], "Inspecting code in the past": [[1, "inspecting-code-in-the-past"]], "Exercise: Basic archaeology commands": [[1, "exercise-basic-archaeology-commands"]], "History-1: Explore basic archaeology commands": [[1, "exercise-0"], [6, "exercise-0"]], "Solution": [[1, "solution-0"], [2, "solution-0"], [3, "solution-0"], [3, "solution-1"], [3, "solution-2"], [4, "solution-0"], [4, "solution-1"], [6, "solution-0"], [6, "solution-0"], [6, "solution-0"], [6, "solution-1"], [6, "solution-2"], [6, "solution-0"], [6, "solution-1"], [6, "solution-0"], [6, "solution-0"], [6, "solution-0"], [6, "solution-1"], [6, "solution-0"], [9, "solution-0"], [11, "solution-0"], [12, "solution-0"], [12, "solution-1"], [16, "solution-0"]], "Finding out when something broke/changed with git bisect": [[1, "finding-out-when-something-broke-changed-with-git-bisect"]], "How would you solve this?": [[1, "discussion-1"]], "Optional exercise: Git bisect": [[1, "optional-exercise-git-bisect"]], "(optional) History-2: Use git bisect to find the bad commit": [[1, "exercise-1"], [6, "exercise-1"]], "Basics": [[2, "basics"], [6, "basics"]], "What is Git, and what is a Git repository?": [[2, "what-is-git-and-what-is-a-git-repository"]], "Recording a snapshot with Git": [[2, "recording-a-snapshot-with-git"]], "Question for the more advanced participants": [[2, "discussion-0"]], "Configuring Git command line": [[2, "configuring-git-command-line"]], "Type-along: Tracking a guacamole recipe with Git": [[2, "type-along-tracking-a-guacamole-recipe-with-git"]], "Creating a repository": [[2, "creating-a-repository"]], "Adding files and committing changes": [[2, "adding-files-and-committing-changes"]], "Exercise: Record changes": [[2, "exercise-record-changes"]], "Basic-1: Record changes": [[2, "exercise-0"], [6, "exercise-0"]], "Git history and log": [[2, "git-history-and-log"]], "Optional exercises: Comparing changes": [[2, "optional-exercises-comparing-changes"]], "(optional) Basic-2: Comparing and showing commits": [[2, "exercise-1"], [6, "exercise-1"]], "(optional) Basic-3: Visual diff tools": [[2, "exercise-2"], [6, "exercise-2"]], "(optional) Basic-4: Browser and command line": [[2, "exercise-3"], [6, "exercise-3"]], "Writing useful commit messages": [[2, "writing-useful-commit-messages"]], "Ignoring files and paths with .gitignore": [[2, "ignoring-files-and-paths-with-gitignore"]], "Graphical user interfaces": [[2, "graphical-user-interfaces"]], "Summary": [[2, "summary"], [3, "summary"], [6, "summary"]], "Basic-5: Test your understanding": [[2, "exercise-4"], [6, "exercise-4"]], "Branching and merging": [[3, "branching-and-merging"], [6, "branching-and-merging"]], "Motivation for branches": [[3, "motivation-for-branches"]], "An important alias": [[3, null]], "Creating and working with branches": [[3, "creating-and-working-with-branches"]], "It is possible to create and merge branches directly on GitHub": [[3, null]], "Exercise: Create and commit to branches": [[3, "exercise-create-and-commit-to-branches"]], "Branch-1: Create and commit to branches": [[3, "exercise-0"], [6, "exercise-0"]], "Exercise: Merging branches": [[3, "exercise-merging-branches"]], "Branch-2: Merge branches": [[3, "exercise-1"], [6, "exercise-1"]], "If you got stuck in the above exercises or joined later": [[3, null]], "Deleting branches safely": [[3, "deleting-branches-safely"]], "Optional exercises with branches": [[3, "optional-exercises-with-branches"]], "(optional) Branch-3: Perform a fast-forward merge": [[3, "exercise-2"], [6, "exercise-2"]], "(optional) Branch-4: Rebase a branch (instead of merge)": [[3, "exercise-3"], [6, "exercise-3"]], "Tags": [[3, "tags"]], "Typical workflows": [[3, "typical-workflows"]], "Branch-5: Test your understanding": [[3, "exercise-4"], [6, "exercise-4"]], "Conflict resolution": [[4, "conflict-resolution"], [4, "id2"], [6, "conflict-resolution"]], "Conflicts in Git and why they are good": [[4, "conflicts-in-git-and-why-they-are-good"]], "The human side of conflicts": [[4, "discussion-0"]], "Preparing a conflict": [[4, "preparing-a-conflict"]], "If you got stuck previously or joined later": [[4, null]], "Merging conflicting changes": [[4, "merging-conflicting-changes"]], "Steps to resolve a conflict": [[4, null]], "Exercise: Create and resolve a conflict": [[4, "exercise-create-and-resolve-a-conflict"]], "Conflict-1: Create another conflict and resolve": [[4, "exercise-0"], [6, "exercise-0"]], "Optional exercises with conflict resolution": [[4, "optional-exercises-with-conflict-resolution"]], "(optional) Conflict-2: Resolve a conflict when rebasing a branch": [[4, "exercise-1"], [6, "exercise-1"]], "(optional) Conflict-3: Resolve a conflict using mergetool": [[4, "exercise-2"], [6, "exercise-2"]], "Using \u201cours\u201d or \u201ctheirs\u201d strategy": [[4, "using-ours-or-theirs-strategy"]], "Aborting a conflicting merge": [[4, "aborting-a-conflicting-merge"]], "Avoiding conflicts": [[4, "avoiding-conflicts"]], "Customizing Git": [[5, "customizing-git"]], "Shell prompt": [[5, "shell-prompt"]], "More useful \u201cdiff\u201d output": [[5, "more-useful-diff-output"]], "List of exercises": [[6, "list-of-exercises"]], "Full list": [[6, "full-list"]], "Motivation": [[6, "motivation"], [11, "motivation"]], "Using the Git staging area": [[6, "using-the-git-staging-area"], [16, "using-the-git-staging-area"]], "Staging-1: Perform an interactive commit": [[6, "exercise-0"], [16, "exercise-0"]], "Staging-2: Use the staging area to make a commit in two steps": [[6, "exercise-1"], [16, "exercise-1"]], "Undoing and recovering": [[6, "undoing-and-recovering"], [12, "undoing-and-recovering"]], "Undoing-1: Revert a commit": [[6, "exercise-0"], [12, "exercise-0"]], "Undoing-2: Modify a previous commit": [[6, "exercise-1"], [12, "exercise-1"]], "Undoing-3: Destroy our experimentation in this episode": [[6, "exercise-2"], [12, "exercise-2"]], "Undoing-4: Test your understanding": [[6, "exercise-3"], [12, "exercise-3"]], "Interrupted work": [[6, "interrupted-work"], [9, "interrupted-work"]], "Interrupted-1: Stash some uncommitted work": [[6, "exercise-0"], [9, "exercise-0"]], "Instructor guide": [[7, "instructor-guide"]], "Schedule Day 1": [[7, "schedule-day-1"]], "Schedule Day 2": [[7, "schedule-day-2"]], "Installation reminders for each day": [[7, "installation-reminders-for-each-day"]], "Why we teach this lesson": [[7, "why-we-teach-this-lesson"]], "Intended learning outcomes": [[7, "intended-learning-outcomes"]], "How to teach this lesson": [[7, "how-to-teach-this-lesson"]], "Take first editor steps slowly": [[7, "take-first-editor-steps-slowly"]], "How to use the exercises": [[7, "how-to-use-the-exercises"]], "\u201cTest your understanding\u201d exercises": [[7, "test-your-understanding-exercises"]], "Live better than reading the website material": [[7, "live-better-than-reading-the-website-material"]], "Log your history in a separate window": [[7, "log-your-history-in-a-separate-window"]], "Create a cheatsheet on the board": [[7, "create-a-cheatsheet-on-the-board"]], "Draw a graph on the board": [[7, "draw-a-graph-on-the-board"]], "Repeat the following points": [[7, "repeat-the-following-points"]], "Start from identical environment": [[7, "start-from-identical-environment"]], "Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version": [[8, "introduction-to-version-control-with-git-why-we-want-to-track-versions-and-how-to-go-back-in-time-to-a-working-version"]], "Prerequisites": [[8, "prerequisites-0"]], "Core episodes": [[8, null]], "Optional episodes": [[8, null]], "Reference": [[8, null]], "About": [[8, null]], "Why GitHub?": [[8, null]], "Frequent situation: interrupted work": [[9, "frequent-situation-interrupted-work"]], "Option 1: Stashing": [[9, "option-1-stashing"]], "Exercise: Stashing": [[9, "exercise-stashing"]], "Option 2: Create branches": [[9, "option-2-create-branches"]], "Storing various junk you don\u2019t need but don\u2019t want to get rid of": [[9, "storing-various-junk-you-don-t-need-but-don-t-want-to-get-rid-of"]], "Practical advice: how much Git is necessary?": [[10, "practical-advice-how-much-git-is-necessary"]], "What level of branching complexity is necessary for each project?": [[10, "what-level-of-branching-complexity-is-necessary-for-each-project"]], "Simple personal projects": [[10, "simple-personal-projects"]], "Projects with few persons: you accept things breaking sometimes": [[10, "projects-with-few-persons-you-accept-things-breaking-sometimes"]], "Projects with few persons: changes are reviewed by others": [[10, "projects-with-few-persons-changes-are-reviewed-by-others"]], "When you distribute releases": [[10, "when-you-distribute-releases"]], "How about staging and committing?": [[10, "how-about-staging-and-committing"]], "How large should a commit be?": [[10, "how-large-should-a-commit-be"]], "Git is all about keeping track of changes": [[11, "git-is-all-about-keeping-track-of-changes"]], "Why do we need to keep track of versions?": [[11, "why-do-we-need-to-keep-track-of-versions"]], "Features: roll-back, branching, merging, collaboration": [[11, "features-roll-back-branching-merging-collaboration"]], "Reproducibility": [[11, "reproducibility"]], "Talking about code": [[11, "talking-about-code"]], "What we typically like to snapshot": [[11, "what-we-typically-like-to-snapshot"]], "Difficulties of version control": [[11, "difficulties-of-version-control"]], "Why Git and not another tool?": [[11, "discussion-1"]], "It is almost always possible to recover": [[12, null]], "Nice resource to visually simulate Git operation": [[12, null]], "Undoing your recent, uncommitted and unstaged changes (preserves history)": [[12, "undoing-your-recent-uncommitted-and-unstaged-changes-preserves-history"]], "Reverting commits (preserves history)": [[12, "reverting-commits-preserves-history"]], "Exercise: Revert a commit": [[12, "exercise-revert-a-commit"]], "Adding to the previous commit (modifies history)": [[12, "adding-to-the-previous-commit-modifies-history"]], "Exercise: Modify a previous commit": [[12, "exercise-modify-a-previous-commit"]], "Rewinding branches (modifies history)": [[12, "rewinding-branches-modifies-history"]], "Exercise: Git reset": [[12, "exercise-git-reset"]], "Recovering from committing to the wrong branch": [[12, "recovering-from-committing-to-the-wrong-branch"]], "Recovering from merging/pulling into the wrong branch": [[12, "recovering-from-merging-pulling-into-the-wrong-branch"]], "Recovering from conflict after pulling changes": [[12, "recovering-from-conflict-after-pulling-changes"]], "Quick reference": [[13, "quick-reference"]], "Other cheatsheets": [[13, "other-cheatsheets"]], "Glossary": [[13, "glossary"]], "Commands we use": [[13, "commands-we-use"]], "Sharing repositories online": [[14, "sharing-repositories-online"]], "From our laptops to the web": [[14, "from-our-laptops-to-the-web"]], "Remotes": [[14, "remotes"]], "If you don\u2019t have the recipe repository from previous episodes": [[14, null]], "Authenticating to GitHub: SSH or HTTPS?": [[14, "authenticating-to-github-ssh-or-https"]], "Publishing an existing repository from laptop to GitHub": [[14, "publishing-an-existing-repository-from-laptop-to-github"]], "If you started in the browser and have nothing on your laptop yet": [[14, null]], "Troubleshooting": [[14, null]], "Cloning a repository from GitHub to laptop": [[14, "cloning-a-repository-from-github-to-laptop"]], "Other resources": [[15, "other-resources"]], "Commit history is telling a story": [[16, "commit-history-is-telling-a-story"]], "Interactive commits": [[16, "interactive-commits"]], "Exercise: Interactive commits": [[16, "exercise-interactive-commits"]], "The staging area": [[16, "the-staging-area"]], "Staging area commands": [[16, "staging-area-commands"]], "Exercise: Using the staging area": [[16, "exercise-using-the-staging-area"]], "Git under the hood": [[17, "git-under-the-hood"]], "Down the rabbit hole": [[17, "down-the-rabbit-hole"]], "Git is basically a content-addressed storage system": [[17, "git-is-basically-a-content-addressed-storage-system"]], "Demonstration: experimenting with branches": [[17, "demonstration-experimenting-with-branches"]], "What to avoid": [[18, "what-to-avoid"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/branch/2023-version/singlehtml/.buildinfo b/branch/2023-version/singlehtml/.buildinfo new file mode 100644 index 00000000..0e3b2f24 --- /dev/null +++ b/branch/2023-version/singlehtml/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 4202fab30366226cc703d00775a306ce +tags: 33eac41acc08762151beb8f3b7b86c8f diff --git a/branch/2023-version/singlehtml/.nojekyll b/branch/2023-version/singlehtml/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/2023-version/singlehtml/_images/add-file.png b/branch/2023-version/singlehtml/_images/add-file.png new file mode 100644 index 00000000..9683b2db Binary files /dev/null and b/branch/2023-version/singlehtml/_images/add-file.png differ diff --git a/branch/2023-version/singlehtml/_images/annotate.png b/branch/2023-version/singlehtml/_images/annotate.png new file mode 100644 index 00000000..8021920a Binary files /dev/null and b/branch/2023-version/singlehtml/_images/annotate.png differ diff --git a/branch/2023-version/singlehtml/_images/bare-repo.png b/branch/2023-version/singlehtml/_images/bare-repo.png new file mode 100644 index 00000000..1aa5699d Binary files /dev/null and b/branch/2023-version/singlehtml/_images/bare-repo.png differ diff --git a/branch/2023-version/singlehtml/_images/browse-files.png b/branch/2023-version/singlehtml/_images/browse-files.png new file mode 100644 index 00000000..5fcc3528 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/browse-files.png differ diff --git a/branch/2023-version/singlehtml/_images/cheat-sheet.jpg b/branch/2023-version/singlehtml/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/branch/2023-version/singlehtml/_images/cheat-sheet.jpg differ diff --git a/branch/2023-version/singlehtml/_images/code-portion.png b/branch/2023-version/singlehtml/_images/code-portion.png new file mode 100644 index 00000000..39356bd5 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/code-portion.png differ diff --git a/branch/2023-version/singlehtml/_images/commit-and-tree.png b/branch/2023-version/singlehtml/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/branch/2023-version/singlehtml/_images/commit-and-tree.png differ diff --git a/branch/2023-version/singlehtml/_images/commit-changes.png b/branch/2023-version/singlehtml/_images/commit-changes.png new file mode 100644 index 00000000..4c0546c6 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/commit-changes.png differ diff --git a/branch/2023-version/singlehtml/_images/commits-and-parents.png b/branch/2023-version/singlehtml/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/commits-and-parents.png differ diff --git a/branch/2023-version/singlehtml/_images/commits.png b/branch/2023-version/singlehtml/_images/commits.png new file mode 100644 index 00000000..b154c666 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/commits.png differ diff --git a/branch/2023-version/singlehtml/_images/edit-file.png b/branch/2023-version/singlehtml/_images/edit-file.png new file mode 100644 index 00000000..f7527bd0 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/edit-file.png differ diff --git a/branch/2023-version/singlehtml/_images/git-annotate.png b/branch/2023-version/singlehtml/_images/git-annotate.png new file mode 100644 index 00000000..60c6f7c2 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/git-annotate.png differ diff --git a/branch/2023-version/singlehtml/_images/git-branch-1.svg b/branch/2023-version/singlehtml/_images/git-branch-1.svg new file mode 100644 index 00000000..1174a2e9 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-branch-1.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + m2 + + + m3 + + + m1 + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/singlehtml/_images/git-branch-2.svg b/branch/2023-version/singlehtml/_images/git-branch-2.svg new file mode 100644 index 00000000..e3f7abfc --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-branch-2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l1 + + + e2 + + + e1 + + + m5 + + + m4 + + + m2 + + + m3 + + + m1 + + + + + less-salt + + + + + HEAD + + + + + experiment + + + + + main + + + diff --git a/branch/2023-version/singlehtml/_images/git-branch-3.svg b/branch/2023-version/singlehtml/_images/git-branch-3.svg new file mode 100644 index 00000000..8916d588 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-branch-3.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + e2 + + + m3 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + + + less-salt + + + + + experiment + + + diff --git a/branch/2023-version/singlehtml/_images/git-collaborative.svg b/branch/2023-version/singlehtml/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/branch/2023-version/singlehtml/_images/git-deleted-branches.svg b/branch/2023-version/singlehtml/_images/git-deleted-branches.svg new file mode 100644 index 00000000..2b4b3fd5 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-deleted-branches.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + m5 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/singlehtml/_images/git-log-github.png b/branch/2023-version/singlehtml/_images/git-log-github.png new file mode 100644 index 00000000..db44d29b Binary files /dev/null and b/branch/2023-version/singlehtml/_images/git-log-github.png differ diff --git a/branch/2023-version/singlehtml/_images/git-log-terminal.png b/branch/2023-version/singlehtml/_images/git-log-terminal.png new file mode 100644 index 00000000..56493e6e Binary files /dev/null and b/branch/2023-version/singlehtml/_images/git-log-terminal.png differ diff --git a/branch/2023-version/singlehtml/_images/git-merge-1.svg b/branch/2023-version/singlehtml/_images/git-merge-1.svg new file mode 100644 index 00000000..34fd0f87 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-merge-1.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + m3 + + + l1 + + + m7 + + + m4 + + + + + experiment + + + + + less-salt + + + + + main + + + + + HEAD + + + diff --git a/branch/2023-version/singlehtml/_images/git-merge-2.svg b/branch/2023-version/singlehtml/_images/git-merge-2.svg new file mode 100644 index 00000000..5f5fd6a7 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-merge-2.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + l1 + + + m5 + + + m4 + + + + + experiment + + + + + main + + + + + HEAD + + + + + less-salt + + + diff --git a/branch/2023-version/singlehtml/_images/git-pre-ff.svg b/branch/2023-version/singlehtml/_images/git-pre-ff.svg new file mode 100644 index 00000000..df06fc7e --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git-pre-ff.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e1 + + + e2 + + + m7 + + + m8 + + + n3 + + + n1 + + + m5 + + + l1 + + + m6 + + + m4 + + + n2 + + + m2 + + + m3 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + main + + + diff --git a/branch/2023-version/singlehtml/_images/git_stage_commit.svg b/branch/2023-version/singlehtml/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/2023-version/singlehtml/_images/gophers.png b/branch/2023-version/singlehtml/_images/gophers.png new file mode 100644 index 00000000..741406ba Binary files /dev/null and b/branch/2023-version/singlehtml/_images/gophers.png differ diff --git a/branch/2023-version/singlehtml/_images/history.png b/branch/2023-version/singlehtml/_images/history.png new file mode 100644 index 00000000..6384e302 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/history.png differ diff --git a/branch/2023-version/singlehtml/_images/meld.png b/branch/2023-version/singlehtml/_images/meld.png new file mode 100644 index 00000000..774f9cd1 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/meld.png differ diff --git a/branch/2023-version/singlehtml/_images/mergetool.png b/branch/2023-version/singlehtml/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/mergetool.png differ diff --git a/branch/2023-version/singlehtml/_images/new-bare-repo-form.png b/branch/2023-version/singlehtml/_images/new-bare-repo-form.png new file mode 100644 index 00000000..939e4f84 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/new-bare-repo-form.png differ diff --git a/branch/2023-version/singlehtml/_images/new-repo-form.png b/branch/2023-version/singlehtml/_images/new-repo-form.png new file mode 100644 index 00000000..b808ee0b Binary files /dev/null and b/branch/2023-version/singlehtml/_images/new-repo-form.png differ diff --git a/branch/2023-version/singlehtml/_images/new-repo-plus.png b/branch/2023-version/singlehtml/_images/new-repo-plus.png new file mode 100644 index 00000000..e58ba5d8 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/new-repo-plus.png differ diff --git a/branch/2023-version/singlehtml/_images/pen-symbol.png b/branch/2023-version/singlehtml/_images/pen-symbol.png new file mode 100644 index 00000000..044902a3 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/pen-symbol.png differ diff --git a/branch/2023-version/singlehtml/_images/preview.png b/branch/2023-version/singlehtml/_images/preview.png new file mode 100644 index 00000000..8a602b66 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/preview.png differ diff --git a/branch/2023-version/singlehtml/_images/search.png b/branch/2023-version/singlehtml/_images/search.png new file mode 100644 index 00000000..4462f71e Binary files /dev/null and b/branch/2023-version/singlehtml/_images/search.png differ diff --git a/branch/2023-version/singlehtml/_images/show.png b/branch/2023-version/singlehtml/_images/show.png new file mode 100644 index 00000000..12d7915c Binary files /dev/null and b/branch/2023-version/singlehtml/_images/show.png differ diff --git a/branch/2023-version/singlehtml/_images/staging-basics.svg b/branch/2023-version/singlehtml/_images/staging-basics.svg new file mode 100644 index 00000000..13df8bf5 --- /dev/null +++ b/branch/2023-version/singlehtml/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + restore + add + commit + restore + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/branch/2023-version/singlehtml/_images/stranger.jpg b/branch/2023-version/singlehtml/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/branch/2023-version/singlehtml/_images/stranger.jpg differ diff --git a/branch/2023-version/singlehtml/_static/_sphinx_javascript_frameworks_compat.js b/branch/2023-version/singlehtml/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/branch/2023-version/singlehtml/_static/basic.css b/branch/2023-version/singlehtml/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/check-solid.svg b/branch/2023-version/singlehtml/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/2023-version/singlehtml/_static/clipboard.min.js b/branch/2023-version/singlehtml/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/branch/2023-version/singlehtml/_static/copybutton.css b/branch/2023-version/singlehtml/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/branch/2023-version/singlehtml/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/branch/2023-version/singlehtml/_static/copybutton.js b/branch/2023-version/singlehtml/_static/copybutton.js new file mode 100644 index 00000000..f3ecd034 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/copybutton.js @@ -0,0 +1,241 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos, .gp'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/copybutton_funcs.js b/branch/2023-version/singlehtml/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/branch/2023-version/singlehtml/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/branch/2023-version/singlehtml/_static/css/badge_only.css b/branch/2023-version/singlehtml/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.eot b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.svg b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.ttf b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-bold.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff differ diff --git a/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff2 b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/css/fonts/lato-normal.woff2 differ diff --git a/branch/2023-version/singlehtml/_static/css/theme.css b/branch/2023-version/singlehtml/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/doctools.js b/branch/2023-version/singlehtml/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/branch/2023-version/singlehtml/_static/documentation_options.js b/branch/2023-version/singlehtml/_static/documentation_options.js new file mode 100644 index 00000000..89003c67 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'singlehtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/file.png b/branch/2023-version/singlehtml/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/file.png differ diff --git a/branch/2023-version/singlehtml/_static/jquery.js b/branch/2023-version/singlehtml/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/branch/2023-version/singlehtml/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/js/html5shiv.min.js b/branch/2023-version/singlehtml/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/branch/2023-version/singlehtml/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/js/theme.js b/branch/2023-version/singlehtml/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/branch/2023-version/singlehtml/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/branch/2023-version/singlehtml/_static/minipres.js b/branch/2023-version/singlehtml/_static/minipres.js new file mode 100644 index 00000000..ad11c871 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/branch/2023-version/singlehtml/_static/minus.png b/branch/2023-version/singlehtml/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/branch/2023-version/singlehtml/_static/minus.png differ diff --git a/branch/2023-version/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/branch/2023-version/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 00000000..33566310 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/branch/2023-version/singlehtml/_static/plus.png b/branch/2023-version/singlehtml/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/branch/2023-version/singlehtml/_static/plus.png differ diff --git a/branch/2023-version/singlehtml/_static/pygments.css b/branch/2023-version/singlehtml/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/searchtools.js b/branch/2023-version/singlehtml/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/branch/2023-version/singlehtml/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/branch/2023-version/singlehtml/_static/sphinx_highlight.js b/branch/2023-version/singlehtml/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/branch/2023-version/singlehtml/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/branch/2023-version/singlehtml/_static/sphinx_lesson.css b/branch/2023-version/singlehtml/_static/sphinx_lesson.css new file mode 100644 index 00000000..14b20c64 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/branch/2023-version/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css b/branch/2023-version/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css new file mode 100644 index 00000000..e68feb82 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css @@ -0,0 +1,47 @@ +/* The following are for web accessibility of sphinx_rtd_theme: they + * solve some of the most frequent contrast issues. Remove when this + * solved: + * https://github.com/readthedocs/sphinx_rtd_theme/issues/971 + */ +/* background: #fcfcfc, note boxes #E7F2FA */ +a { color: #2573A7; } /* original #2980B9, #1F5C84; */ +body { color: #242424; } /* original #404040, #383838 */ +.wy-side-nav-search>a, .wy-side-nav-search .wy-dropdown>a { + color: #ffffff; +} /* original #fcfcfc */ +footer { color: #737373; } /* original gray=#808080*/ +footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { + color: #737373; +} /* original gray=#808080*/ +.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { + color: #AB2314; +} +/* Sidebar background */ +.wy-side-nav-search { background-color: #277CB4;} + +/* Same, but for pygments */ +.highlight .ch { color: #3E7A89; } /* #! line */ +.highlight .c1 { color: #3E7A89; } /* also comments */ +.highlight .nv { color: #AD3ECC; } /* variable */ +.highlight .gp { color: #B45608; } /* prompt character, $*/ +.highlight .si { color: #3975B1; } /* ${} variable text */ +.highlight .nc { color: #0C78A7; } + +/* Sphinx admonitions */ +/* warning */ +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { + background: #B15E16; } +/* important */ +.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { + background: #12826C; } +/* seealso, note, etc */ +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { + background: #277CB4; } +/* error, danger */ +.rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { + background: #e31704; +} + +/* Generic admonition titles */ +.wy-alert-title, .rst-content .admonition-title { + background: #277CB4; } diff --git a/branch/2023-version/singlehtml/_static/tabs.css b/branch/2023-version/singlehtml/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/branch/2023-version/singlehtml/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/branch/2023-version/singlehtml/_static/tabs.js b/branch/2023-version/singlehtml/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/branch/2023-version/singlehtml/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/branch/2023-version/singlehtml/_static/term_role_formatting.css b/branch/2023-version/singlehtml/_static/term_role_formatting.css new file mode 100644 index 00000000..0b66095c --- /dev/null +++ b/branch/2023-version/singlehtml/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/branch/2023-version/singlehtml/_static/togglebutton.css b/branch/2023-version/singlehtml/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/branch/2023-version/singlehtml/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/branch/2023-version/singlehtml/_static/togglebutton.js b/branch/2023-version/singlehtml/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/branch/2023-version/singlehtml/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/branch/2023-version/singlehtml/index.html b/branch/2023-version/singlehtml/index.html new file mode 100644 index 00000000..68c9ea51 --- /dev/null +++ b/branch/2023-version/singlehtml/index.html @@ -0,0 +1,4193 @@ + + + + + + + Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version

+

This is the introductory lesson to version control using +Git. It is assumed to be the very first thing +done in a course.

+

Our philosophy is that we start from own local repository, branching and +merging (locally), and a brief introduction to pushing to remotes. In +the separate collaborative Git +lesson, we teach more use of +remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with +Git to be able to work well. We try to avoid commands which might get +you into a confusing state.

+

The goals of the module as a whole are that the user will feel +comfortable about staging changes, committing them, merging, and +branching.

+
+

Prerequisites

+
    +
  • A reasonably recent version of Git (ideal is 2.28 or newer but we +recommend at least 2.23) is installed and configured (installation +instructions). But also on older +Git (2.0) the workshop will work and we will offer workarounds for Git below 2.28 +or 2.23.

  • +
  • For one of the episodes we need a GitHub user +account (but alternatives exist, see below).

  • +
  • Being comfortable with the command line. No expertise is required, but +the lesson will be mostly taken from the command line. For most commands, where reasonable, +we also offer the possibility to participate through the browser.

  • +
  • To edit files on the local computer, learners should be familiar with +using a text editor on their system. If you are new to text editors, +we recommend to start with Nano or VS Code.

  • +
+
+
+
+

Motivation

+
+

Objectives

+
    +
  • Make sure nobody leaves the workshop without starting to use some form of version control.

  • +
  • Discuss the reasons why we advocate distributed version control.

  • +
+
+
+

Instructor note

+
    +
  • 15 min teaching/demonstration

  • +
+
+
+

Git is all about keeping track of changes

+

We will learn how to keep track of changes first in a terminal (example +repository):

+
+Screenshot of a git log in terminal +
+

Later also via web interface (example +repository):

+
+Screenshot of a git log on GitHub +
+
+
+

Why do we need to keep track of versions?

+

Version control is an answer to these questions (do you recognize some of them?):

+
    +
  • “It broke … hopefully I have a working version somewhere?”

  • +
  • “Can you please send me the latest version?”

  • +
  • “Where is the latest version?”

  • +
  • “Which version are you using?”

  • +
  • “Which version have the authors used in the paper I am trying to reproduce?”

  • +
  • “Found a bug! Since when was it there?”

  • +
  • “I am sure it used to work. When did it change?”

  • +
  • “My laptop is gone. Is my thesis now gone?”

  • +
+
+
+

Features: roll-back, branching, merging, collaboration

+
    +
  • Roll-back: you can always go back to a previous version and compare

  • +
  • Branching and merging:

    +
      +
    • Work on different ideas at the same time

    • +
    • Different people can work on the same code/project without interfering

    • +
    • You can experiment with an idea and discard it if it turns out to be a bad idea

    • +
    +
  • +
+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+ +
+
+

Reproducibility

+
    +
  • How do you indicate which version of your code you have used in your paper?

  • +
  • When you find a bug, how do you know when precisely this bug was introduced +(Are published results affected? Do you need to inform collaborators or users of your code?).

  • +
+

With version control we can “annotate” code (browse this example online):

+
+Example of a git-annotated code with code and history side-by-side +
+

Example of a git-annotated code with code and history side-by-side.

+
+
+
+
+

Talking about code

+

Which of these two is more practical?

+
    +
  • “Clone the code, go to the file ‘src/util.rs’, and search for ‘time_iso8601’”. +Oh! But make sure you use the version from August 2023.”

  • +
  • Or I can send you a permalink:

  • +
+
+Screen-shot of a code portion +
+

Permalink that points to a code portion.

+
+
+
+
+

What we typically like to snapshot

+
    +
  • Software (this is how it started but Git/GitHub can track a lot more)

  • +
  • Scripts

  • +
  • Documents (plain text files much better suitable than Word documents)

  • +
  • Manuscripts (Git is great for collaborating/sharing LaTeX or Quarto manuscripts)

  • +
  • Configuration files

  • +
  • Website sources

  • +
  • Data

  • +
+
+

Discussion

+

In this example somebody tried to keep track of versions without a version +control system tool like Git. Discuss the following directory listing. What +possible problems do you anticipate with this kind of “version control”:

+
myproject-2019.zip
+myproject-2020-February.zip
+myproject-2021-August.zip
+myproject-2023-09-19-working.zip
+myproject-2023-09-21.zip
+myproject-2023-09-21-test.zip
+myproject-2023-09-21-myversion.zip
+myproject-2023-09-21-newfeature.zip
+...
+
+
+ +
+
+
+

Difficulties of version control

+

Despite the benefits, let’s be honest, there are some difficulties:

+
    +
  • One more thing to learn (it’s probably worth it and will save you more time in the long run; basic career skill).

  • +
  • Difficult if your collaborators don’t want to use it (in the worst case, you can version control on your side and email them versions).

  • +
  • Advanced things can be difficult, but basics are often enough (ask others for help when needed).

  • +
+
+
+

Why Git and not another tool?

+
    +
  • Easy to set up: no server needed.

  • +
  • Very popular: chances are high you will need to contribute to somebody else’s code which is tracked with Git.

  • +
  • Distributed: good backup, no single point of failure, you can track and +clean-up changes offline, simplifies collaboration model for open-source +projects.

  • +
  • Important platforms such as GitHub, GitLab, and Bitbucket +build on top of Git.

  • +
+

However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +Subversion, +Mercurial, Pijul, or others.

+
+
+
+
+

Basics

+
+

Objectives

+
    +
  • Learn to create Git repositories and make commits.

  • +
  • Get a grasp of the structure of a repository.

  • +
  • Learn how to inspect the project history.

  • +
  • Learn how to write useful commit log messages.

  • +
+
+
+

Instructor note

+
    +
  • 35 min teaching/type-along

  • +
  • 40 min exercise

  • +
+
+
+

What is Git, and what is a Git repository?

+
    +
  • Git is a version control system: can record/save snapshots and track the content of a folder as it changes over time.

  • +
  • Every time we commit a snapshot, Git records a snapshot of the entire project, saves it, and assigns it a version.

  • +
  • These snapshots are kept inside a sub-folder called .git.

  • +
  • If we remove .git, we remove the repository and history (but keep the working directory!).

  • +
  • The directory .git uses relative paths - you can move the whole repository somewhere else and it will still work.

  • +
  • Git doesn’t do anything unless you ask it to (it does not record anything automatically).

  • +
  • Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces).

  • +
+
+
+

Recording a snapshot with Git

+
    +
  • Git takes snapshots only if we request it.

  • +
  • We will record changes in two steps (we will later explain why this is a recommended practice).

  • +
  • Example (we don’t need to type yet):

    +
    $ git add FILE.txt
    +$ git commit
    +
    +$ git add FILE.txt ANOTHERFILE.txt
    +$ git commit
    +
    +
    +
  • +
  • We first focus (git add, we “stage” the change), then record (git commit):

  • +
+
+Git staging +
+

Git staging and committing.

+
+
+
+

Question for the more advanced participants

+

What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end.

+
+
+
+

Configuring Git command line

+

Before we start using Git on the command line, we need to configure Git. +This is also part of the +installation instructions +but we need to make sure we all have +set name, email address, editor, and +default branch:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+$ git config --global core.editor nano
+$ git config --global init.defaultBranch main
+
+
+

Verify with:

+
$ git config --list
+
+
+
+

Instructor note

+

Instructors, give learners enough time to do the above configuration steps.

+
+
+
+

Type-along: Tracking a guacamole recipe with Git

+

We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list)

+

The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language.

+
+

Instructor note

+

Instructors, please encourage now that participants type along.

+
+
+

Note

+

It is possible to go through this lesson in the command line or in the browser +(on GitHub).

+
    +
  • We recommend to start with the command line but later to also try in the browser.

  • +
  • If you get really stuck in the command line, try following in the browser and +later you can try to return to the command line.

  • +
+
+
+
+

Creating a repository

+

One of the basic principles of Git is that it is easy to create repositories:

+
+
$ mkdir recipe
+$ cd recipe
+$ git init -b main
+
+
+

That’s it! With git init -b main have now created an empty Git repository +where main is the default branch (more about branches later).

+

We will use git status a lot to check out what is going on:

+
$ git status
+
+On branch main
+
+No commits yet
+
+nothing to commit (create/copy files and use "git add" to track)
+
+
+

We will make sense of this information during this workshop.

+
+
+
+

Adding files and committing changes

+

Let us now create two files.

+

One file is called ingredients.txt and contains:

+
* 2 avocados
+* 1 chili
+* 1 lime
+* 2 tsp salt
+
+
+

The second file is called instructions.txt and contains:

+
* chop avocados
+* chop onion
+* chop chili
+* squeeze lime
+* add salt
+* and mix well
+
+
+
+

As mentioned above, in Git you can always check the status of files in your repository using +git status. It is always a safe command to run and in general a good idea to +do when you are trying to figure out what to do next:

+
$ git status
+
+On branch main
+
+No commits yet
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    ingredients.txt
+    instructions.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+
+

The two files are untracked in the repository (directory). You want to add the files (focus the camera) +to the list of files tracked by Git. Git does not track +any files automatically and you need make a conscious decision to add a file. Let’s do what +Git hints at, and add the files, one by one:

+
$ git add ingredients.txt
+$ git status
+
+On branch main
+
+No commits yet
+
+Changes to be committed:
+  (use "git rm --cached <file>..." to unstage)
+    new file:   ingredients.txt
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    instructions.txt
+
+
+

Now this change is staged and ready to be committed. +Let us now commit the change to the repository:

+
$ git commit -m "adding ingredients"
+
+[main (root-commit) f146d25] adding ingredients
+ 1 file changed, 4 insertions(+)
+ create mode 100644 ingredients.txt
+
+
+

Right after we query the status to get this useful command into our muscle memory:

+
$ git status
+
+
+

Now stage and commit also the other file:

+
$ git add instructions.txt
+$ git commit -m "adding instructions"
+
+
+

We will add a third file to the repository, README.md, containing:

+
# recipe
+
+This is an exercise repository.
+
+
+

Now stage and commit also the README.md file:

+
$ git add README.md
+$ git commit -m "adding README"
+
+
+

What does the -m flag mean? Let us check the help page for that command:

+
$ git help commit
+
+
+

You should see a very long help page as the tool is very versatile (press q to quit). +Do not worry about this now but keep in mind that you can always read the help files +when in doubt. Searching online can also be useful, but choosing search terms +to find relevant information takes some practice and discussions in some +online threads may be confusing. +Note that help pages also work when you don’t have a network connection!

+
+
+
+

Exercise: Record changes

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+
+
+

Git history and log

+
+

If you haven’t yet, please try now git log:

+
$ git log
+
+commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main)
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:47 2023 +0200
+
+    don't forget to enjoy
+
+commit 79161b6e67c62ad4688a58c1e54183334611a390
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:32 2023 +0200
+
+    add half an onion
+
+commit a3394e39535343c4dae3bb4f703741a31aa8b78a
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:47:14 2023 +0200
+
+    adding README
+
+commit 369624674e63de48055a65bf63055bd59c985d22
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:46:58 2023 +0200
+
+    adding instructions
+
+commit f146d25b94569a15e94d7f0da6f15d7554f76c49
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:35:52 2023 +0200
+
+    adding ingredients
+
+
+
+
    +
  • We can browse the development and access each state that we have committed.

  • +
  • The long hashes uniquely label a state of the code.

  • +
  • They are not just integers counting 1, 2, 3, 4, … (why?).

  • +
  • Output is in reverse chronological order, i.e. newest commits on top.

  • +
  • We will use them when comparing versions and when going back in time.

  • +
  • git log --oneline only shows the first 7 characters of the commit hash and is good to get an overview.

  • +
  • If the first characters of the hash are unique it is not necessary to type the entire hash.

  • +
  • git log --stat is nice to show which files have been modified.

  • +
+
+
+

Optional exercises: Comparing changes

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+
+
+

Writing useful commit messages

+

Using git log --oneline or browsing a repository on the web, we better +understand that the first line of the commit message is very important.

+

Good example:

+
increase threshold alpha to 2.0
+
+the motivation for this change is
+to enable ...
+...
+this is based on a discussion in #123
+
+
+

Convention: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

Ignoring files and paths with .gitignore

+
+

Discussion

+
    +
  • Should we add and track all files in a project?

  • +
  • How about generated files?

  • +
  • Why is it considered a bad idea to commit compiled binaries to version control?

  • +
  • What types of generated files do you know?

  • +
+
+

Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files. Example:

+
# ignore compiled python 2 files
+*.pyc
+# ignore compiled python 3 files
+__pycache__
+
+
+

An example taken from the official Git documentation:

+
# ignore objects and archives, anywhere in the tree.
+*.[oa]
+# ignore generated html files,
+*.html
+# except foo.html which is maintained by hand
+!foo.html
+# ignore everything under build directory
+build/
+
+
+
    +
  • .gitignore should be part of the repository because we want to make sure that all developers see the same behavior.

  • +
  • All files should be either tracked or ignored.

  • +
  • .gitignore uses something called a +shell glob syntax for +determining file patterns to ignore. You can read more about the syntax in the +documentation.

  • +
  • You can have .gitignore files in lower level directories and they affect the paths below.

  • +
+
+
+

Graphical user interfaces

+

We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI):

+ +
+
+

Summary

+

Now we know how to save snapshots:

+
$ git add FILE(S)
+$ git commit
+
+
+

And this is what we do as we program.

+

Every state is then saved and later we will learn how to go back to these “checkpoints” +and how to undo things.

+
$ git init -b main  # initialize new repository (main is default branch)
+$ git add           # add files or stage file(s)
+$ git commit        # commit staged file(s)
+$ git status        # see what is going on
+$ git log           # see history
+$ git diff          # show unstaged/uncommitted modifications
+$ git show          # show the change for a specific commit
+$ git mv            # move/rename tracked files
+$ git rm            # remove tracked files
+
+
+

Git is not ideal for large binary files +(for this consider git-annex).

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • It takes only one command to initialize a Git repository: git init -b main.

  • +
  • Commits should be used to tell a story.

  • +
  • Git uses the .git folder to store the snapshots.

  • +
  • Don’t be afraid to stage and commit often. Better too often than not often enough.

  • +
+
+
+
+
+

Branching and merging

+
+

Objectives

+
    +
  • Be able to create and merge branches.

  • +
  • Know the difference between a branch and a tag.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Motivation for branches

+

In the previous section we tracked a guacamole recipe with Git.

+

Up until now our repository had only one branch with one commit coming +after the other:

+
+Linear Git repository +
+

Linear Git repository.

+
+
+
    +
  • Commits are depicted here as little boxes with abbreviated hashes.

  • +
  • Here the branch main points to a commit.

  • +
  • “HEAD” is the current position (remember the recording head of tape +recorders?). When we say HEAD, we mean those literal letters - +this isn’t a placeholder for something else.

  • +
  • When we talk about branches, we often mean all parent commits, not only the commit pointed to.

  • +
+

Now we want to do this:

+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+

Software development is often not linear:

+
    +
  • We typically need at least one version of the code to “work” (to compile, to give expected results, …).

  • +
  • At the same time we work on new features, often several features concurrently. +Often they are unfinished.

  • +
  • We need to be able to separate different lines of work really well.

  • +
+

The strength of version control is that it permits the researcher to isolate +different tracks of work, which can later be merged to create a composite +version that contains all changes:

+
+Isolated tracks of work +
+

Isolated tracks of work.

+
+
+
    +
  • We see branching points and merging points.

  • +
  • Main line development is often called main or master.

  • +
  • Other than this convention there is nothing special about main or master, it is a branch like any other.

  • +
  • Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow).

  • +
+

A group of commits that create a single narrative are called a branch. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. “fast sequence extraction” or “Python interface” or “fixing bug in +matrix inversion algorithm”.

+
+

An important alias

+

We will now define an alias in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). This is extensively used in the rest of this +and other lessons:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+
+
+

Instructor note

+

Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative.

+
+

Let us inspect the project history using the git graph alias:

+
$ git graph
+
+* e7cf023 (HEAD -> main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • We have a couple commits and only +one development line (branch) and this branch is called main.

  • +
  • Commits are states characterized by a 40-character hash (checksum).

  • +
  • git graph print abbreviations of these checksums.

  • +
  • Branches are pointers that point to a commit.

  • +
  • Branch main points to a commit (in this example it is e7cf023efe382340e5284c278c6ae2c087dd3ff7 but on your computer +the hash will be different).

  • +
  • HEAD is another pointer, it points to where we are right now (currently main)

  • +
+

In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards.

+
+
+

Creating and working with branches

+
+

Instructor note

+

We do the following part together. Encourage participants to type along.

+
+
+

It is possible to create and merge branches directly on GitHub

+
    +
  • However, we do not have screenshots for that in this episode

  • +
  • But if you prefer to work in the browser, please try it

  • +
  • Please contribute screenshots to this lesson

  • +
+
+

Let’s create a branch called experiment where we add cilantro to ingredients.txt +(text after “#” are comments and not part of the command).

+
$ git branch experiment main  # creates branch "experiment" from "main"
+$ git switch experiment       # switch to branch "experiment"
+$ git branch                  # list all local branches and show on which branch we are
+
+
+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+
    +
  • Verify that you are on the experiment branch (note that git graph also +makes it clear what branch you are on: HEAD -> branchname):

    +
    $ git branch
    +
    +* experiment
    +  main
    +
    +
    +

    This command shows where we are, it does not create a branch.

    +
  • +
  • Then add 2 tbsp cilantro on top of the ingredients.txt:

    +
    * 2 tbsp cilantro
    +* 2 avocados
    +* 1 chili
    +* 1 lime
    +* 2 tsp salt
    +* 1/2 onion
    +
    +
    +
  • +
  • Stage this and commit it with the message “let us try with some cilantro”.

  • +
  • Then reduce the amount of cilantro to 1 tbsp, stage and commit again with “maybe little bit less cilantro”.

  • +
+

We have created two new commits:

+
$ git graph
+
+* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro
+* f6ec7b7 let us try with some cilantro
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • The branch experiment is two commits ahead of main.

  • +
  • We commit our changes to this branch.

  • +
+
+
+

Exercise: Create and commit to branches

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+
+
+

Exercise: Merging branches

+

It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge experiment into main.

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+
+

If you got stuck in the above exercises or joined later

+

If you got stuck in the above exercises or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git switch experiment
+$ git switch less-salt
+$ git switch main
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

First we make sure we are on the branch we wish to merge into:

+
$ git branch
+
+  experiment
+  less-salt
+* main
+
+
+

Then we merge experiment into main:

+
$ git merge experiment
+
+
+
+_images/git-merge-1.svg
+

We can verify the result:

+
$ git graph
+
+*   81fcc0c (HEAD -> main) Merge branch 'experiment'
+|\
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+* | b4af65b improve the documentation
+|/
+| * bf28166 (less-salt) reduce amount of salt
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents.

+

To view the branches that are merged into the current branch we can use the command:

+
$ git branch --merged
+
+  experiment
+* main
+
+
+

We are also happy with the work on the less-salt branch. Let us merge that +one, too, into main:

+
$ git branch  # make sure you are on main
+$ git merge less-salt
+
+
+
+Commit graph after merge
+

Commit graph after merge.

+
+
+

We can verify the result in the terminal:

+
$ git graph
+
+*   4e03d4b (HEAD -> main) Merge branch 'less-salt'
+|\
+| * bf28166 (less-salt) reduce amount of salt
+* |   81fcc0c Merge branch 'experiment'
+|\ \
+| * | bcb8b78 (experiment) maybe little bit less cilantro
+| * | f6ec7b7 let us try with some cilantro
+| |/
+* / b4af65b improve the documentation
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Observe how Git nicely merged the changed amount of salt and the new ingredient in the same file +without us merging it manually:

+
$ cat ingredients.txt
+
+* 1 tbsp cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually settle merge conflicts (we will do that later).

+
+
+

Deleting branches safely

+

Both feature branches are merged:

+
$ git branch --merged
+
+  experiment
+  less-salt
+* main
+
+
+

This means we can delete the branches:

+
$ git branch -d experiment
+$ git branch -d less-salt
+
+
+

This is the result:

+
+Commit graph after merged branches were deleted
+

Commit graph after merged branches were deleted.

+
+
+

We observe that when deleting branches, +only the pointers (“sticky notes”) disappeared, not the commits.

+

Git will not let you delete a branch which has not been reintegrated unless you +insist using git branch -D. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them.

+
+
+

Optional exercises with branches

+

The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section.

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+
+
+

Tags

+
    +
  • A tag is a pointer to a commit but in contrast to a branch it does not ever +move when creating new commits later.

  • +
  • It can be useful to think of branches as sticky notes and of tags as +commemorative plaques.

  • +
  • We use tags to record particular states or milestones of a project at a given +point in time, like for instance versions (have a look at semantic versioning, +v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a).

  • +
  • There are two basic types of tags: annotated and lightweight.

  • +
  • Use annotated tags since they contain the author and can be cryptographically signed using +GPG, timestamped, and a message attached.

  • +
+

Let’s add an annotated tag to our current state of the guacamole recipe:

+
$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet"
+
+
+

As you may have found out already, git show is a very versatile command. Try this:

+
$ git show nobel-2023
+
+
+

For more information about tags see for example +the Pro Git book chapter on the +subject.

+
+
+
+

Summary

+

Let us pause for a moment and recapitulate what we have just learned:

+
$ git branch               # see where we are
+$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+$ git merge NAME           # merge branch NAME (to current branch)
+$ git branch -d NAME       # delete branch NAME
+$ git branch -D NAME       # delete unmerged branch NAME
+
+
+

Since the following command combo is so frequent:

+
$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+
+
+

There is a shortcut for it:

+
$ git switch --create NAME  # create branch NAME and switch to it
+
+
+
+

Typical workflows

+

With this there are two typical workflows:

+
$ git switch --create new-feature  # create branch, switch to it
+$ git commit                       # work, work, work, ..., and test
+$ git switch main                  # once feature is ready, switch to main
+$ git merge new-feature            # merge work to main
+$ git branch -d new-feature        # remove branch
+
+
+

Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging:

+
$ git switch --create wild-idea    # create branch, switch to it, work, work, work ...
+$ git switch main                  # realize it was a bad idea, back to main
+$ git branch -D wild-idea          # it is gone, off to a new idea
+
+
+
+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • A branch is a division unit of work, to be merged with other units of work.

  • +
  • A tag is a pointer to a moment in the history of a project.

  • +
+
+
+
+
+
+

Conflict resolution

+
+

Objectives

+
    +
  • Understand merge conflicts sufficiently well to be able to fix them.

  • +
+
+
+

Instructor note

+
    +
  • 20 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Conflicts in Git and why they are good

+

Imagine we start with the following text file:

+
1 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch A somebody modifies:

+
2 tbsp cilantro
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch B somebody else modifies:

+
1/2 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1 onion
+
+
+

When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro:

+
?????????????????
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1 onion
+
+
+

Git is very good at resolving modifications when merging branches and +in most cases a git merge runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see Optional exercises with branches) without you even noticing.

+

But sometimes the same portion of the code/text is modified on two branches +in two different ways and Git issues a conflict. +Then you need to tell Git which version to keep (resolve it).

+

There are several ways to do that as we will see.

+

Please remember:

+
    +
  • It is good that Git conflicts exist: Git will not silently overwrite one of +two differing modifications.

  • +
  • Conflicts may look scary, but are not that bad after a little bit of +practice. Also they are luckily rare.

  • +
  • Don’t be afraid of Git because of conflicts. You may not meet some conflicts +using other systems because you simply can’t do the kinds of things you do +in Git.

  • +
  • You can take human measures to reduce them.

  • +
+
+
+

The human side of conflicts

+
    +
  • What does it mean if two people do the same thing in two different ways?

  • +
  • What if you work on the same file but do two different things in the different sections?

  • +
  • What if you do something, don’t tell someone from 6 months, and then try to combine it with other people’s work?

  • +
  • How are conflicts avoided in other work? (Only one person working at once? +Declaring what you are doing before you start, if there is any chance someone +else might do the same thing, helps.)

  • +
  • Minor conflicts (two people revise spelling) vs semantic (two people rewrite +a function to add two different new features). How did Git solve these in +branching/merging easily?

  • +
+
+

Now we can go to show how Git controls when there is actually a conflict.

+
+
+

Preparing a conflict

+
+

Instructor note

+

We do the following together as type-along/demo.

+
+
+

If you got stuck previously or joined later

+

If you got stuck previously or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together.

+
    +
  • Create two branches from main: one called like-cilantro, one called dislike-cilantro:

    +
    $ git branch like-cilantro main
    +$ git branch dislike-cilantro main
    +
    +
    +
  • +
  • On the two branches make different modifications to the amount of the same ingredient:

  • +
  • On the branch like-cilantro we have the following change:

    +
    $ git diff main like-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6cacd50 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
  • And on the branch dislike-cilantro we have the following change:

    +
    $ git diff main dislike-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6484462 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 1/2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
+
+
+

Merging conflicting changes

+

What do you expect will happen when we try to merge these two branches into +main?

+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+

The first merge will work:

+
$ git switch main
+$ git status
+$ git merge like-cilantro
+
+Updating 4e03d4b..3caa632
+Fast-forward
+ ingredients.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+
+

But the second will fail:

+
$ git merge dislike-cilantro
+
+Auto-merging ingredients.txt
+CONFLICT (content): Merge conflict in ingredients.txt
+Automatic merge failed; fix conflicts and then commit the result.
+
+
+

Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit:

+
$ git status
+
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+  (use "git merge --abort" to abort the merge)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+	both modified:   ingredients.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+
+
+

Git won’t decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward.

+

Let us inspect the conflicting file:

+
$ cat ingredients.txt
+
+<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

Git inserted resolution markers (the <<<<<<<, >>>>>>>, and =======).

+

Try also git diff:

+
$ git diff
+
+
+
diff --cc ingredients.txt
+index 6cacd50,6484462..0000000
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@@ -1,4 -1,4 +1,10 @@@
+++<<<<<<< HEAD
+ +* 2 tbsp cilantro
+++=======
++ * 1/2 tbsp cilantro
+++>>>>>>> dislike-cilantro
+  * 2 avocados
+  * 1 chili
+  * 1 lime
+
+
+

git diff now only shows the conflicting part, nothing else.

+
+
+

Conflict resolution

+
<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+
+
+

We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged.

+
+

Steps to resolve a conflict

+
    +
  • Check status with git status and git diff.

  • +
  • Decide what you keep (the one, the other, or both or something +else). Edit the file to do this.

    +
      +
    • Remove the resolution markers, if not already done.

    • +
    • The file(s) should now look exactly how you want them.

    • +
    +
  • +
  • Check status with git status and git diff.

  • +
  • Tell Git that you have resolved the conflict with git add ingredients.txt +(if you use the Emacs editor with a certain plugin the editor may stage the +change for you after you have removed the conflict markers).

  • +
  • Verify the result with git status.

  • +
  • Finally commit the merge with only git commit. Everything is pre-filled.

  • +
+
+
+
+

Exercise: Create and resolve a conflict

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+
+
+

Optional exercises with conflict resolution

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+
+

Using “ours” or “theirs” strategy

+
    +
  • Sometimes you know that you want to keep “ours” version (version on the branch you are on) +or “theirs” (version on the merged branch).

  • +
  • Then you do not have to resolve conflicts manually.

  • +
  • See merge strategies.

  • +
+

Example (merge and in doubt take the changes from current branch):

+
$ git merge -s recursive -Xours less-avocados
+
+
+

Or (merge and in doubt take the changes from less-avocados branch):

+
$ git merge -s recursive -Xtheirs less-avocados
+
+
+
+
+
+

Aborting a conflicting merge

+

Sometimes you get a merge conflict but realize that you can’t solve it without +talking to a colleague (who created the other change) first. What to do?

+

You can abort the merge and postponing conflict resolution by resetting the +repository to HEAD (last committed state):

+
$ git merge --abort
+
+
+

The repository looks then exactly as it was before the merge.

+
+
+
+

Avoiding conflicts

+
    +
  • Human measures

    +
      +
    • Think and plan to which branch you will commit to.

    • +
    • Do not put unrelated changes on the same branch.

    • +
    +
  • +
  • Collaboration measures

    +
      +
    • Open an issue and discuss with collaborators before starting a long-living +branch.

    • +
    +
  • +
  • Project layout measures

    +
      +
    • Modifying global data often causes conflicts.

    • +
    • Modular programming reduces this risk.

    • +
    +
  • +
  • Technical measures

    +
      +
    • Share your changes early and often - this is one of the happy, +rare circumstances when everyone doing the selfish thing (e.g. git push as +early as practical) results in best case for everyone!

    • +
    • Pull/rebase often to keep up to date with upstream.

    • +
    • Resolve conflicts early.

    • +
    +
  • +
+
+

Discussion

+

Discuss how Git handles conflicts compared to services like Google Drive.

+
+
+

Keypoints

+
    +
  • Conflicts often appear because of not enough communication or not optimal +branching strategy.

  • +
+
+
+
+
+

Sharing repositories online

+
+

Objectives

+
    +
  • We get a feeling for remote repositories (more later).

  • +
  • We are able to publish a repository on the web.

  • +
  • We are able to fetch and track a repository from the web.

  • +
+
+
+

Instructor note

+
    +
  • 15 min demonstration/type-along

  • +
  • 25 min exercise

  • +
+
+
+

From our laptops to the web

+

We have seen that creating Git repositories and moving them around is +relatively simple and that is great.

+

So far, if you only worked in the command line, everything was local and all +snapshots, branches, and tags are saved under .git.

+

If we remove .git, we remove all Git history of a project.

+
+

Discussion

+
    +
  • What if the hard disk fails?

  • +
  • What if somebody steals my laptop?

  • +
  • How can we collaborate with others across the web?

  • +
+
+
+
+

Remotes

+

We will learn how to work with remote repositories in detail in the +collaborative distributed version control lesson.

+

In this section we only want to get a taste to prepare us for other lessons +where we will employ GitHub. Our goal is to publish our exercise guacamole recipe +which we prepared in the previous episodes on +the web. Don’t worry, you will be able to remove it afterwards.

+
+

If you don’t have the recipe repository from previous episodes

+

Maybe you joined the workshop later or got stuck somewhere? No problem!

+

If you don’t have the recipe repository from previous episodes, you can +clone our version of the repository using (please skip this if you have the recipe +repository on your computer already):

+
$ git clone https://github.com/coderefinery/recipe-before-merge.git recipe
+$ cd recipe
+$ git remote remove origin
+
+
+

Now you have a repository called recipe on your computer with a couple of +commits. Further down we will also clarify what git clone does.

+
+

To store your git data on another server, you use remotes. +A remote is a repository on its own, with its own branches +We can push changes to the remote and pull +from the remote.

+

You might use remotes to:

+
    +
  • Back up your own work.

  • +
  • To collaborate with other people.

  • +
+

There are different types of remotes:

+
    +
  • If you have a server you can ssh to, you can use that as a remote.

  • +
  • GitHub is a popular, closed-source commercial site.

  • +
  • GitLab is a popular, open-core +commercial site. Many universities have their own private GitLab servers +set up.

  • +
  • Bitbucket is yet another popular commercial site.

  • +
  • Another option is NotABug.

  • +
  • We also operate a Nordic +research software repository +platform. +This is GitLab, free for researchers and allows private, +cross-university sharing.

  • +
+
+
+
+

Authenticating to GitHub: SSH or HTTPS?

+

How does Github know who you are? This is hard and there are two +options.

+
    +
  • SSH is the classic method, using Secure Shell remote connection +keys.

  • +
  • HTTPS works with the Git Credential Manager, which is an +extra add-on that works easily in Windows and Mac.

  • +
+

Read how to install them from the installation +instructions.

+

Test which one you should use:

+
+

Try this command:

+
$ ssh -T git@github.com
+
+
+

If it returns Hi USERNAME! You've successfully authenticated, ..., +then SSH is configured and the following steps will work with the SSH +cloning.

+

See our installation +instructions to +set up SSH access.

+

From now on, if you know that SSH works, you should always select +SSH as the clone URL from GitHub, or translate the URL to start with +the right thing yourself: git@github.com: (with the trailing +:).

+
+

If you do not have these configured, please watch as we do this episode and you +can check the installation +instructions +before the next collaborative Git +lesson, where we will need +one of these set up.

+
+
+
+

Publishing an existing repository from laptop to GitHub

+
+

If you started in the browser and have nothing on your laptop yet

+

It is possible, that you already have a repository on GitHub if you followed +the examples and exercises in previous episodes in the browser. In this case, +please watch others publish their repository and try to clone your repository +to the laptop using instructions at the bottom of this page.

+
+

First log into GitHub, then follow the screenshots and descriptions below.

+
+Screenshot on GitHub before a new repository form is opened +
+

Click on the “plus” symbol on top right, then on “New repository”.

+
+
+

Another way to create a new repository is to visit +https://github.com/new directly.

+
+Screenshot on GitHub just before a new repository is created +
+

Choose a repository name, add a short description, but please do not check “Add a +README file”**. For “Add .gitignore” and “Choose a license” also leave as “None”. Finally “Create repository”.

+
+
+

Once you click the green “Create repository”, you will see a page similar to:

+
+Screenshot on GitHub after a bare repository was created +
+

What this means is that we have now an empty project with either an HTTPS or an +SSH address: click on the HTTPS and SSH buttons to see what happens.

+

We now want to follow the “… or push an existing repository from the command line:

+
    +
  1. Now go to your guacamole repository on your computer.

  2. +
  3. Check that you are in the right place with git status.

  4. +
  5. Copy paste the three lines to the terminal and execute those, in my case (you +need to replace the “USER” part and possibly also the repository name):

  6. +
+
+

See above for if SSH is the right option for you.

+
$ git remote add origin git@github.com:USER/recipe.git
+
+
+
+

Then:

+
$ git branch -M main
+$ git push -u origin main
+
+
+

The meaning of the above lines:

+
    +
  • Add a remote reference with the name “origin”

  • +
  • Rename current branch to “main”

  • +
  • Push branch “main” to “origin”

  • +
+

You should now see:

+
Enumerating objects: 3, done.
+Counting objects: 100% (3/3), done.
+Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
+Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
+To github.com:USER/recipe.git
+ * [new branch]      main -> main
+Branch 'main' set up to track remote branch 'main' from 'origin'.
+
+
+

Reload your GitHub project website and - taa-daa - your commits should now be +online! What just happened? Think of publishing a repository as uploading +the .git part online.

+
+

Troubleshooting

+

error: remote origin already exists.

+
    +
  • Explanation: You probably ran a git remote add origin ... command, then changed your +mind about HTTPS or SSH and then tried to run the other git remote add origin ... command but “origin” then already exists.

  • +
  • Recovery:

    +
      +
    • First remove “origin” with git remote remove origin

    • +
    • Then run the correct git remote add origin ... command

    • +
    +
  • +
+

remote contains work that you do not have

+
    +
  • Explanation: You probably clicked on “Add a README file” and now the +repository on GitHub is not empty but contains one commit and locally you +have a different history. Git now prevents you from accidentally overwriting +the history on GitHub.

  • +
  • Recovery:

    +
      +
    • Use git push --force instead of git push, which will force Git to overwrite the history on GitHub

    • +
    • Note that this is a powerful but also possibly dangerous option but here it +helps us. If it’s a brand new repo, it probably is fine to do this. For real +repositories, don’t do this unless you are very sure what is happening.

    • +
    +
  • +
+
+
+
+
+

Cloning a repository from GitHub to laptop

+

Now other people can clone this repository and contribute changes. In the +collaborative distributed version control lesson +we will learn how this works.

+

At this point only a brief demo - if you copy the SSH or HTTPS address, you can clone repositories like this +(again adapt the USER in the “USER/repository.git” part):

+
+
$ git clone git@github.com:USER/recipe.git
+
+
+

From now on, if you are using SSH, you should pay attention and make +sure your clone URLs start with git@github.com: now and in future +lessons.

+
+

This creates a directory called “recipe” unless it already exists. You can also specify the target directory +on your computer:

+
+
$ git clone git@github.com:USER/recipe.git myrecipe
+
+
+
+

What just happened? Think of cloning as downloading the .git part to your +computer. After downloading the .git part, the default branch (the branch pointed to by HEAD) is +automatically checked out.

+
+

Keypoints

+
    +
  • A repository can have one or multiple remotes (we will revisit these later).

  • +
  • Local branches often track remote branches.

  • +
  • A remote serves as a full backup of your work.

  • +
  • We’ll properly learn how to use these in the +collaborative distributed version control.

  • +
+
+
+
+
+

Inspecting history

+
+

Objectives

+
    +
  • Be able find a line of code, find out why it was introduced and when.

  • +
  • Be able to quickly find the commit that changed a behavior.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 30 min exercise

  • +
+
+
+

Preparation

+

Please make sure that you do not clone repositories inside an already tracked folder:

+
$ git status
+
+
+

If you are inside an existing Git repository, step out of it. +You need to find a different location since we will clone a new repository.

+

If you see this message, this is good in this case:

+
fatal: not a git repository (or any of the parent directories): .git
+
+
+
+
+

Our toolbox for history inspection

+
+

Instructor note

+

First the instructor demonstrates few commands on a real life example +repository https://github.com/networkx/networkx (mentioned in the amazing site The +Programming Historian). +Later we will practice these in an archaeology exercise (below).

+
+
+

Warm-up: “Git History” browser

+

As a warm-up we can try the “Git History” browser +on the README.rst file of the networkx repository:

+ +
+
+

Searching text patterns in the repository

+
+

With git grep you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or some error message printed:

+
$ git grep TEXT
+$ git grep "some text with spaces"
+
+
+

In the networkx repository you can try:

+
$ git clone https://github.com/networkx/networkx
+$ cd networkx
+$ git grep -i fixme
+
+
+

While git grep searches the current state of the repository, +it is also possible to search through all changes with git log -S sometext +which can be useful to find where something got removed.

+
+
+
+

Inspecting individual commits

+
+

We have seen this one before already. Using git show we can inspect an individual commit if +we know its hash:

+
$ git show HASH
+
+
+

For instance:

+
$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7
+
+
+
+
+
+

Line-by-line code annotation with metadata

+

With git annotate you can see line by line who and when the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility.

+
+
$ git annotate FILE
+
+
+

Example:

+
$ git annotate networkx/convert_matrix.py
+
+
+

If you annotate in a terminal and the file is longer than the screen, Git by default uses the program less to +scroll the output. +Use /sometext <ENTER> to find “sometext” and you can cycle through the results with n (next) and N (last). +You can also use page up/down to scroll. You can quit with q.

+
+
+

Discussion

+

Discuss how these relatively trivial changes affect the annotation:

+
    +
  • Wrapping long lines of text/code into shorter lines

  • +
  • Auto-formatting tools such as black

  • +
  • Editors that automatically remove trailing whitespace

  • +
+
+
+
+

Inspecting code in the past

+
+

We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code:

+
$ git switch --create BRANCHNAME HASH
+
+
+

Example (lines starting with “#” are only comments):

+
$ # create branch called "older-code" from hash 347e6292419b
+$ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9
+
+$ # now you can navigate and inspect the code as it was back then
+$ # ...
+
+$ # after we are done we can switch back to "main"
+$ git switch main
+
+$ # if we like we can delete the "older-code" branch
+$ git branch -d older-code
+
+
+

On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

+
$ git checkout -b BRANCHNAME SOMEHASH
+
+
+
+
+
+
+

Exercise: Basic archaeology commands

+
+

History-1: Explore basic archaeology commands

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Clone this repository: +https://github.com/networkx/networkx.git. +Then step into the new directory and create an exercise branch from the networkx-2.6.3 tag/release:

    +
    $ git clone https://github.com/networkx/networkx.git
    +$ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+
+
+
+

Finding out when something broke/changed with git bisect

+
+

“But I am sure it used to work! Strange.”

+
+

Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke.

+
+

How would you solve this?

+

Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now.

+
    +
  • How would you find the commit which changed it?

  • +
  • Why could it be useful to know the commit that changed it?

  • +
+
+

We will probably arrive at a solution which is similar to git bisect:

+
    +
  • First find out a commit in past when it worked.

    +
    $ git bisect start
    +$ git bisect good f0ea950  # this is a commit that worked
    +$ git bisect bad main      # last commit is broken
    +
    +
    +
  • +
  • Now compile and/or run and/or test and decide whether “good” or “bad”.

  • +
  • This is how you can tell Git that this was a working commit:

    +
    $ git bisect good
    +
    +
    +
  • +
  • And this is how you can tell Git that this was not a working commit:

    +
    $ git bisect bad
    +
    +
    +
  • +
  • Then bisect/iterate your way until you find the commit that broke it.

  • +
  • If you want to go back to start, type git bisect reset.

  • +
  • This can even be automatized with git bisect run SCRIPT. +For this you write a script that returns zero/non-zero (success/failure).

  • +
+
+
+

Optional exercise: Git bisect

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+

Keypoints

+
    +
  • git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project.

  • +
  • git switch --create NAME HASH is the recommended mechanism to inspect old code.

  • +
+
+
+
+
+

Practical advice: how much Git is necessary?

+
+

Instructor note

+
    +
  • 20 min teaching/discussion

  • +
+
+
+

What level of branching complexity is necessary for each project?

+
+

Simple personal projects

+
    +
  • Typically start with just the main branch.

  • +
  • Use branches for unfinished/untested ideas.

  • +
  • Use branches when you are not sure about a change.

  • +
  • Use tags to mark important milestones.

  • +
+
+
+

Projects with few persons: you accept things breaking sometimes

+
    +
  • It might be reasonable to commit to the main branch and feature branches.

  • +
+
+
+

Projects with few persons: changes are reviewed by others

+
    +
  • You create new feature branches for changes.

  • +
  • Changes are reviewed before they are merged to the main branch +(more about that in the collaborative Git lesson).

  • +
  • The main branch is write-protected and can only be changed with pull requests or merge requests.

  • +
+
+
+

When you distribute releases

+
    +
  • If you want to patch releases, you probably need release branches.

  • +
  • The main branch and release branches are read-only.

  • +
  • Many branching models exist.

  • +
+
+
+
+
+

How about staging and committing?

+
    +
  • It is OK to start committing directly by doing git commit SOMEFILE.

  • +
  • Commit early and often: rather create too many commits than too few. +You can always combine commits later.

  • +
  • Once you commit, it is very, very hard to really lose your code.

  • +
  • Always fully commit (or stash) before you do dangerous things, so that you know you are safe. +Otherwise it can be hard to recover.

  • +
  • Later you can start using the staging area.

  • +
  • Later start using git add -p and/or git commit -p.

  • +
+
+
+
+

How large should a commit be?

+
    +
  • Better too small than too large (easier to combine than to split).

  • +
  • Often I make a commit at the end of the day (this is a unit I would not like to lose).

  • +
  • Smaller sized commits may be easier to review for others than huge commits.

  • +
  • Imperfect commits are better than no commits.

  • +
  • A commit should not contain unrelated changes to simplify review and possible +repair/adjustments/undo later (but again: imperfect commits are better than no commits).

  • +
+
+
+

Keypoints

+
    +
  • There is no one size fits all - start simple and grow your project.

  • +
+
+
+

Discussion

+

How do you [plan to] use Git?

+
    +
  • Advanced users or beginners, please provide your input in the online collaborative document.

  • +
+
+
+
+
+

What to avoid

+

The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas.

+

Postponing commits because the changes are “unfinished”/”ugly”: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all.

+

Not updating your branch before starting new work: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later.

+

Commit unrelated changes together: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects.

+

Too ambitious branch which risks to never get completed: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere.

+

Committing generated files: See Ignoring files and paths with .gitignore.

+

Over-engineering the branch layout and safeguards in small projects: This +may prevent people from contributing (maybe even including yourself?). Add more restrictions and safeguards as +the project and the group of collaborators grows.

+

Commit messages that explain what has been changed but do not explain why it has been +changed: This is as useful as code comments which describe the “obvious” such +as “this is a loop” instead of explaining why something is done this way. +But don’t let perfect commit messages stop you from the most important point, committing often (first point).

+

Commit huge files: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent git rm does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request.

+
+

Discussion

+

Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements.

+
+
+
+
+
+

Using the Git staging area

+
+

Objectives

+
    +
  • Learn how to tell a story with your commit history.

  • +
  • Demystify the Git staging area.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 10 min exercise

  • +
+
+
+

Commit history is telling a story

+

Your current code is very important, but the history can be just +as important - it tells a story about how your code came to be.

+
    +
  • Each individual line of code rarely stands alone.

  • +
  • You often want to see all the related changes together.

  • +
  • But you also hardly ever do one thing at once.

  • +
+

Along with your code, Git creates a history for you, and if your +history is clear then you are a long way to organized code.

+
+

Discussion

+

Here are five types of history. What are the advantages and +disadvantages of each, when you look at it later?

+

Example 1:

+
b135ec8 add features A, B, and C
+
+
+

Example 2 (newest commit is on top):

+
6f0d49f implement feature C
+fee1807 implement feature B
+6fe2f23 implement feature A
+
+
+

Example 3:

+
ab990f4 saving three months of miscellaneous work I forgot to commit
+
+
+

Example 4 (newest commit is on top):

+
bf39f9d more work on feature B
+45831a5 removing debug prints for feature A and add new file
+bddb280 more work on feature B and make feature A compile again
+72d78e7 feature A did not work and started work on feature B
+b135ec8 now feature A should work
+72e0211 another fix to make it compile
+61dd3a3 forgot file and bugfix
+49dc419 wip (work in progress)
+
+
+

Example 5 (newest commit is on top):

+
1949dc4 Work of 2020-04-07
+a361dd3 Work of 2020-04-06
+1172e02 Work of 2020-04-03
+e772d78 Work of 2020-04-02
+
+
+

Discuss these examples. Can you anticipate problems?

+
+

We want to have nice commits. But we also want to “save often” +(checkpointing) - how can we have both?

+
    +
  • We will now learn to create nice commits using git commit --patch and/or the staging area.

  • +
  • Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits.

  • +
  • The staging area isn’t the only way to organize your history nicely, some alternatives are discussed at the end of the lesson.

  • +
+
+
+

Interactive commits

+
    +
  • The simplest ways to solve this is to do interactive commits: +the git commit --patch option (or git commit -p for short).

  • +
  • It will present you with every change you have made individually, +and you can decide which ones to commit right now.

  • +
  • Reference and key commands

    +
      +
    • git commit --patch to start the interactive commit

    • +
    • y to use the change

    • +
    • n to skip the change

    • +
    • s (split) if there are several changes grouped together, but +separated by a blank line, split them into separate choices.

    • +
    • q aborts everything.

    • +
    • ? for more options.

    • +
    +
  • +
  • The -p option is also available on commit, restore, checkout, reset, and add.

  • +
+
+
+

Exercise: Interactive commits

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+
+
+

The staging area

+
    +
  • The interactive commits above are great, but what if there are so +many changes that you can’t sort them out in one shot?

  • +
  • What if you make progress and want to record it somehow, but it’s +not ready to be committed?

  • +
  • The staging area is a place to record things before committing.

  • +
+
+

Instructor note

+

We give two examples and the instructor can pick one or both:

+
    +
  • Analogy using moving boxes

  • +
  • Analogy using shopping receipts

  • +
+
+
+

Discussion

+

Analogy using moving boxes

+
    +
  • You’re moving and you have a box to pack your things in.

  • +
  • You can put stuff into the box, but you can also take stuff out of the box.

  • +
  • You wouldn’t want to mix items from the bathroom, kitchen, and living room +into the same box.

  • +
  • The box corresponds to the staging area of Git, where you can craft your commits.

  • +
  • Committing is like sealing the box and sticking a label on it.

  • +
  • You wouldn’t want to label your box with “stuff”, but rather give a more +descriptive label.

  • +
  • See also https://dev.to/sublimegeek/git-staging-area-explained-like-im-five-1anh

  • +
+

Analogy using shopping receipts

+
    +
  • You need to go shopping and buy some stuff for work and for home. +You need two separate receipts.

  • +
  • Bad idea: go through the store get home stuff, pay, start at the +beginning and go through the store again. This is inefficient and +annoying.

  • +
  • What you actually do:

    +
      +
    • Go through the store and put everything you need in your shopping +basket.

    • +
    • Get to the check-out. Put your home stuff on the conveyor belt +(git add). Check both the belt (git diff --staged) and your +basket (git diff) to make sure you got all your home stuff.

    • +
    • Pay (git commit)

    • +
    • Repeat for work stuff.

    • +
    +
  • +
+

In order to keep organized, you have to use multiple locations to +stage things in sequence.

+
+
+
+

Staging area commands

+

The staging area is a middle ground between what you have done to your files +(the working directory) and what you have last committed (the HEAD commit). +Just like the name implies, it lets you prepare (stage) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since you can modify and stage several times before committing.

+

git add stages/prepares for the next commit:

+
                git add
+ [project*]  <------------  project*
+                               ^
+                               | modify with editor
+                               |
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git commit creates a new commit:

+
  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+  HEAD~2          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git reset --soft HEAD~1 (move HEAD back by one but keep changes and stage +them) would do the opposite of git commit. (in this case, HEAD +is literally this - not a replacement)

+

Going back to the last staged version:

+
              git restore
+ [project*]  ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Unstaging changes with git restore --staged:

+
          git restore --staged
+             ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Discarding unstaged changes:

+
                            project*
+                               |
+                               | git restore
+                               v
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Comparing:

+
                git diff
+ [project*]  <----------->  project*
+    ^                          ^
+    | git diff --staged        | git diff HEAD
+    v                          v
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+
+Staging basics +
+

The different states of the repository and the commands to move from one to +another.

+
+
+
+
+

Exercise: Using the staging area

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+

Discussion

+
    +
  • When is it better to “save” a change as commit, when is it better to “save” +it with git add?

  • +
  • Is it a problem to commit many small changes?

  • +
+
+
+

Keypoints

+
    +
  • The staging area helps us to create well-defined commits.

  • +
+
+
+
+
+

Undoing and recovering

+
+

Objectives

+
    +
  • Learn to undo changes safely

  • +
  • See when undone changes are permanently deleted and when they can be retrieved

  • +
+
+
+

Instructor note

+
    +
  • 25 min teaching/type-along

  • +
  • 25 min exercise

  • +
+
+

One of the main points of version control is that you can go back in +time to recover. Unlike this xkcd comic implies: https://xkcd.com/1597/

+

In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn’t a “commit” permanent?

+
    +
  • You can modify old commit history.

  • +
  • But if you have shared that history already, modifying it can make +a huge mess.

  • +
+
+

It is almost always possible to recover

+

As long as you commit something once (or at least git add it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru… until that guru becomes you.

+
+
+

Nice resource to visually simulate Git operation

+

git-sim +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command.

+
+
+
+

Undoing your recent, uncommitted and unstaged changes (preserves history)

+
+

Note

+

In case git restore does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git restore.

+
+

You do some work, and want to undo your uncommitted and unstaged modifications. +You can always do that with:

+
    +
  • git restore . (the dot means “here and in all folders below”)

  • +
+

You can also undo things selectively:

+
    +
  • git restore -p (decide which portions of changes to undo) or git restore PATH (decide which path/file)

  • +
+

If you have staged changes, you have at least two options to undo the staging:

+
    +
  • git restore --staged . followed by git status and git restore .

  • +
  • git reset --hard HEAD throws away everything that is not in last +commit (HEAD - this literal word, this isn’t a placeholder)

  • +
+
+
+
+

Reverting commits (preserves history)

+

Imagine we made a few commits. +We realize that the latest commit e02efcd was a mistake and we wish to undo it:

+
$ git log --oneline
+
+e02efcd (HEAD -> main) not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

A safe way to undo the commit is to revert the commit with git revert:

+
$ git revert e02efcd
+
+
+

This creates a new commit that does the opposite of the reverted commit. +The old commit remains in the history:

+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

You can revert any commit, no matter how old it is. It doesn’t affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we’ll learn about later).

+
+

Exercise: Revert a commit

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+
+
+
+

Adding to the previous commit (modifies history)

+

Sometimes we commit but realize we forgot something. +We can amend to the last commit:

+
$ git commit --amend
+
+
+

This can also be used to modify the last commit message.

+

Note that this will change the commit hash. This command modifies the history. +This means that we avoid this command on commits that we have shared with others.

+
+

Exercise: Modify a previous commit

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+
+
+
+

Rewinding branches (modifies history)

+

You can reset branch history to move your branch back to some +point in the past.

+
    +
  • git reset --hard HASH will force a branch label to any other point. All +other changes are lost (but it is possible to recover if you force reset by mistake).

  • +
  • Be careful if you do this - it can mess stuff up. Use git graph a +lot before and after.

  • +
+
+

Exercise: Git reset

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+
+
+
+
+

Recovering from committing to the wrong branch

+

It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes.

+

Here we assume that we made a couple of commits but we realize they went to the +wrong branch.

+

Solution 1 using git cherry-pick:

+
    +
  1. Make sure that the correct branch exists and if not, create it. Make sure to +create it from the commit hash where you wish you had created it from: git branch BRANCHNAME HASH

  2. +
  3. Switch to the correct branch.

  4. +
  5. git cherry-pick HASH can be used to take a specific commit to the +current branch. Cherry-pick all commits that should have gone to the correct +branch, from oldest to most recent.

  6. +
  7. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  8. +
+

Solution 2 using git reset --hard (makes sense if the correct branch should +contain all commits of the accidentally modified branch):

+
    +
  1. Create the correct branch, pointing at the latest commit: git branch BRANCHNAME.

  2. +
  3. Check with git log or git graph that both branches point to the same, latest, commit.

  4. +
  5. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  6. +
+
+
+

Recovering from merging/pulling into the wrong branch

+

git merge, git rebase, and git pull modify the current branch, never +the other branch. But sometimes we run this command on the wrong branch.

+
    +
  1. Check with git log the commit hash that you would like to rewind the +wrongly modified branch to.

  2. +
  3. Rewind the branch that accidentally got wrong commits with git reset --hard HASH (see also above).

  4. +
+
+
+

Recovering from conflict after pulling changes

+

Pulling changes with +git pull can create a conflict since git pull always also includes a git merge (more about this +in the collaborative Git lesson).

+

The recovery is same as described in Conflict resolution. Either +resolve conflicts or abort the merge with git merge --abort.

+
+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+
+

Interrupted work

+
+

Objectives

+
    +
  • Learn to switch context or abort work without panicking.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+

Keypoints

+
    +
  • There is almost never reason to clone a fresh copy to complete a task that +you have in mind.

  • +
+
+
+

Frequent situation: interrupted work

+

We all wish that we could write beautiful perfect code. But the real world is +much more chaotic:

+
    +
  • You are in the middle of a “Jackson-Pollock-style” debugging spree with 27 modified files +and debugging prints everywhere.

  • +
  • Your colleague comes in and wants you to fix/commit something right now.

  • +
  • What to do?

  • +
+

Git provides lots of ways to switch tasks without ruining everything.

+
+
+

Option 1: Stashing

+

The stash is the first and easiest place to temporarily “stash” +things.

+
    +
  • git stash will put working directory and staging area changes +away. Your code will be same as last commit.

  • +
  • git stash pop will return to the state you were before. Can give it a list.

  • +
  • git stash list will list the current stashes.

  • +
  • git stash save NAME is like the first, but will give it a name. +Useful if it might last a while.

  • +
  • git stash save [-p] [filename] will stash certain files files +and/or by patches.

  • +
  • git stash drop will drop the most recent stash (or whichever stash +you give).

  • +
  • The stashes form a stack, so you can stash several batches of modifications.

  • +
+
+

Exercise: Stashing

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+
+

Option 2: Create branches

+

You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch.

+

You basically know how to do this:

+
$ git switch --create temporary  # create a branch and switch to it
+$ git add PATHS                  # stage changes
+$ git commit                     # commit them
+$ git switch main                # back to main, continue your work there ...
+$ git switch temporary           # continue again on "temporary" where you left off
+
+
+

Later you can merge it to main or rebase it on top of main and resume work.

+
+
+

Storing various junk you don’t need but don’t want to get rid of

+

It happens often that you do something and don’t need it, but you don’t want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still.

+
+
+
+

Aliases and configuration

+
+

Objectives

+
    +
  • Learn to use aliases for most common commands.

  • +
+
+

Are you getting tired of typing so much? In Git you can define aliases (shortcuts):

+
    +
  • These are great because they can save you time typing.

  • +
  • But it’s easy to forget them, get confused, or be inconsistent with your colleagues.

  • +
+

There is plenty of other configuration for Git, that can make it nicer.

+
+

Aliases

+
    +
  • Aliases offer a way to improve the usability of Git: for +example git ci instead of git commit.

  • +
  • Aliases are based on simple string replacement in the command.

  • +
  • Aliases can either be specific to a repository or global.

    +
      +
    • Global aliases help you do the things you are used to across Git projects.

    • +
    • Per-project aliases can also be created.

    • +
    +
  • +
  • Global aliases are stored in ~/.gitconfig.

  • +
+
+
+

Example alias: git graph

+

A very useful shortcut which we use a lot in our workshops:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ cd your_git_repository
+$ git graph
+
+
+
+
+

Using external commands

+

It is possible to call external commands using the exclamation mark character “!”. +In this example here we create a local alias which is +stored in .git/config and not synchronized with remotes:

+
$ cd your_git_repository
+$ git config alias.hi '!echo hello'
+$ git hi
+
+
+
+

Food for thought: When to alias?

+
    +
  • How many times should you wait before aliasing a command?

  • +
  • Do you believe a list of generic two-letter acronyms for common commands will +save your time?

  • +
+
+
+
+

List of aliases the instructors use

+

You are welcome to reuse, suggest, improve. +You can see your current aliases in ~/.gitconfig.

+
$ git config --global alias.ap "add --patch"
+$ git config --global alias.br branch
+$ git config --global alias.ci "commit -v"
+$ git config --global alias.cip "commit --patch -v"
+$ git config --global alias.cl "clone --recursive"
+$ git config --global alias.di diff
+$ git config --global alias.dic "diff --staged --color-words"
+$ git config --global alias.diw "diff --color-words"
+$ git config --global alias.dis "!git --no-pager diff --stat"
+$ git config --global alias.fe fetch
+$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ git config --global alias.rem remote
+$ git config --global alias.st status
+$ git config --global alias.su "submodule update --init --recursive"
+
+
+

Here is what they do:

+
    +
  • ap: add, selecting parts individually, interactively.

  • +
  • br: branch (obvious)

  • +
  • ci: commit (check in), with -v option for clarity

  • +
  • cip: commit, selecting parts individually, interactively.

  • +
  • cl: clone, init submodules (submodules are an advanced topic)

  • +
  • di: diff (obvious)

  • +
  • dic: diff of staging area vs last commit (what is about to be committed)

  • +
  • diw: a word diff, color. Useful for small changes.

  • +
  • dis: a “diffstat”: what files are changed, not contents

  • +
  • fe: fetch (obvious)

  • +
  • graph: show whole git graph (so useful, some of us call it l)

  • +
  • rem: remote (obvious)

  • +
  • st: status (obvious)

  • +
  • su: submodule update (advanced)

  • +
+

A useful setting for the p aliases:

+
$ git config --global interactive.singlekey true
+
+
+
+
+

Advanced aliases

+

These are advanced aliases and configuration options. We won’t explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages!

+
$ git config --global alias.cif "commit -v -p --fixup"
+$ git config --global alias.rb "rebase --autosquash"
+$ git config --global alias.rbi "rebase --interactive --autosquash"
+$ git config --global alias.rbis "rebase --interactive --autosquash --autostash"
+$ git config --global alias.rbs "rebase --autosquash --autostash"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard"
+$ git config --global alias.new "log HEAD..HEAD@{upstream}"
+$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}"
+$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}"
+$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all"
+$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD"
+$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat"
+
+
+
+
+

Advanced Git configuration

+

Besides aliases, you can do plenty of other configuration of git. +Here are some of the most common ones:

+
$ git config --global interactive.singlekey true
+$ git config --global core.pager "less -RS"
+$ git config --global core.excludesfile ~/.gitignore
+$ git config --global merge.conflictstyle diff3
+$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]"
+$ git config --global diff.mnemonicPrefix true
+
+
+

Do you get tired of typing and copying and pasting your remote names +all the time, like git@github.com:myusername? You can create remote +aliases like this:

+
$ git config --global url.git@github.com:.insteadOf gh:
+$ git config --global url.git@github.com:/username/.insteadOf ghu:
+
+
+

Then, when you add a remote ghu:recipe, it will automatically be +translated to git@github.com:/username/recipe using a simple prefix +matching.

+
+

Keypoints

+
    +
  • If you are frustrated about remembering a command, you should create an alias.

  • +
+
+
+
+
+

Git under the hood

+
+

Objectives

+
    +
  • Verify that branches are pointers to commits and extremely lightweight.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+Git under the hood +
+
+

Down the rabbit hole

+

When working with Git, you will never need to go inside .git, but in this +exercise we will, in order to learn about how branches are implemented in Git.

+

For this exercise create a new repository and commit a couple of changes.

+

Now that we’ve made a couple of commits let us look at what is happening under +the hood.

+
$ cd .git
+$ ls -l
+
+drwxr-xr-x   - user 25 Aug 15:51 branches
+.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG
+.rw-r--r--  92 user 25 Aug 15:51 config
+.rw-r--r--  73 user 25 Aug 15:51 description
+.rw-r--r--  21 user 25 Aug 15:51 HEAD
+drwxr-xr-x   - user 25 Aug 15:51 hooks
+.rw-r--r-- 137 user 25 Aug 15:52 index
+drwxr-xr-x   - user 25 Aug 15:51 info
+drwxr-xr-x   - user 25 Aug 15:52 logs
+drwxr-xr-x   - user 25 Aug 15:52 objects
+drwxr-xr-x   - user 25 Aug 15:51 refs
+
+
+

Git stores everything under the .git folder in your repository. In fact, the +.git directory is the Git repository.

+

Previously when you wrote the commit messages using your text editor, they +were in fact saved to COMMIT_EDITMSG.

+

Each commit in Git is stored as a “blob”. This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file.

+

Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string).

+
+A commit inside Git +
+

States of a Git file. Image from the Pro Git book. License CC BY 3.0.

+
+
+

Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a directed acyclic +graph (do not worry +if the term is not familiar).

+
+A commit and its parents +
+

A commit and its parents. Image from the Pro Git book. License CC BY 3.0.

+
+
+

All branches and tags in Git are pointers to commits.

+
+
+

Git is basically a content-addressed storage system

+ +

Let us poke a bit into raw objects! Start with:

+
$ git cat-file -p HEAD
+
+
+

Then explore the tree object, then the file object, etc. recursively using the hashes you see.

+
+
+

Demonstration: experimenting with branches

+

Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an “Aha!” moment and provide us a +good understanding of the underlying model.

+

We are starting from the main branch and create an idea branch:

+
$ git status
+
+On branch main
+nothing to commit, working tree clean
+
+
+
$ git switch --create idea
+
+Switched to a new branch 'idea'
+
+
+
$ git branch
+
+* idea
+  main
+
+
+

Now let us go in:

+
$ cd .git
+$ cd refs/heads
+$ ls -l
+
+.rw-r--r-- 41 user 25 Aug 15:54 idea
+.rw-r--r-- 41 user 25 Aug 15:52 main
+
+
+

Let us check what the idea file looks like +(do not worry if the hash is different):

+
$ cat idea
+
+045e3db14740c60684d745e5fb891ae71e335611
+
+
+

Now let us replicate this file:

+
$ cp idea idea-2
+$ cp idea idea-3
+$ cp idea idea-4
+$ cp idea idea-5
+
+
+

Let us go up two levels and inspect the file HEAD:

+
$ cd ../..
+$ cat HEAD
+
+ref: refs/heads/idea
+
+
+

Let us open this file and change it to:

+
ref: refs/heads/idea-3
+
+
+

Now we are ready for the aha moment! +First let us go back to the working area:

+
$ cd ..
+
+
+

Now - on which branch are we?

+
$ git branch
+
+  idea
+  idea-2
+* idea-3
+  idea-4
+  idea-5
+  main
+
+
+
+

Discussion

+

Discuss the findings with other course participants.

+
+
+
+
+
+
+

Quick reference

+
+

Other cheatsheets

+ +
+
+

Glossary

+
    +
  • working directory/ workspace: the actual files you see and edit

  • +
  • staging area: Place files go after git add and before git commit

  • +
  • hash: unique reference of any commit or state

  • +
  • branch: One line of work. Different branches can exist at the +same time and split/merge.

  • +
  • HEAD: Pointer to the most recent commit on the current branch.

  • +
  • remote: Roughly, another server that holds .git.

  • +
  • origin: Default name for a remote repository.

  • +
  • master: Default name for main branch on Git. Depending on the configuration and service, +the default branch is sometimes main. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

  • +
  • main: Default name for main branch on GitLab and GitHub. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

  • +
+
+
+

Commands we use

+

Setup:

+
    +
  • git config: edit configuration options

  • +
  • git init -b main: create new repository with main as the default branch

  • +
+

See our status:

+
    +
  • git status: see status of files - use often!

  • +
  • git log: see history of commits and their messages, newest first

  • +
  • git graph: see a detailed graph of commits. Create this command +with git config --global alias.graph "log --all --graph --decorate --oneline"

  • +
  • git diff: show difference between working directory and last commit

  • +
  • git diff --staged: show difference between staging area and last commit

  • +
  • git show COMMIT: inspect individual commits

  • +
+

General work:

+
    +
  • git add FILE:

    +
      +
    • Add a new file

    • +
    • Add a file to staging

    • +
    +
  • +
  • git commit: record a version, add it to current branch

  • +
  • git commit --amend: amend our last commit

  • +
  • git branch: show which branch we’re on

  • +
  • git branch NAME: create a new branch called “name”

  • +
  • git restore FILE: restore last committed/staged version of FILE, losing unstaged changes

  • +
  • git switch --create BRANCH-NAME: create a new branch and switch to it

  • +
  • git revert HASH: create a new commit which reverts commit HASH

  • +
  • git reset --soft HASH: remove all commits after HASH, but keep their modifications as staged changes

  • +
  • git reset --hard HASH: remove all commits after HASH, permanently throwing away their changes

  • +
  • git merge BRANCH-NAME: merge branch BRANCH-NAME into current branch

  • +
  • git grep PATTERN: search for patterns in tracked files

  • +
  • git annotate FILE: find out when a specific line got introduced and by whom

  • +
  • git bisect: find a commit which broke some functionality

  • +
+
+
+
+

Customizing Git

+
+

Shell prompt

+
+

Instructor note

+

Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like.

+
+

You can make your shell display contextual information about +your Git state even at all times.

+

Here are few example projects that make this possible and easy:

+ +
+
+

More useful “diff” output

+

Delta is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +“diff” output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more.

+
+
+
+

Other resources

+ +
+
+

List of exercises

+
+

Summary

+

Basics:

+ +

Branching and merging:

+ +

Conflict resolution:

+ +

Inspecting history:

+ +

Using the Git staging area:

+ +

Undoing and recovering:

+ +

Interrupted work:

+ +
+
+

Full list

+

This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests.

+
+
+
+

Instructor guide

+
+

Schedule Day 1

+

Times here are in CE(S)T.

+
    +
  • 08:50 - 09:00 (10 min) Soft start and icebreaker question

  • +
  • 09:00 - 09:20 (20 min) Welcome and practical information

  • +
  • 09:20 - 09:35 (15 min) Motivation

  • +
  • 09:35 - 09:50 (15 min) Basics - configuration and first commits

  • +
  • 09:50 - 10:00 (10 min) Break

  • +
  • 10:00 - 10:20 (20 min) Exercise

    +
      +
    • Record changes

    • +
    • Optional exercises

    • +
    +
  • +
  • 10:20 - 10:40 (20 min) Basics - history, commit log, ignoring

  • +
  • 10:40 - 11:00 (20 min) Exercise

    +
      +
    • One or all optional exercises

    • +
    +
  • +
  • 11:00 - 12:00: Lunch break

  • +
  • 12:00 - 12:15 (15 min) Branching and merging

  • +
  • 12:15 - 12:35 (20 min) Exercise

    +
      +
    • Branch-1

    • +
    • Branch-2

    • +
    +
  • +
  • 12:35 - 12:50 (15 min) Summarize/discuss branching and merging

  • +
  • 12:50 - 13:00 (10 min) Break

  • +
  • 13:00 - 13:20 (20 min) Conflict resolution

  • +
  • 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow?

  • +
+
+
+

Schedule Day 2

+

Times here are in CE(S)T.

+
    +
  • 08:50 - 09:00 (10 min) Soft start and icebreaker question

  • +
  • 09:00 - 09:10 (10 min) Recap and Q&A from day 1

  • +
  • 09:10 - 09:25 (15 min) Sharing repositories online

  • +
  • 09:25 - 09:50 (25 min) Exercise

    +
      +
    • Set up SSH keys

    • +
    • Pushing our guacamole recipe repository to GitHub

    • +
    • Clone repository

    • +
    +
  • +
  • 09:50 - 10:00 (10 min) Break

  • +
  • 10:00 - 10:15 (15 min) Inspecting history

  • +
  • 10:15 - 10:45 (30 min) Exercise

    +
      +
    • History-1

    • +
    • History-2 is optional

    • +
    +
  • +
  • 10:45 - 11:00 (15 min) Summarize/discuss inspecting history

  • +
  • 11:00 - 12:00: Lunch break

  • +
  • 12:00 - 12:15 (15 min) Undoing and recovering

  • +
  • 12:15 - 12:40 (25 min) Exercises

    +
      +
    • Undoing-1

    • +
    • Undoing-2

    • +
    • Undoing-3

    • +
    +
  • +
  • 12:40 - 11:50 (10 min) Summarize undoing and recovering and discussion and mention that staging area exists

  • +
  • 12:50 - 13:00 (10 min) Break

  • +
  • 13:00 - 13:20 (20 min) How much Git is necessary?

  • +
  • 13:20 - 13:30 (10 min) Q&A, feedback, and what will we be doing tomorrow?

  • +
+
+
+

Installation reminders for each day

+
    +
  • Day 1: Git configuration

  • +
  • Day 2: SSH set up (if you don’t, sharing repositories online will be demo)

  • +
+
+
+

Why we teach this lesson

+

Everyone should be using a version control system for their work, even if they’re working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories.

+

Specific motivations:

+
    +
  • Code easily becomes a disaster without version control

  • +
  • Mistakes happen - Git offers roll-back functionality and easy backup mechanism

  • +
  • One often needs to work on multiple things in parallel - branches solve that problem

  • +
  • Git enables people to collaborate on code or text without stepping on each other’s toes

  • +
  • Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, +and if bugs are found one can find out exactly when it was introduced

  • +
+

Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices (e.g. how to use the staging area), which is useful for more experienced users.

+
+
+

Intended learning outcomes

+

By the end of this lesson, learners should:

+
    +
  • realize that version control is very important and Git is a valuable tool to learn and use

  • +
  • understand that Git is configurable and know how to set basic configurations

  • +
  • be able to set up Git repositories and make commits

  • +
  • understand that information on commits, branches etc. are stored under .git/, and have a +mental model of how that relates to the working directory

  • +
  • have a mental model of the different states a file can have in Git (untracked, modified, staged, unmodified)

  • +
  • know how to write good commit messages

  • +
  • have an idea of how the staging area can be used to craft good commits

  • +
  • know how to undo commits using git revert and discard changes using git restore

  • +
  • understand that git restore can be dangerous if changes have not been staged

  • +
  • know how to create branches and switch between branches

  • +
  • have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way

  • +
  • know how to merge branches and understand what that means in terms of combining different modifications

  • +
  • know how to resolve conflicts, or to abort conflicting merges

  • +
  • realize that conflicts are generally a good thing since they prevent incorrect merges

  • +
  • be able to set up a repository on GitHub and connect it with local repository

  • +
  • push changes to a remote repository

  • +
  • know a few ways to search through a repository and its history

  • +
+
+
+

How to teach this lesson

+
+

Take first editor steps slowly

+

Some participants will be new to using a terminal text editor so please open, +edit, and close the editor (Nano) slowly in first type-along sessions and +exercises to avoid that participants will fall behind the instructor. At one +point a student did not follow the file edits of the instructor, and to correct +the mistake they had to do a manual merge, which they were not ready for.

+
+
+

How to use the exercises

+

Most episodes have standard exercises followed by optional (often more advanced) exercises +for more experienced learners so they don’t get bored waiting for the newcomers. +The instructor should briefly introduce the exercises and mention that after finishing the +standard exercise (and indicating that using the green sticky) the learners can move on to the +optional ones if they wish. When at least half of the learners have raised the green sticky +the instructor should go through the standard exercise to describe its most important take-home messages. +It’s also fine to briefly go though important points from the optional exercises, but don’t spend +too much time on it since everyone will not have attempted them.

+
+
+

“Test your understanding” exercises

+

Some episodes have a “test your understanding” exercise at the end which is intended as formative assessment, +i.e. an activity that provides feedback to instructors and learners on whether learning objectives are being met. +The instructor should end each episode by posing the “test your understanding” multiple-choice question, +giving learners a minute to think about it, and then asking for the right answer or asking learners to raise their +hands to signal which answer they think is correct.

+
+
+

Inspecting history

+

Key lesson is how to find when something is broken or what commit has broken +the code.

+

It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that git annotate +and git show are available on GitHub and GitLab.

+

When discussing git annotate and git bisect the “when” is more important +than “who”. It is not to blame anybody but rather to find out whether published +results are affected.

+

Discuss how one would find out this information without version control.

+

Questions to involve participants:

+
    +
  • Have you ever found a bug in your code and wondered whether it has affected published results?

  • +
  • Have you ever wondered when, and by whom, a particular line of code was introduced?

  • +
  • Have you ever found out that a code behaves differently than it used to but you are not sure when +precisely this changed?

  • +
+

Confusion during git bisect exercise:

+

Learners may get stuck in the git bisect exercise if they incorrectly assign a commit +as bad or good. +To leave the bisect mode and return to the commit before git bisect start was issued, +one can do

+
$ git bisect reset
+
+
+

and start over if needed.

+
+
+

Live better than reading the website material

+

It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier.

+
+
+

Log your history in a separate window

+

The screencasting (shell window cheatsheet) hints have been moved to +the presenting +manual.

+
+
+

Create a cheatsheet on the board

+

For in-person workshops, create a “cheatsheet” on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven’t forgotten anything. Re-create and expand in future git lessons. +One strategy is:

+
    +
  • a common section for basic commands: init, config, clone, help, stash

  • +
  • info commands, can be run anytime: status, log, diff, graph

  • +
  • A section for all the commands that move code from different states: +add, commit, etc. See the visual cheat sheet below.

  • +
+

You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it’s probably too confusing to use after this course. But, the idea +of commands moving from the “working dir”, “staging area”, “commits”, +etc is good.

+
+Example cheat sheet +
+

Example cheat sheet.

+
+
+

We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to.

+
+
+

Draw a graph on the board

+

Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run git graph, then do the command, +then look at git graph again.

+
+
+

Repeat the following points

+
    +
  • Always check git status, git diff, and git graph (our alias) before and +after every command until you get used to things. These give you a clear view +into what is going on, the key to knowing what you are doing. Even +after you are used to things… anytime you do something you do +infrequently, it’s good to check.

  • +
  • git graph is a direct representation of what we are drawing on the +board and should constantly be compared to it.

  • +
  • Once you git add something, it’s almost impossible to lose it. +This is used all the time, for example once you commit or even add +it is hard to lose. Commit before you merge or rebase. And so on.

  • +
+
+
+

Start from identical environment

+

You probably have a highly optimized bash and git environment - one +that is different from students. Move .gitconfig and .bashrc out +of the way before you start so that your environment is identical to +what students have.

+
+
+
+
+
+
+
+

Why GitHub?

+

In this introduction we will mention and use +GitHub but also +GitLab and +Bitbucket allow similar workflows and +basically everything that we will discuss is transferable. With this +material and these exercises we do not implicitly endorse the company +GitHub. We have chosen to demonstrate a +number of concepts using examples with +GitHub because it is currently the most +popular web platform for hosting Git repositories and the chance is +high that you will interact with +GitHub-based repositories even if you choose +to host your Git repository on another platform.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/singlehtml/objects.inv b/branch/2023-version/singlehtml/objects.inv new file mode 100644 index 00000000..64062e47 Binary files /dev/null and b/branch/2023-version/singlehtml/objects.inv differ diff --git a/branch/2023-version/staging-area/index.html b/branch/2023-version/staging-area/index.html new file mode 100644 index 00000000..3baf7a6d --- /dev/null +++ b/branch/2023-version/staging-area/index.html @@ -0,0 +1,493 @@ + + + + + + + Using the Git staging area — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Using the Git staging area

+
+

Objectives

+
    +
  • Learn how to tell a story with your commit history.

  • +
  • Demystify the Git staging area.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 10 min exercise

  • +
+
+
+

Commit history is telling a story

+

Your current code is very important, but the history can be just +as important - it tells a story about how your code came to be.

+
    +
  • Each individual line of code rarely stands alone.

  • +
  • You often want to see all the related changes together.

  • +
  • But you also hardly ever do one thing at once.

  • +
+

Along with your code, Git creates a history for you, and if your +history is clear then you are a long way to organized code.

+
+

Discussion

+

Here are five types of history. What are the advantages and +disadvantages of each, when you look at it later?

+

Example 1:

+
b135ec8 add features A, B, and C
+
+
+

Example 2 (newest commit is on top):

+
6f0d49f implement feature C
+fee1807 implement feature B
+6fe2f23 implement feature A
+
+
+

Example 3:

+
ab990f4 saving three months of miscellaneous work I forgot to commit
+
+
+

Example 4 (newest commit is on top):

+
bf39f9d more work on feature B
+45831a5 removing debug prints for feature A and add new file
+bddb280 more work on feature B and make feature A compile again
+72d78e7 feature A did not work and started work on feature B
+b135ec8 now feature A should work
+72e0211 another fix to make it compile
+61dd3a3 forgot file and bugfix
+49dc419 wip (work in progress)
+
+
+

Example 5 (newest commit is on top):

+
1949dc4 Work of 2020-04-07
+a361dd3 Work of 2020-04-06
+1172e02 Work of 2020-04-03
+e772d78 Work of 2020-04-02
+
+
+

Discuss these examples. Can you anticipate problems?

+
+

We want to have nice commits. But we also want to “save often” +(checkpointing) - how can we have both?

+
    +
  • We will now learn to create nice commits using git commit --patch and/or the staging area.

  • +
  • Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits.

  • +
  • The staging area isn’t the only way to organize your history nicely, some alternatives are discussed at the end of the lesson.

  • +
+
+
+

Interactive commits

+
    +
  • The simplest ways to solve this is to do interactive commits: +the git commit --patch option (or git commit -p for short).

  • +
  • It will present you with every change you have made individually, +and you can decide which ones to commit right now.

  • +
  • Reference and key commands

    +
      +
    • git commit --patch to start the interactive commit

    • +
    • y to use the change

    • +
    • n to skip the change

    • +
    • s (split) if there are several changes grouped together, but +separated by a blank line, split them into separate choices.

    • +
    • q aborts everything.

    • +
    • ? for more options.

    • +
    +
  • +
  • The -p option is also available on commit, restore, checkout, reset, and add.

  • +
+
+
+

Exercise: Interactive commits

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+
+
+

The staging area

+
    +
  • The interactive commits above are great, but what if there are so +many changes that you can’t sort them out in one shot?

  • +
  • What if you make progress and want to record it somehow, but it’s +not ready to be committed?

  • +
  • The staging area is a place to record things before committing.

  • +
+
+

Instructor note

+

We give two examples and the instructor can pick one or both:

+
    +
  • Analogy using moving boxes

  • +
  • Analogy using shopping receipts

  • +
+
+
+

Discussion

+

Analogy using moving boxes

+
    +
  • You’re moving and you have a box to pack your things in.

  • +
  • You can put stuff into the box, but you can also take stuff out of the box.

  • +
  • You wouldn’t want to mix items from the bathroom, kitchen, and living room +into the same box.

  • +
  • The box corresponds to the staging area of Git, where you can craft your commits.

  • +
  • Committing is like sealing the box and sticking a label on it.

  • +
  • You wouldn’t want to label your box with “stuff”, but rather give a more +descriptive label.

  • +
  • See also https://dev.to/sublimegeek/git-staging-area-explained-like-im-five-1anh

  • +
+

Analogy using shopping receipts

+
    +
  • You need to go shopping and buy some stuff for work and for home. +You need two separate receipts.

  • +
  • Bad idea: go through the store get home stuff, pay, start at the +beginning and go through the store again. This is inefficient and +annoying.

  • +
  • What you actually do:

    +
      +
    • Go through the store and put everything you need in your shopping +basket.

    • +
    • Get to the check-out. Put your home stuff on the conveyor belt +(git add). Check both the belt (git diff --staged) and your +basket (git diff) to make sure you got all your home stuff.

    • +
    • Pay (git commit)

    • +
    • Repeat for work stuff.

    • +
    +
  • +
+

In order to keep organized, you have to use multiple locations to +stage things in sequence.

+
+
+
+

Staging area commands

+

The staging area is a middle ground between what you have done to your files +(the working directory) and what you have last committed (the HEAD commit). +Just like the name implies, it lets you prepare (stage) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since you can modify and stage several times before committing.

+

git add stages/prepares for the next commit:

+
                git add
+ [project*]  <------------  project*
+                               ^
+                               | modify with editor
+                               |
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git commit creates a new commit:

+
  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+  HEAD~2          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git reset --soft HEAD~1 (move HEAD back by one but keep changes and stage +them) would do the opposite of git commit. (in this case, HEAD +is literally this - not a replacement)

+

Going back to the last staged version:

+
              git restore
+ [project*]  ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Unstaging changes with git restore --staged:

+
          git restore --staged
+             ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Discarding unstaged changes:

+
                            project*
+                               |
+                               | git restore
+                               v
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Comparing:

+
                git diff
+ [project*]  <----------->  project*
+    ^                          ^
+    | git diff --staged        | git diff HEAD
+    v                          v
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+
+Staging basics +
+

The different states of the repository and the commands to move from one to +another.

+
+
+
+
+

Exercise: Using the staging area

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+

Discussion

+
    +
  • When is it better to “save” a change as commit, when is it better to “save” +it with git add?

  • +
  • Is it a problem to commit many small changes?

  • +
+
+
+

Keypoints

+
    +
  • The staging area helps us to create well-defined commits.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/under-the-hood/index.html b/branch/2023-version/under-the-hood/index.html new file mode 100644 index 00000000..a7f7b75f --- /dev/null +++ b/branch/2023-version/under-the-hood/index.html @@ -0,0 +1,321 @@ + + + + + + + Git under the hood — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Git under the hood

+
+

Objectives

+
    +
  • Verify that branches are pointers to commits and extremely lightweight.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+Git under the hood +
+
+

Down the rabbit hole

+

When working with Git, you will never need to go inside .git, but in this +exercise we will, in order to learn about how branches are implemented in Git.

+

For this exercise create a new repository and commit a couple of changes.

+

Now that we’ve made a couple of commits let us look at what is happening under +the hood.

+
$ cd .git
+$ ls -l
+
+drwxr-xr-x   - user 25 Aug 15:51 branches
+.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG
+.rw-r--r--  92 user 25 Aug 15:51 config
+.rw-r--r--  73 user 25 Aug 15:51 description
+.rw-r--r--  21 user 25 Aug 15:51 HEAD
+drwxr-xr-x   - user 25 Aug 15:51 hooks
+.rw-r--r-- 137 user 25 Aug 15:52 index
+drwxr-xr-x   - user 25 Aug 15:51 info
+drwxr-xr-x   - user 25 Aug 15:52 logs
+drwxr-xr-x   - user 25 Aug 15:52 objects
+drwxr-xr-x   - user 25 Aug 15:51 refs
+
+
+

Git stores everything under the .git folder in your repository. In fact, the +.git directory is the Git repository.

+

Previously when you wrote the commit messages using your text editor, they +were in fact saved to COMMIT_EDITMSG.

+

Each commit in Git is stored as a “blob”. This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file.

+

Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string).

+
+A commit inside Git +
+

States of a Git file. Image from the Pro Git book. License CC BY 3.0.

+
+
+

Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a directed acyclic +graph (do not worry +if the term is not familiar).

+
+A commit and its parents +
+

A commit and its parents. Image from the Pro Git book. License CC BY 3.0.

+
+
+

All branches and tags in Git are pointers to commits.

+
+
+

Git is basically a content-addressed storage system

+ +

Let us poke a bit into raw objects! Start with:

+
$ git cat-file -p HEAD
+
+
+

Then explore the tree object, then the file object, etc. recursively using the hashes you see.

+
+
+

Demonstration: experimenting with branches

+

Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an “Aha!” moment and provide us a +good understanding of the underlying model.

+

We are starting from the main branch and create an idea branch:

+
$ git status
+
+On branch main
+nothing to commit, working tree clean
+
+
+
$ git switch --create idea
+
+Switched to a new branch 'idea'
+
+
+
$ git branch
+
+* idea
+  main
+
+
+

Now let us go in:

+
$ cd .git
+$ cd refs/heads
+$ ls -l
+
+.rw-r--r-- 41 user 25 Aug 15:54 idea
+.rw-r--r-- 41 user 25 Aug 15:52 main
+
+
+

Let us check what the idea file looks like +(do not worry if the hash is different):

+
$ cat idea
+
+045e3db14740c60684d745e5fb891ae71e335611
+
+
+

Now let us replicate this file:

+
$ cp idea idea-2
+$ cp idea idea-3
+$ cp idea idea-4
+$ cp idea idea-5
+
+
+

Let us go up two levels and inspect the file HEAD:

+
$ cd ../..
+$ cat HEAD
+
+ref: refs/heads/idea
+
+
+

Let us open this file and change it to:

+
ref: refs/heads/idea-3
+
+
+

Now we are ready for the aha moment! +First let us go back to the working area:

+
$ cd ..
+
+
+

Now - on which branch are we?

+
$ git branch
+
+  idea
+  idea-2
+* idea-3
+  idea-4
+  idea-5
+  main
+
+
+
+

Discussion

+

Discuss the findings with other course participants.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/2023-version/what-to-avoid/index.html b/branch/2023-version/what-to-avoid/index.html new file mode 100644 index 00000000..85a8b76e --- /dev/null +++ b/branch/2023-version/what-to-avoid/index.html @@ -0,0 +1,197 @@ + + + + + + + What to avoid — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

What to avoid

+

The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas.

+

Postponing commits because the changes are “unfinished”/”ugly”: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all.

+

Not updating your branch before starting new work: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later.

+

Commit unrelated changes together: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects.

+

Too ambitious branch which risks to never get completed: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere.

+

Committing generated files: See Ignoring files and paths with .gitignore.

+

Over-engineering the branch layout and safeguards in small projects: This +may prevent people from contributing (maybe even including yourself?). Add more restrictions and safeguards as +the project and the group of collaborators grows.

+

Commit messages that explain what has been changed but do not explain why it has been +changed: This is as useful as code comments which describe the “obvious” such +as “this is a loop” instead of explaining why something is done this way. +But don’t let perfect commit messages stop you from the most important point, committing often (first point).

+

Commit huge files: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent git rm does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request.

+
+

Discussion

+

Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/.buildinfo b/branch/main/.buildinfo new file mode 100644 index 00000000..5a3dbcf9 --- /dev/null +++ b/branch/main/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: e21ba9a26a1fa041e43d0d2e9e34e5b6 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/branch/main/.nojekyll b/branch/main/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/main/_images/add-file.png b/branch/main/_images/add-file.png new file mode 100644 index 00000000..9683b2db Binary files /dev/null and b/branch/main/_images/add-file.png differ diff --git a/branch/main/_images/annotate.png b/branch/main/_images/annotate.png new file mode 100644 index 00000000..8021920a Binary files /dev/null and b/branch/main/_images/annotate.png differ diff --git a/branch/main/_images/annotate1.png b/branch/main/_images/annotate1.png new file mode 100644 index 00000000..93416b2a Binary files /dev/null and b/branch/main/_images/annotate1.png differ diff --git a/branch/main/_images/bare-repository.png b/branch/main/_images/bare-repository.png new file mode 100644 index 00000000..45286f93 Binary files /dev/null and b/branch/main/_images/bare-repository.png differ diff --git a/branch/main/_images/browse-files.png b/branch/main/_images/browse-files.png new file mode 100644 index 00000000..5fcc3528 Binary files /dev/null and b/branch/main/_images/browse-files.png differ diff --git a/branch/main/_images/cheat-sheet.jpg b/branch/main/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/branch/main/_images/cheat-sheet.jpg differ diff --git a/branch/main/_images/code-portion.png b/branch/main/_images/code-portion.png new file mode 100644 index 00000000..39356bd5 Binary files /dev/null and b/branch/main/_images/code-portion.png differ diff --git a/branch/main/_images/commit-and-tree.png b/branch/main/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/branch/main/_images/commit-and-tree.png differ diff --git a/branch/main/_images/commit-changes.png b/branch/main/_images/commit-changes.png new file mode 100644 index 00000000..4c0546c6 Binary files /dev/null and b/branch/main/_images/commit-changes.png differ diff --git a/branch/main/_images/commits-and-parents.png b/branch/main/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/branch/main/_images/commits-and-parents.png differ diff --git a/branch/main/_images/commits.png b/branch/main/_images/commits.png new file mode 100644 index 00000000..b154c666 Binary files /dev/null and b/branch/main/_images/commits.png differ diff --git a/branch/main/_images/create-repository-with-readme.png b/branch/main/_images/create-repository-with-readme.png new file mode 100644 index 00000000..24118344 Binary files /dev/null and b/branch/main/_images/create-repository-with-readme.png differ diff --git a/branch/main/_images/create-repository.png b/branch/main/_images/create-repository.png new file mode 100644 index 00000000..80fb99c2 Binary files /dev/null and b/branch/main/_images/create-repository.png differ diff --git a/branch/main/_images/edit-file.png b/branch/main/_images/edit-file.png new file mode 100644 index 00000000..f7527bd0 Binary files /dev/null and b/branch/main/_images/edit-file.png differ diff --git a/branch/main/_images/file-history.png b/branch/main/_images/file-history.png new file mode 100644 index 00000000..5e42fbe9 Binary files /dev/null and b/branch/main/_images/file-history.png differ diff --git a/branch/main/_images/fork.png b/branch/main/_images/fork.png new file mode 100644 index 00000000..0c992d3d Binary files /dev/null and b/branch/main/_images/fork.png differ diff --git a/branch/main/_images/forking.png b/branch/main/_images/forking.png new file mode 100644 index 00000000..73c4d71a Binary files /dev/null and b/branch/main/_images/forking.png differ diff --git a/branch/main/_images/git-annotate.png b/branch/main/_images/git-annotate.png new file mode 100644 index 00000000..60c6f7c2 Binary files /dev/null and b/branch/main/_images/git-annotate.png differ diff --git a/branch/main/_images/git-branch-1.svg b/branch/main/_images/git-branch-1.svg new file mode 100644 index 00000000..4b735e40 --- /dev/null +++ b/branch/main/_images/git-branch-1.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + m2 + + + m3 + + + m1 + + + + + main + + + + + HEAD + + + diff --git a/branch/main/_images/git-branch-2.svg b/branch/main/_images/git-branch-2.svg new file mode 100644 index 00000000..dde628b6 --- /dev/null +++ b/branch/main/_images/git-branch-2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l1 + + + e2 + + + e1 + + + m5 + + + m4 + + + m2 + + + m3 + + + m1 + + + + + less-salt + + + + + HEAD + + + + + experiment + + + + + main + + + diff --git a/branch/main/_images/git-branch-3.svg b/branch/main/_images/git-branch-3.svg new file mode 100644 index 00000000..19231579 --- /dev/null +++ b/branch/main/_images/git-branch-3.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + e2 + + + m3 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + + + less-salt + + + + + experiment + + + diff --git a/branch/main/_images/git-collaborative.svg b/branch/main/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/branch/main/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/branch/main/_images/git-deleted-branches.svg b/branch/main/_images/git-deleted-branches.svg new file mode 100644 index 00000000..d54c0032 --- /dev/null +++ b/branch/main/_images/git-deleted-branches.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + m5 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + diff --git a/branch/main/_images/git-log-github.png b/branch/main/_images/git-log-github.png new file mode 100644 index 00000000..db44d29b Binary files /dev/null and b/branch/main/_images/git-log-github.png differ diff --git a/branch/main/_images/git-log-terminal.png b/branch/main/_images/git-log-terminal.png new file mode 100644 index 00000000..56493e6e Binary files /dev/null and b/branch/main/_images/git-log-terminal.png differ diff --git a/branch/main/_images/git-merge-1.svg b/branch/main/_images/git-merge-1.svg new file mode 100644 index 00000000..005301ab --- /dev/null +++ b/branch/main/_images/git-merge-1.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + m3 + + + l1 + + + m7 + + + m4 + + + + + experiment + + + + + less-salt + + + + + main + + + + + HEAD + + + diff --git a/branch/main/_images/git-merge-2.svg b/branch/main/_images/git-merge-2.svg new file mode 100644 index 00000000..cb268ee7 --- /dev/null +++ b/branch/main/_images/git-merge-2.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + l1 + + + m5 + + + m4 + + + + + experiment + + + + + main + + + + + HEAD + + + + + less-salt + + + diff --git a/branch/main/_images/git-pre-ff.svg b/branch/main/_images/git-pre-ff.svg new file mode 100644 index 00000000..e4d8bc5b --- /dev/null +++ b/branch/main/_images/git-pre-ff.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e1 + + + e2 + + + m7 + + + m8 + + + n3 + + + n1 + + + m5 + + + l1 + + + m6 + + + m4 + + + n2 + + + m2 + + + m3 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + main + + + diff --git a/branch/main/_images/git_stage_commit.svg b/branch/main/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/branch/main/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/main/_images/github-branches-overview.png b/branch/main/_images/github-branches-overview.png new file mode 100644 index 00000000..89e0058d Binary files /dev/null and b/branch/main/_images/github-branches-overview.png differ diff --git a/branch/main/_images/github-branches.png b/branch/main/_images/github-branches.png new file mode 100644 index 00000000..3a6a8ff9 Binary files /dev/null and b/branch/main/_images/github-branches.png differ diff --git a/branch/main/_images/github-comparing-changes.png b/branch/main/_images/github-comparing-changes.png new file mode 100644 index 00000000..735b990b Binary files /dev/null and b/branch/main/_images/github-comparing-changes.png differ diff --git a/branch/main/_images/github-contribute.png b/branch/main/_images/github-contribute.png new file mode 100644 index 00000000..a149e9f3 Binary files /dev/null and b/branch/main/_images/github-contribute.png differ diff --git a/branch/main/_images/github-create-branch.png b/branch/main/_images/github-create-branch.png new file mode 100644 index 00000000..e7958ff2 Binary files /dev/null and b/branch/main/_images/github-create-branch.png differ diff --git a/branch/main/_images/github-create-tag.png b/branch/main/_images/github-create-tag.png new file mode 100644 index 00000000..f08f5878 Binary files /dev/null and b/branch/main/_images/github-create-tag.png differ diff --git a/branch/main/_images/github-merged.png b/branch/main/_images/github-merged.png new file mode 100644 index 00000000..eea47d93 Binary files /dev/null and b/branch/main/_images/github-merged.png differ diff --git a/branch/main/_images/github-navigate-to-branch.png b/branch/main/_images/github-navigate-to-branch.png new file mode 100644 index 00000000..42b0f753 Binary files /dev/null and b/branch/main/_images/github-navigate-to-branch.png differ diff --git a/branch/main/_images/gophers.png b/branch/main/_images/gophers.png new file mode 100644 index 00000000..741406ba Binary files /dev/null and b/branch/main/_images/gophers.png differ diff --git a/branch/main/_images/history.png b/branch/main/_images/history.png new file mode 100644 index 00000000..6384e302 Binary files /dev/null and b/branch/main/_images/history.png differ diff --git a/branch/main/_images/history1.png b/branch/main/_images/history1.png new file mode 100644 index 00000000..06662c31 Binary files /dev/null and b/branch/main/_images/history1.png differ diff --git a/branch/main/_images/license.png b/branch/main/_images/license.png new file mode 100644 index 00000000..f4cadf0d Binary files /dev/null and b/branch/main/_images/license.png differ diff --git a/branch/main/_images/meld.png b/branch/main/_images/meld.png new file mode 100644 index 00000000..774f9cd1 Binary files /dev/null and b/branch/main/_images/meld.png differ diff --git a/branch/main/_images/mergetool.png b/branch/main/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/branch/main/_images/mergetool.png differ diff --git a/branch/main/_images/network.png b/branch/main/_images/network.png new file mode 100644 index 00000000..e0fcb2fb Binary files /dev/null and b/branch/main/_images/network.png differ diff --git a/branch/main/_images/new-repo-form.png b/branch/main/_images/new-repo-form.png new file mode 100644 index 00000000..b808ee0b Binary files /dev/null and b/branch/main/_images/new-repo-form.png differ diff --git a/branch/main/_images/new-repo-plus.png b/branch/main/_images/new-repo-plus.png new file mode 100644 index 00000000..e58ba5d8 Binary files /dev/null and b/branch/main/_images/new-repo-plus.png differ diff --git a/branch/main/_images/new-repository.png b/branch/main/_images/new-repository.png new file mode 100644 index 00000000..aff76772 Binary files /dev/null and b/branch/main/_images/new-repository.png differ diff --git a/branch/main/_images/pen-symbol.png b/branch/main/_images/pen-symbol.png new file mode 100644 index 00000000..044902a3 Binary files /dev/null and b/branch/main/_images/pen-symbol.png differ diff --git a/branch/main/_images/preview.png b/branch/main/_images/preview.png new file mode 100644 index 00000000..8a602b66 Binary files /dev/null and b/branch/main/_images/preview.png differ diff --git a/branch/main/_images/search.png b/branch/main/_images/search.png new file mode 100644 index 00000000..4462f71e Binary files /dev/null and b/branch/main/_images/search.png differ diff --git a/branch/main/_images/search1.png b/branch/main/_images/search1.png new file mode 100644 index 00000000..89c0e25a Binary files /dev/null and b/branch/main/_images/search1.png differ diff --git a/branch/main/_images/show.png b/branch/main/_images/show.png new file mode 100644 index 00000000..12d7915c Binary files /dev/null and b/branch/main/_images/show.png differ diff --git a/branch/main/_images/staging-basics.svg b/branch/main/_images/staging-basics.svg new file mode 100644 index 00000000..13df8bf5 --- /dev/null +++ b/branch/main/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + restore + add + commit + restore + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/branch/main/_images/stranger.jpg b/branch/main/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/branch/main/_images/stranger.jpg differ diff --git a/branch/main/_images/upload-files.png b/branch/main/_images/upload-files.png new file mode 100644 index 00000000..fd3ef8cc Binary files /dev/null and b/branch/main/_images/upload-files.png differ diff --git a/branch/main/_images/vscode-add-and-commit.png b/branch/main/_images/vscode-add-and-commit.png new file mode 100644 index 00000000..d9a09c46 Binary files /dev/null and b/branch/main/_images/vscode-add-and-commit.png differ diff --git a/branch/main/_images/vscode-authorize.png b/branch/main/_images/vscode-authorize.png new file mode 100644 index 00000000..4d45dc2d Binary files /dev/null and b/branch/main/_images/vscode-authorize.png differ diff --git a/branch/main/_images/vscode-change-branch.png b/branch/main/_images/vscode-change-branch.png new file mode 100644 index 00000000..c1a5f00a Binary files /dev/null and b/branch/main/_images/vscode-change-branch.png differ diff --git a/branch/main/_images/vscode-create-branch.png b/branch/main/_images/vscode-create-branch.png new file mode 100644 index 00000000..71b275a9 Binary files /dev/null and b/branch/main/_images/vscode-create-branch.png differ diff --git a/branch/main/_images/vscode-merging.png b/branch/main/_images/vscode-merging.png new file mode 100644 index 00000000..7e5880e7 Binary files /dev/null and b/branch/main/_images/vscode-merging.png differ diff --git a/branch/main/_images/vscode-open-terminal.png b/branch/main/_images/vscode-open-terminal.png new file mode 100644 index 00000000..1be92267 Binary files /dev/null and b/branch/main/_images/vscode-open-terminal.png differ diff --git a/branch/main/_images/vscode-publish-to-github1.png b/branch/main/_images/vscode-publish-to-github1.png new file mode 100644 index 00000000..883e756c Binary files /dev/null and b/branch/main/_images/vscode-publish-to-github1.png differ diff --git a/branch/main/_images/vscode-publish-to-github2.png b/branch/main/_images/vscode-publish-to-github2.png new file mode 100644 index 00000000..d0055db4 Binary files /dev/null and b/branch/main/_images/vscode-publish-to-github2.png differ diff --git a/branch/main/_images/vscode-publish-to-github3.png b/branch/main/_images/vscode-publish-to-github3.png new file mode 100644 index 00000000..0f68d0ee Binary files /dev/null and b/branch/main/_images/vscode-publish-to-github3.png differ diff --git a/branch/main/_images/vscode-start.png b/branch/main/_images/vscode-start.png new file mode 100644 index 00000000..e7830807 Binary files /dev/null and b/branch/main/_images/vscode-start.png differ diff --git a/branch/main/_sources/aliases.md.txt b/branch/main/_sources/aliases.md.txt new file mode 100644 index 00000000..a257a1b7 --- /dev/null +++ b/branch/main/_sources/aliases.md.txt @@ -0,0 +1,156 @@ +(aliases)= + +# Aliases and configuration + +```{objectives} +- Learn to use aliases for most common commands. +``` + +Are you getting tired of typing so much? In Git you can define aliases (shortcuts): +- These are great because they can save you time typing. +- But it's easy to forget them, get confused, or be inconsistent with your colleagues. + +There is plenty of other configuration for Git, that can make it nicer. + + +## Aliases + +- Aliases offer a way to improve the usability of Git: for + example `git ci` instead of `git commit`. +- Aliases are based on simple string replacement in the command. +- Aliases can either be specific to a repository or global. + - Global aliases help you do the things you are used to across Git projects. + - Per-project aliases can also be created. +- Global aliases are stored in `~/.gitconfig`. + + +## Example alias: git graph + +A very useful shortcut which we use a lot in our workshops: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ cd your_git_repository +$ git graph +``` + + +## Using external commands + +It is possible to call external commands using the exclamation mark character "!". +In this example here we create a local alias which is +stored in `.git/config` and not synchronized with remotes: + +```console +$ cd your_git_repository +$ git config alias.hi '!echo hello' +$ git hi +``` + +```{discussion} Food for thought: When to alias? +- How many times should you wait before aliasing a command? +- Do you believe a list of generic two-letter acronyms for common commands will + save your time? +``` + + +## List of aliases the instructors use + +You are welcome to reuse, suggest, improve. +You can see your current aliases in `~/.gitconfig`. + +```console +$ git config --global alias.ap "add --patch" +$ git config --global alias.br branch +$ git config --global alias.ci "commit -v" +$ git config --global alias.cip "commit --patch -v" +$ git config --global alias.cl "clone --recursive" +$ git config --global alias.di diff +$ git config --global alias.dic "diff --staged --color-words" +$ git config --global alias.diw "diff --color-words" +$ git config --global alias.dis "!git --no-pager diff --stat" +$ git config --global alias.fe fetch +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ git config --global alias.rem remote +$ git config --global alias.st status +$ git config --global alias.su "submodule update --init --recursive" +``` + +Here is what they do: +- `ap`: add, selecting parts individually, interactively. +- `br`: branch (obvious) +- `ci`: commit (check in), with `-v` option for clarity +- `cip`: commit, selecting parts individually, interactively. +- `cl`: clone, init submodules (submodules are an advanced topic) +- `di`: diff (obvious) +- `dic`: diff of staging area vs last commit (what is about to be committed) +- `diw`: a word diff, color. Useful for small changes. +- `dis`: a "diffstat": what files are changed, not contents +- `fe`: fetch (obvious) +- `graph`: show whole git graph (so useful, some of us call it `l`) +- `rem`: remote (obvious) +- `st`: status (obvious) +- `su`: submodule update (advanced) + +A useful setting for the `p` aliases: +```console +$ git config --global interactive.singlekey true +``` + + +## Advanced aliases + +These are advanced aliases and configuration options. We won't explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages! + +```console +$ git config --global alias.cif "commit -v -p --fixup" +$ git config --global alias.rb "rebase --autosquash" +$ git config --global alias.rbi "rebase --interactive --autosquash" +$ git config --global alias.rbis "rebase --interactive --autosquash --autostash" +$ git config --global alias.rbs "rebase --autosquash --autostash" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard" +$ git config --global alias.new "log HEAD..HEAD@{upstream}" +$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}" +$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}" +$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all" +$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD" +$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat" +``` + +## Advanced Git configuration + +Besides aliases, you can do plenty of other configuration of `git`. +Here are some of the most common ones: + +```console +$ git config --global interactive.singlekey true +$ git config --global core.pager "less -RS" +$ git config --global core.excludesfile ~/.gitignore +$ git config --global merge.conflictstyle diff3 +$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]" +$ git config --global diff.mnemonicPrefix true +``` + +Do you get tired of typing and copying and pasting your remote names +all the time, like `git@github.com:myusername`? You can create remote +aliases like this: + +```console +$ git config --global url.git@github.com:.insteadOf gh: +$ git config --global url.git@github.com:/username/.insteadOf ghu: +``` + +Then, when you add a remote `ghu:recipe`, it will automatically be +translated to `git@github.com:/username/recipe` using a simple prefix +matching. + + +```{keypoints} +- If you are frustrated about remembering a command, you should create an alias. +``` diff --git a/branch/main/_sources/archaeology.md.txt b/branch/main/_sources/archaeology.md.txt new file mode 100644 index 00000000..c8fade0f --- /dev/null +++ b/branch/main/_sources/archaeology.md.txt @@ -0,0 +1,488 @@ +# Inspecting history + +:::{objectives} +- Be able find a line of code, find out why it was introduced and when. +- Be able to quickly find the commit that changed a behavior. +::: + +:::{instructor-note} +- 30 min teaching/type-along +- 20 min exercise +::: + + +## Command line, GitHub, and VS Code + +As usual, we offer ways to do this with the command line, VS Code, and +GitHub. + +* **Command line** is most powerful and relatively easy with this. + You may also use it along with other things. If you haven't tried + it yet, we'd recommend you to give it a try. +* The **GitHub** web interface allows many things to be done, but not + everything. +* **VS Code** allows some of these, but for some it's easier to open + the VS Code terminal and run git there. + + +## Our toolbox for history inspection + +:::{instructor-note} +First the instructor demonstrates few commands on a real life example +repository (mentioned in the amazing site [The +Programming Historian](https://programminghistorian.org/)). +Later we will practice these in an archaeology exercise (below). +::: + + +### Warm-up: ["Git History" browser](https://githistory.xyz/) + +As a warm-up we can try the ["Git History" browser](https://githistory.xyz/) +on the README.rst file of the [networkx](https://github.com/networkx/networkx) repository: + +- Visit and browse (use left/right keys). +- You can try this on some of your GitHub repositories, too! + + +### Searching text patterns in the repository + +With `git grep` you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or +some error message printed. + +:::::{tabs} + ::::{group-tab} Command line + The Git command is as described above: + ```console + $ git grep TEXT + $ git grep "some text with spaces" + ``` + + In the [networkx](https://github.com/networkx/networkx) repository you can try: + + ```console + $ git clone https://github.com/networkx/networkx + $ cd networkx + $ git grep -i fixme + ``` + + While `git grep` searches the **current state** of the repository, + it is also possible to search through all changes with `git log -S sometext` + which can be useful to find where something got removed. + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/search.png + :alt: Searching for "fixme" in a GitHub repository + :width: 100% + :class: with-border + + Searching for "fixme" in a GitHub repository. + ``` + :::: + + ::::{group-tab} VS Code + Our example repository is . + From a new VS Code window, select "Clone Git repository" and enter + that URL. + + Searching with the magnifying glass from the left sidebar is + equivalent to `git grep`. + :::: +::::: + + +### Inspecting individual commits + +:::::{tabs} + ::::{group-tab} Command line + We have seen this one before already. Using `git show` we can inspect an individual commit if + we know its hash: + + ```console + $ git show HASH + ``` + + For instance: + ```console + $ git show 759d589bdfa61aff99e0535938f14f67b01c83f7 + ``` + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/show.png + :alt: Inspecting an individual commit on GitHub + :width: 100% + :class: with-border + + Inspecting an individual commit on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + We don't know of a built-in way to see every single Git commit in + order (extensions allow this). You can open the terminal and run + the command line option. + + But, if you open single files, a "Timeline" view under the + explorer shows changes to *that file*. You can click on a change + to see the details. + :::: +::::: + + +### Line-by-line code annotation with metadata + +With `git annotate` you can see line by line who and **when** the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility. + +:::::{tabs} + ::::{group-tab} Command line + ```console + $ git annotate FILE + ``` + + Example: + ```console + $ git annotate networkx/convert_matrix.py + ``` + + If you annotate in a terminal and the file is longer than the screen, Git by default uses the program `less` to + scroll the output. + Use `/sometext` `` to find "sometext" and you can cycle through the results with `n` (next) and `N` (last). + You can also use page up/down to scroll. You can quit with `q`. + :::: + + ::::{group-tab} GitHub + We can try the same example in the browser: + + + ```{figure} img/archaeology/annotate.png + :alt: Screenshot of file annotation on GitHub + :width: 100% + :class: with-border + + Screenshot of file annotation on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + It seems this needs an extension. We'd recommend trying the + command line method for now. + :::: +::::: + +:::{discussion} +Discuss how these relatively trivial changes affect the annotation: +- Wrapping long lines of text/code into shorter lines +- Auto-formatting tools such as `black` +- Editors that automatically remove trailing whitespace +::: + + +### Inspecting code in the past + +:::::{tabs} + ::::{group-tab} Command line + We can create branches pointing to a commit in the past. + This is the recommended mechanism to inspect old code: + + ```console + $ git switch --create BRANCHNAME HASH + ``` + + Example (lines starting with "#" are only comments): + + ```console + $ # create branch called "older-code" from hash 347e6292419b + $ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9 + + $ # now you can navigate and inspect the code as it was back then + $ # ... + + $ # after we are done we can switch back to "main" + $ git switch main + + $ # if we like we can delete the "older-code" branch + $ git branch -d older-code + ``` + + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + + ```console + $ git checkout -b BRANCHNAME SOMEHASH + ``` + :::: + + ::::{group-tab} GitHub + We now know how to visit a specific commit: + + + Once we are there we can "Browse files" at that point in history. + + ```{figure} img/archaeology/browse-files.png + :alt: Browsing code in the past on GitHub + :width: 100% + :class: with-border + + Browsing code in the past on GitHub. + ``` + :::: + + ::::{group-tab} VS Code + Switch to "Source Control", then the "..." menu, then "Branch", then "Create new branch from..." and now you can type a commit identifier (hash). + + Make sure you change back to the main branch when you are done. + :::: +::::: + + +## Exercise + +This is described with the command line method, but by looking above +you can translate to the other options. + +:::::{exercise} Exercise: Explore basic archaeology commands (20 min) + Let us explore the value of these commands in an exercise. Future + exercises do not depend on this, so it is OK if you do not complete + it fully. + + Exercise steps: + - **Make sure you are not inside another Git repository** when running this + exercise. If you are, first step "outside" of it. + We want to avoid creating a Git repository inside another Git repository. + :::::{tabs} + ::::{group-tab} Command line + You can check if you are inside a Git repository with: + ```console + $ git status + + fatal: not a git repository (or any of the parent directories): .git + ``` + You want to see the above message which tells us that this is not a Git repository. + :::: + + ::::{group-tab} GitHub + This is not a problem in the GitHub web interface since we are not + creating a new local repository. + :::: + + ::::{group-tab} VS Code + "File" -> "New Window". + :::: + ::::: + + - Clone this repository: + . + :::::{tabs} + ::::{group-tab} Command line + ```console + $ git clone https://github.com/networkx/networkx.git + ``` + :::: + + ::::{group-tab} GitHub + Nothing to clone. We will try to inspect the repository directly on GitHub. + :::: + + ::::{group-tab} VS Code + From a new VS Code window, select "Clone Git repository" and enter + that URL. + :::: + ::::: + + - Then let us all **make sure we are working on a well-defined version** of the repository. + :::::{tabs} + ::::{group-tab} Command line + Step into the new directory and create an exercise branch from the + networkx-2.6.3 tag/release: + ```console + $ cd networkx + $ git switch --create exercise networkx-2.6.3 + ``` + On old Git versions which do not know the `switch` command (before 2.23), you + need to use this instead: + ```console + $ git checkout -b exercise networkx-2.6.3 + ``` + :::: + + ::::{group-tab} GitHub + We can visit the version directly: + :::: + + ::::{group-tab} VS Code + Switch to "Source Control", then the "..." menu, then "Branch", then "Create new branch from..." and select "networkx-2.6.3". + :::: + ::::: + + Then using the above toolbox try to: + 1. Find the code line which contains `"Logic error in degree_correlation"`. + 1. Find out when this line was last modified or added. Find the actual commit which modified that line. + 1. Inspect that commit with `git show`. + 1. Create a branch pointing to the past when that commit was created to be + able to browse and use the code as it was back then. + 1. How would you bring the code to the version of the code right before that line was last modified? + + ::::{solution} + We provide here a solution for the command line but we also encourage you to + try to solve this in the browser. + + 1. We use `git grep`: + ```console + $ git grep "Logic error in degree_correlation" + ``` + This gives the output: + ``` + networkx/algorithms/threshold.py: print("Logic error in degree_correlation", i, rdi) + ``` + Maybe you also want to know the line number: + ```console + $ git grep -n "Logic error in degree_correlation" + ``` + 2. We use `git annotate`: + ```console + $ git annotate networkx/algorithms/threshold.py + ``` + Then search for "Logic error" by typing "/Logic error" followed by Enter. + The last commit that modified it was `90544b4fa` (unless that line changed since). + 3. We use `git show`: + ```console + $ git show 90544b4fa + ``` + 4. Create a branch pointing to that commit (here we called the branch "past-code"): + ```console + $ git branch past-code 90544b4fa + ``` + 5. This is a compact way to access the first parent of `90544b4fa` (here we + called the branch "just-before"): + ```console + $ git switch --create just-before 90544b4fa~1 + ``` + :::: +::::: + +--- + +## Finding out when something broke/changed with `git bisect` + +This only works with the command line. + +> *"But I am sure it used to work! Strange."* + +Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke. + +:::{discussion} How would you solve this? +Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now. + +- How would you find the commit which changed it? +- Why could it be useful to know the commit that changed it? +::: + +We will probably arrive at a solution which is similar to `git bisect`: + +- First find out a commit in past when it worked. + ```console + $ git bisect start + $ git bisect good f0ea950 # this is a commit that worked + $ git bisect bad main # last commit is broken + ``` +- Now compile and/or run and/or test and decide whether "good" or "bad". +- This is how you can tell Git that this was a working commit: + ```console + $ git bisect good + ``` +- And this is how you can tell Git that this was not a working commit: + ```console + $ git bisect bad + ``` +- Then bisect/iterate your way until you find the commit that broke it. +- If you want to go back to start, type `git bisect reset`. +- This can even be automatized with `git bisect run SCRIPT`. + For this you write a script that returns zero/non-zero (success/failure). + + +(exercise-bisect)= + +## Optional exercise: Git bisect + +This only works with the command line. + +::::{exercise} (optional) History-2: Use git bisect to find the bad commit + In this exercise, we use `git bisect` on an example repository. It + is OK if you do not complete this exercise fully. + + Begin by cloning [https://github.com/coderefinery/git-bisect-exercise](https://github.com/coderefinery/git-bisect-exercise). + + + **Motivation** + + The motivation for this exercise is to be able to do archaeology with Git on a + source code where the bug is difficult to see visually. **Finding the offending + commit is often more than half the debugging**. + + + **Background** + + The script `get_pi.py` approximates pi using terms of the Nilakantha series. It + should produce 3.14 but it does not. The script broke at some point and + produces 3.57 using the last commit: + + ```console + $ python get_pi.py + + 3.57 + ``` + + At some point within the 500 first commits, an error was introduced. The only + thing we know is that the first commit worked correctly. + + + **Your task** + + - Clone this repository and use `git bisect` to find the commit which + broke the computation + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + - Once you have found the offending commit, also practice navigating to the last good commit. + - Bonus exercise: + Write a script that checks for a correct result and use `git bisect run` to + find the offending commit automatically + ([solution - spoiler alert!](https://github.com/coderefinery/git-bisect-exercise#solutions-spoiler-alert)). + + + **Hints** + + Finding the first commit: + + ```console + $ git log --oneline | tail -n 1 + ``` + + How to navigate to the parent of a commit with hash SOMEHASH: + ```console + $ git switch --create BRANCHNAME SOMEHASH~1 + ``` + + Instead of a tilde you can also use this: + ```console + $ git switch --create BRANCHNAME SOMEHASH^ + ``` +:::: + + +## Summary + +- git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project on the command line. +- `git switch --create NAME HASH` is the recommended mechanism to inspect old code on the command line. +- Most of these commands can be used in the GitHub web interface (except `git bisect`). diff --git a/branch/main/_sources/basics.md.txt b/branch/main/_sources/basics.md.txt new file mode 100644 index 00000000..fb56e9ca --- /dev/null +++ b/branch/main/_sources/basics.md.txt @@ -0,0 +1,715 @@ +# Basics + +```{objectives} +- Learn to create Git repositories and make commits. +- Get a grasp of the structure of a repository. +- Learn how to inspect the project history. +- Learn how to write useful commit log messages. +``` + +```{instructor-note} +- 35 min teaching/type-along +- 40 min exercise +``` + + +## What is Git, and what is a Git repository? + +- Git is a version control system: can **record/save snapshots** and track the content of a folder as it changes over time. +- Every time we **commit** a snapshot, Git records a snapshot of the **entire project**, saves it, and assigns it a version. +- These snapshots are kept inside a sub-folder called `.git`. +- If we remove `.git`, we remove the repository and history (but keep the working directory!). +- The directory `.git` uses relative paths - you can move the whole repository somewhere else and it will still work. +- Git doesn't do anything unless you ask it to (it **does not record anything automatically**). +- Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces). + + +## Recording a snapshot with Git + +- Git takes snapshots only if we request it. +- We will record changes in two steps (we will later explain why this is a recommended practice). +- Example (we don't need to type yet): + + ```console + $ git add FILE.txt + $ git commit + + $ git add FILE.txt ANOTHERFILE.txt + $ git commit + ``` + +- We first focus (`git add`, we "stage" the change), then record (`git commit`): + +```{figure} img/git_stage_commit.svg +:alt: Git staging +:width: 100% + +Git staging and committing. +``` + +```{discussion} Question for the more advanced participants +What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end. +``` + + +## Configuring Git command line + +Before we start using Git on the command line, we need to configure Git. +This is also part of the +[installation instructions](https://coderefinery.github.io/installation/shell-and-git/#configuration) +but we need to make sure we all have +set name, email address, editor, and +default branch: +```console +$ git config --global user.name "Your Name" +$ git config --global user.email yourname@example.com +$ git config --global core.editor nano +$ git config --global init.defaultBranch main +``` + +Verify with: +```console +$ git config --list +``` + +```{instructor-note} +Instructors, give learners enough time to do the above configuration steps. +``` + + +## Type-along: Tracking a guacamole recipe with Git + +We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list) + +The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language. + +```{instructor-note} +Instructors, please encourage now that participants type along. +``` + +```{note} +It is possible to go through this lesson in the command line or in the browser +(on GitHub). + +- We recommend to start with the command line but later to also try in the browser. +- If you get really stuck in the command line, try following in the browser and + later you can try to return to the command line. +``` + + +## Creating a repository + +One of the basic principles of Git is that it is **easy to create repositories**: + +`````{tabs} + ````{group-tab} Command line + ```console + $ mkdir recipe + $ cd recipe + $ git init -b main + ``` + + That's it! With `git init -b main` have now created an empty Git repository + where `main` is the default branch (more about branches later). + + We will use `git status` a lot to check out what is going on: + + ```console + $ git status + + On branch main + + No commits yet + + nothing to commit (create/copy files and use "git add" to track) + ``` + + We will make sense of this information during this workshop. + ```` + + ````{group-tab} Browser (GitHub) + First log into GitHub, then follow the screenshots and descriptions below. + + ```{figure} img/basics/new-repo-plus.png + :alt: Screenshot on GitHub before a new repository form is opened + :width: 100% + :class: with-border + + Click on the "plus" symbol on top right, then on "New repository". + ``` + + Another way to create a new repository is to visit + directly. + + ```{figure} img/basics/new-repo-form.png + :alt: Screenshot on GitHub just before creating a new repository + :width: 100% + :class: with-border + + Choose a repository name, add a short description, **check "Add a + README file"**, finally "Create repository". + ``` + + After you have clicked "Create repository" you should see a repository overview + with one file (README.md) and one commit. + ```` +````` + + +## Adding files and committing changes + +Let us now **create two files**. + +One file is called `ingredients.txt` and contains: +```shell +* 2 avocados +* 1 chili +* 1 lime +* 2 tsp salt +``` + +The second file is called `instructions.txt` and contains: +```shell +* chop avocados +* chop onion +* chop chili +* squeeze lime +* add salt +* and mix well +``` + +`````{tabs} + ````{group-tab} Command line + As mentioned above, in Git you can always check the status of files in your repository using + `git status`. It is always a safe command to run and in general a good idea to + do when you are trying to figure out what to do next: + + ```console + $ git status + + On branch main + + No commits yet + + Untracked files: + (use "git add ..." to include in what will be committed) + ingredients.txt + instructions.txt + + nothing added to commit but untracked files present (use "git add" to track) + ``` + + The two files are untracked in the repository (directory). You want to **add the files** (focus the camera) + to the list of files tracked by Git. Git does not track + any files automatically and you need make a conscious decision to add a file. Let's do what + Git hints at, and add the files, one by one: + + ```console + $ git add ingredients.txt + $ git status + + On branch main + + No commits yet + + Changes to be committed: + (use "git rm --cached ..." to unstage) + new file: ingredients.txt + + Untracked files: + (use "git add ..." to include in what will be committed) + instructions.txt + ``` + + Now this change is *staged* and ready to be committed. + Let us now commit the change to the repository: + ```console + $ git commit -m "adding ingredients" + + [main (root-commit) f146d25] adding ingredients + 1 file changed, 4 insertions(+) + create mode 100644 ingredients.txt + ``` + + Right after we query the status to get this useful command into our muscle memory: + ```console + $ git status + ``` + + Now stage and commit also the other file: + ```console + $ git add instructions.txt + $ git commit -m "adding instructions" + ``` + + We will add a third file to the repository, `README.md`, containing: + ```markdown + # recipe + + This is an exercise repository. + ``` + + Now stage and commit also the `README.md` file: + ```console + $ git add README.md + $ git commit -m "adding README" + ``` + + What does the `-m` flag mean? Let us check the help page for that command: + ```console + $ git help commit + ``` + + You should see a very long help page as the tool is very versatile (press q to quit). + Do not worry about this now but keep in mind that you can always read the help files + when in doubt. Searching online can also be useful, but choosing search terms + to find relevant information takes some practice and discussions in some + online threads may be confusing. + Note that help pages also work when you don't have a network connection! + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/add-file.png + :alt: Screenshot on GitHub before a new file is created + :width: 100% + :class: with-border + + Click on "Add file", then "Create new file". + ``` + + ```{figure} img/basics/edit-file.png + :alt: Screenshot on GitHub when editing a file + :width: 100% + :class: with-border + + Edit the file and specify the file name. + ``` + + ```{figure} img/basics/commit-changes.png + :alt: Screenshot on GitHub when editing the commit message + :width: 100% + :class: with-border + + Before you commit the change, adjust the commit message. + ``` + + After you have added `ingredients.txt`, add also `instructions.txt` in a similar + way. + + We have added two files, each in one commit. However, we ended up with + three files and three commits since `README.md` was automatically committed + when we created the repository on GitHub. + ```` +````` + + +(exercise-record-changes)= + +## Exercise: Record changes + +``````{exercise} Basic-1: Record changes + Add 1/2 onion to `ingredients.txt` and also the instruction + to "enjoy!" to `instructions.txt`. + + `````{tabs} + ````{group-tab} Command line + After modifying the files, do not stage the changes yet (do not `git add` + yet). + + When you are done editing the files, try `git diff`: + ```console + $ git diff + ``` + + You will see (can you identify in there the two added lines?): + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index 4422a31..ba8854f 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -2,3 +2,4 @@ + * 1 chili + * 1 lime + * 2 tsp salt + +* 1/2 onion + diff --git a/instructions.txt b/instructions.txt + index 7811273..2b11074 100644 + --- a/instructions.txt + +++ b/instructions.txt + @@ -4,3 +4,4 @@ + * squeeze lime + * add salt + * and mix well + +* enjoy! + ``` + + Now first stage and commit each change separately (what happens when we leave out the `-m` flag?): + ```console + $ git add ingredients.txt + $ git commit -m "add half an onion" + $ git add instructions.txt + $ git commit # <-- we have left out -m "..." + ``` + + When you leave out the `-m` flag, Git should open an editor where you can edit + your commit message. This message will be associated and stored with the + changes you made. This message is your chance to explain what you've done and + convince others (and your future self) that the changes you made were + justified. Write a message and save and close the file. + + When you are done committing the changes, experiment with these commands: + ```console + $ git log + $ git log --stat + $ git log --oneline + ``` + ```` + + ````{group-tab} Browser (GitHub) + We can make modifications to a file by clicking on the file and then the + pen symbol: + ```{figure} img/basics/pen-symbol.png + :alt: Screenshot on GitHub before clicking on the pen symbol + :width: 100% + :class: with-border + + By clicking on the pen symbol we can switch to edit mode. + ``` + + ```{figure} img/basics/preview.png + :alt: Screenshot on GitHub when previewing file changes + :width: 100% + :class: with-border + + Before committing the change, click on "Preview". + ``` + + Our goal is to arrive at two new commits: + - "add half an onion" (modifying `ingredients.txt`) + - "don't forget to enjoy" (modifying `instructions.txt`) + + When you are done committing the changes, try to browse commit history + on GitHub. + ```` + ````` +`````` + + +## Git history and log + +`````{tabs} + ````{group-tab} Command line + If you haven't yet, please try now `git log`: + + ```console + $ git log + + commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main) + Author: Radovan Bast + Date: Sun Sep 17 19:12:47 2023 +0200 + + don't forget to enjoy + + commit 79161b6e67c62ad4688a58c1e54183334611a390 + Author: Radovan Bast + Date: Sun Sep 17 19:12:32 2023 +0200 + + add half an onion + + commit a3394e39535343c4dae3bb4f703741a31aa8b78a + Author: Radovan Bast + Date: Sun Sep 17 18:47:14 2023 +0200 + + adding README + + commit 369624674e63de48055a65bf63055bd59c985d22 + Author: Radovan Bast + Date: Sun Sep 17 18:46:58 2023 +0200 + + adding instructions + + commit f146d25b94569a15e94d7f0da6f15d7554f76c49 + Author: Radovan Bast + Date: Sun Sep 17 18:35:52 2023 +0200 + + adding ingredients + ``` + ```` + + ````{group-tab} Browser (GitHub) + ```{figure} img/basics/commits.png + :alt: Screenshot on GitHub before clicking on commit history + :width: 100% + :class: with-border + + Click on the history symbol with (here) 5 commits. + ``` + + ```{figure} img/basics/history.png + :alt: Screenshot of GitHub repository commit history + :width: 100% + :class: with-border + + In this overview you can browse each commit individually. + ``` + + On GitHub you can also compare arbitrary two commits (replace "USER", + "HASH1", and "HASH2"): + `https://github.com/USER/recipe/compare/HASH1..HASH2` + + Try it with two of your commits. + ```` +````` + +- We can browse the development and access each state that we have committed. +- The long hashes uniquely label a state of the code. +- They are not just integers counting 1, 2, 3, 4, ... (why?). +- Output is in reverse chronological order, i.e. **newest commits on top**. +- We will use them when comparing versions and when going back in time. +- `git log --oneline` only shows the first 7 characters of the commit hash and is good to get an overview. +- If the first characters of the hash are unique it is not necessary to type the entire hash. +- `git log --stat` is nice to show which files have been modified. + + +(exercise-diff-and-rename)= + +## Optional exercises: Comparing changes + +``````{exercise} (optional) Basic-2: Comparing and showing commits + `````{tabs} + ````{group-tab} Command line + 1. Have a look at specific commits with `git show HASH`. + 2. Inspect differences between commit hashes with `git diff HASH1 HASH2`. + ```` + + ````{group-tab} Browser (GitHub) + 1. Have a look at specific commits. + 2. Inspect differences between commits. + + Use the screenshots under "Git history and log". + ```` + ````` +`````` + +````{exercise} (optional) Basic-3: Visual diff tools + This exercise is only relevant for the command line. In the browser, + the preview is already side-by-side and "visual". + + - Make further modifications and experiment with `git difftool` (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + On Windows or Linux: + ```console + $ git difftool --tool=meld HASH + ``` + + On macOS: + ```console + $ git difftool --tool=opendiff HASH + ``` + + ```{figure} img/meld.png + :alt: Git difftool using meld + :width: 100% + + Git difftool using meld. + ``` + + You probably want to use the same visual diff tool every time and + you can configure Git for that: + ```console + $ git config --global diff.tool meld + ``` +```` + +```{exercise} (optional) Basic-4: Browser and command line +You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both. + +- If you have managed to do the above in the command line, try now in the browser. +- If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git. +``` + + +## Writing useful commit messages + +Using `git log --oneline` or browsing a repository on the web, we better +understand that the first line of the commit message is very important. + +Good example: +```text +increase threshold alpha to 2.0 + +the motivation for this change is +to enable ... +... +this is based on a discussion in #123 +``` + +Convention: **one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary**. + +- **Why something was changed is more important than what has changed.** +- Cross-reference to issues and discussions if possible/relevant. +- Bad commit messages: "fix", "oops", "save work" +- Bad examples: [http://whatthecommit.com](http://whatthecommit.com) +- Write commit messages in English that will be understood + 15 years from now by someone else than you. Or by your future you. +- Many projects start out as projects "just for me" and end up to be successful projects + that are developed by 50 people over decades. +- [Commits with multiple authors](https://help.github.com/articles/creating-a-commit-with-multiple-authors/) are possible. + +Good references: + +- ["My favourite Git commit"](https://fatbusinessman.com/2019/my-favourite-git-commit) +- ["On commit messages"](https://who-t.blogspot.com/2009/12/on-commit-messages.html) +- ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) + +```{note} +A great way to learn how to write commit messages and to get inspired by their +style choices: **browse repositories of codes that you use/like**: + +Some examples (but there are so many good examples): +- [SciPy](https://github.com/scipy/scipy/commits/main) +- [NumPy](https://github.com/numpy/numpy/commits/main) +- [Pandas](https://github.com/pandas-dev/pandas/commits/main) +- [Julia](https://github.com/JuliaLang/julia/commits/master) +- [ggplot2](https://github.com/tidyverse/ggplot2/commits/main), + compare with their [release + notes](https://github.com/tidyverse/ggplot2/releases) +- [Flask](https://github.com/pallets/flask/commits/main), + compare with their [release + notes](https://github.com/pallets/flask/blob/main/CHANGES.rst) + +When designing commit message styles consider also these: +- How will you easily generate a changelog or release notes? +- During code review, you can help each other improving commit messages. +``` + +But remember: it is better to make any commit, than no commit. Especially in small projects. +**Let not the perfect be the enemy of the good enough**. + + +## Ignoring files and paths with .gitignore + +```{discussion} +- Should we add and track all files in a project? +- How about generated files? +- Why is it considered a bad idea to commit compiled binaries to version control? +- What types of generated files do you know? +``` + +Compiled and generated files are not +committed to version control. There are many reasons for this: + +- These files can make it more difficult to run on different platforms. +- These files are automatically generated and thus do not contribute in any meaningful way. +- When tracking generated files you could see differences in the code although you haven't touched the code. + +For this we use `.gitignore` files. Example: +```shell +# ignore compiled python 2 files +*.pyc +# ignore compiled python 3 files +__pycache__ +``` + +An example taken from the [official Git documentation](https://git-scm.com/docs/gitignore): +```shell +# ignore objects and archives, anywhere in the tree. +*.[oa] +# ignore generated html files, +*.html +# except foo.html which is maintained by hand +!foo.html +# ignore everything under build directory +build/ +``` + +- `.gitignore` should be part of the repository because we want to make sure that all developers see the same behavior. +- **All files should be either tracked or ignored**. +- `.gitignore` uses something called a + [shell glob syntax](https://en.wikipedia.org/wiki/Glob_(programming)) for + determining file patterns to ignore. You can read more about the syntax in the + [documentation](https://git-scm.com/docs/gitignore). +- You can have `.gitignore` files in lower level directories and they affect the paths below. + + +## Graphical user interfaces + +We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI): + +- [GitHub Desktop](https://desktop.github.com) +- [SourceTree](https://www.sourcetreeapp.com) +- [List of third-party GUIs](https://git-scm.com/downloads/guis) + + +## Summary + +Now we know how to save snapshots: + +```console +$ git add FILE(S) +$ git commit +``` + +And this is what we do as we program. + +Every state is then saved and later we will learn how to go back to these "checkpoints" +and how to undo things. + +```console +$ git init -b main # initialize new repository (main is default branch) +$ git add # add files or stage file(s) +$ git commit # commit staged file(s) +$ git status # see what is going on +$ git log # see history +$ git diff # show unstaged/uncommitted modifications +$ git show # show the change for a specific commit +$ git mv # move/rename tracked files +$ git rm # remove tracked files +``` + +Git is not ideal for large binary files +(for this consider [git-annex](http://git-annex.branchable.com)). + +````{challenge} Basic-5: Test your understanding + Which command(s) below would save the changes of `myfile.txt` + to an existing local Git repository? + + 1. ```console + $ git commit -m "my recent changes" + ``` + 2. ```console + $ git init myfile.txt + $ git commit -m "my recent changes" + ``` + 3. ```console + $ git add myfile.txt + $ git commit -m "my recent changes" + ``` + 4. ```console + $ git commit -m myfile.txt "my recent changes" + ``` + ```{solution} + + 1. Would only create a commit if files have already been staged. + 2. Would try to create a new repository in a folder "myfile.txt". + 3. **Is correct: first add the file to the staging area, then commit.** + 4. Would try to commit a file "my recent changes" with the message myfile.txt. + ``` +```` + +```{keypoints} +- It takes only one command to initialize a Git repository: `git init -b main`. +- Commits should be used to tell a story. +- Git uses the .git folder to store the snapshots. +- Don't be afraid to stage and commit often. Better too often than not often enough. +``` diff --git a/branch/main/_sources/branches.md.txt b/branch/main/_sources/branches.md.txt new file mode 100644 index 00000000..418e4d67 --- /dev/null +++ b/branch/main/_sources/branches.md.txt @@ -0,0 +1,624 @@ +# Branching and merging + +```{objectives} +- Be able to create and merge branches. +- Know the difference between a branch and a tag. +``` + +```{instructor-note} +- 30 min teaching/type-along +- 20 min exercise +``` + + +## Motivation for branches + +In the previous section we tracked a guacamole recipe with Git. + +Up until now our repository had only one branch with one commit coming +after the other: + +```{figure} img/gitink/git-branch-1.svg +:alt: Linear Git repository +:width: 40% + +Linear Git repository. +``` + +- Commits are depicted here as little boxes with abbreviated hashes. +- Here the branch `main` points to a commit. +- "HEAD" is the current position (remember the recording head of tape + recorders?). When we say `HEAD`, we mean those literal letters - + this isn't a placeholder for something else. +- When we talk about branches, we often mean all parent commits, not only the commit pointed to. + +**Now we want to do this:** + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +Software development is often not linear: + +- We typically need at least one version of the code to "work" (to compile, to give expected results, ...). +- At the same time we work on new features, often several features concurrently. + Often they are unfinished. +- We need to be able to separate different lines of work really well. + +The strength of version control is that it permits the researcher to **isolate +different tracks of work**, which can later be merged to create a composite +version that contains all changes: + +```{figure} img/gitink/git-collaborative.svg +:alt: Isolated tracks of work +:width: 100% + +Isolated tracks of work. +``` + +- We see branching points and merging points. +- Main line development is often called `main` or `master`. +- Other than this convention there is nothing special about `main` or `master`, it is a branch like any other. +- Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow). + +A group of commits that create a single narrative are called a **branch**. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. "fast sequence extraction" or "Python interface" or "fixing bug in +matrix inversion algorithm". + +````{admonition} **An important alias** +--- +class: important +--- + +We will now define an *alias* in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). **This is extensively used in the rest of this +and other lessons**: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` +```` + +```{instructor-note} +Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative. +``` + +Let us inspect the project history using the `git graph` alias: + +```console +$ git graph + +* e7cf023 (HEAD -> main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- We have a couple commits and only + one development line (branch) and this branch is called `main`. +- Commits are states characterized by a 40-character hash (checksum). +- `git graph` print abbreviations of these checksums. +- **Branches are pointers that point to a commit.** +- Branch `main` points to a commit (in this example it is `e7cf023efe382340e5284c278c6ae2c087dd3ff7` but on your computer + the hash will be different). +- `HEAD` is another pointer, it points to where we are right now (currently `main`) + +In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards. + + +## Creating and working with branches + +```{instructor-note} +We do the following part together. Encourage participants to type along. +``` + +```{admonition} It is possible to create and merge branches directly on GitHub +- However, we do not have screenshots for that in this episode +- But if you prefer to work in the browser, please try it +- Please contribute screenshots to this lesson +``` + +Let's create a branch called `experiment` where we add cilantro to `ingredients.txt` +(text after "#" are comments and not part of the command). + +```console +$ git branch experiment main # creates branch "experiment" from "main" +$ git switch experiment # switch to branch "experiment" +$ git branch # list all local branches and show on which branch we are +``` + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +- Verify that you are on the `experiment` branch (note that `git graph` also + makes it clear what branch you are on: `HEAD -> branchname`): + ```console + $ git branch + + * experiment + main + ``` + This command shows where we are, it does not create a branch. + +- Then add 2 tbsp cilantro **on top** of the `ingredients.txt`: + + ```{code-block} shell + --- + emphasize-lines: 1 + --- + * 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + * 2 tsp salt + * 1/2 onion + ``` + +- Stage this and commit it with the message "let us try with some cilantro". +- Then reduce the amount of cilantro to 1 tbsp, stage and commit again with "maybe little bit less cilantro". + +We have created **two new commits**: + +```{code-block} console +--- +emphasize-lines: 3-4 +--- +$ git graph + +* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro +* f6ec7b7 let us try with some cilantro +* e7cf023 (main) don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +- The branch `experiment` is two commits ahead of `main`. +- We commit our changes to this branch. + + +(exercise-branches)= + +## Exercise: Create and commit to branches + +````{exercise} Branch-1: Create and commit to branches + In this exercise, you will create another new branch and few more commits. + We will use this in the next section, to practice + merging. **The goal of the exercise is to end up with 3 branches**. + + - Change to the branch `main`. + - Create another branch called `less-salt`. + - Note! makes sure you are on main branch when you create the `less-salt` branch. + - A safer way would be to explicitly mention to create from the main branch + as shown below: + ```console + $ git branch less-salt main + ``` + - Switch to the `less-salt` branch. + - On the `less-salt` branch reduce the amount of salt. + - Commit your changes to the `less-salt` branch. + + Use the same commands as we used above. + + We now have three branches (in this case `HEAD` points to `less-salt`): + + ```console + $ git branch + + experiment + * less-salt + main + + $ git graph + + * bf28166 (HEAD -> less-salt) reduce amount of salt + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 (main) don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + Here is a graphical representation of what we have created: + + ```{figure} img/gitink/git-branch-2.svg + ``` + + - Now switch to `main`. + - In a new commit, improve the `README.md` file (we added the word "Guacamole"): + + ```markdown + # Guacamole recipe + + This is an exercise repository. + ``` + + Now you should have this situation: + + ```console + $ git graph + + * b4af65b (HEAD -> main) improve the documentation + | * bf28166 (less-salt) reduce amount of salt + |/ + | * bcb8b78 (experiment) maybe little bit less cilantro + | * f6ec7b7 let us try with some cilantro + |/ + * e7cf023 don't forget to enjoy + * 79161b6 add half an onion + * a3394e3 adding README + * 3696246 adding instructions + * f146d25 adding ingredients + ``` + + ```{figure} img/gitink/git-branch-3.svg + ``` + + And for comparison this is how it looks [on GitHub](https://github.com/coderefinery/recipe-before-merge/network). +```` + +(exercise-branches-merging)= + +## Exercise: Merging branches + +It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge `experiment` into `main`. + +```{exercise} Branch-2: Merge branches +Merge `experiment` and `less-salt` back into `main` following the lesson below +until the point where we start deleting branches. +``` + +````{admonition} If you got stuck in the above exercises or joined later + **If you got stuck in the above exercises or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git switch experiment + $ git switch less-salt + $ git switch main + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +First we make sure we are on the branch we wish to merge **into**: + +```{code-block} console +--- +emphasize-lines: 5 +--- +$ git branch + + experiment + less-salt +* main +``` + +Then we merge `experiment` into `main`: + +```console +$ git merge experiment +``` + +```{figure} img/gitink/git-merge-1.svg +``` + +We can verify the result: + +```console +$ git graph + +* 81fcc0c (HEAD -> main) Merge branch 'experiment' +|\ +| * bcb8b78 (experiment) maybe little bit less cilantro +| * f6ec7b7 let us try with some cilantro +* | b4af65b improve the documentation +|/ +| * bf28166 (less-salt) reduce amount of salt +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents. + +To view the branches that are merged into the current branch we can use the command: + +```console +$ git branch --merged + + experiment +* main +``` + +We are also happy with the work on the `less-salt` branch. Let us merge that +one, too, into `main`: + +```console +$ git branch # make sure you are on main +$ git merge less-salt +``` + +```{figure} img/gitink/git-merge-2.svg +:alt: Commit graph after merge + +Commit graph after merge. +``` + +We can verify the result in the terminal: + +```console +$ git graph + +* 4e03d4b (HEAD -> main) Merge branch 'less-salt' +|\ +| * bf28166 (less-salt) reduce amount of salt +* | 81fcc0c Merge branch 'experiment' +|\ \ +| * | bcb8b78 (experiment) maybe little bit less cilantro +| * | f6ec7b7 let us try with some cilantro +| |/ +* / b4af65b improve the documentation +|/ +* e7cf023 don't forget to enjoy +* 79161b6 add half an onion +* a3394e3 adding README +* 3696246 adding instructions +* f146d25 adding ingredients +``` + +Observe how Git nicely merged the changed amount of salt and the new ingredient **in the same file +without us merging it manually**: + +```console +$ cat ingredients.txt + +* 1 tbsp cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually *settle merge conflicts* (we will do that later). + + +## Deleting branches safely + +Both feature branches are merged: + +```console +$ git branch --merged + + experiment + less-salt +* main +``` + +This means we can delete the branches: + +```console +$ git branch -d experiment +$ git branch -d less-salt +``` + +This is the result: + +```{figure} img/gitink/git-deleted-branches.svg +:alt: Commit graph after merged branches were deleted + +Commit graph after merged branches were deleted. +``` + +We observe that when deleting branches, +only the pointers ("sticky notes") disappeared, not the commits. + +Git will not let you delete a branch which has not been reintegrated unless you +insist using `git branch -D`. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them. + + +(exercise-branches-optional)= + +## Optional exercises with branches + +The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section. + +````{exercise} (optional) Branch-3: Perform a fast-forward merge +1. Create a new branch from `main` and switch to it. +2. Create a couple of commits on the new branch (for instance edit `README.md`): + ```{figure} img/gitink/git-pre-ff.svg + ``` +3. Now switch to `main`. +4. Merge the new branch to `main`. +5. Examine the result with `git graph`. +6. Have you expected the result? Discuss what you see. + + ```{solution} + You will see that in this case no merge commit was created and Git merged the + two branches by moving (fast-forwarding) the "main" branch (label) three + commits forward. + + This was possible since one branch is the ancestor of the other and their + developments did not diverge. + + A merge that does not require any merge commit is a fast-forward merge. + ``` +```` + +````{exercise} (optional) Branch-4: Rebase a branch (instead of merge) +As an alternative to merging branches, one can also *rebase* branches. +Rebasing means that the new commits are *replayed* on top of another branch +(instead of creating an explicit merge commit). +**Note that rebasing changes history and should not be done on public commits!** +1. Create a new branch, and make a couple of commits on it. +2. Switch back to `main`, and make a couple of commits on it. +3. Inspect the situation with `git graph`. +4. Now rebase the new branch on top of `main` by first switching to the new branch, and then `git rebase main`. +5. Inspect again the situation with `git graph`. Notice that the commit hashes have changed - think about why! + + ```{solution} + You will notice two things: + - History is now linear and does not contain merge commits. + - All the commit hashes that were on the branch that got rebased, have + changed. This also demonstrates that `git rebase` is a command that alters + history. The commit history looks as if the rebased commits were all done + after the `main` commits. + ``` +```` + + +## Tags + +- A tag is a pointer to a commit but in contrast to a branch it **does not ever + move** when creating new commits later. +- It can be useful to think of branches as sticky notes and of tags as + [commemorative plaques](https://en.wikipedia.org/wiki/Commemorative_plaque). +- We use tags to record particular states or milestones of a project at a given + point in time, like for instance versions (have a look at [semantic versioning](http://semver.org), + v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a). +- There are two basic types of tags: annotated and lightweight. +- **Use annotated tags** since they contain the author and can be cryptographically signed using + GPG, timestamped, and a message attached. + +Let's add an annotated tag to our current state of the guacamole recipe: +```console +$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet" +``` + +As you may have found out already, `git show` is a very versatile command. Try this: + +```console +$ git show nobel-2023 +``` + +For more information about tags see for example +[the Pro Git book](https://git-scm.com/book/en/v2/Git-Basics-Tagging) chapter on the +subject. + +--- + +## Summary + +Let us pause for a moment and recapitulate what we have just learned: + +```console +$ git branch # see where we are +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +$ git merge NAME # merge branch NAME (to current branch) +$ git branch -d NAME # delete branch NAME +$ git branch -D NAME # delete unmerged branch NAME +``` + +Since the following command combo is so frequent: + +```console +$ git branch NAME # create branch NAME +$ git switch NAME # switch to branch NAME +``` + +There is a shortcut for it: + +```console +$ git switch --create NAME # create branch NAME and switch to it +``` + +### Typical workflows + +With this there are two typical workflows: + +```console +$ git switch --create new-feature # create branch, switch to it +$ git commit # work, work, work, ..., and test +$ git switch main # once feature is ready, switch to main +$ git merge new-feature # merge work to main +$ git branch -d new-feature # remove branch +``` + +Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging: + +```console +$ git switch --create wild-idea # create branch, switch to it, work, work, work ... +$ git switch main # realize it was a bad idea, back to main +$ git branch -D wild-idea # it is gone, off to a new idea +``` + +--- + +````{challenge} Branch-5: Test your understanding + Which of the following combos (one or more) creates a new branch and makes a commit to it? + 1. ```console + $ git branch new-branch + $ git add file.txt + $ git commit + ``` + 2. ```console + $ git add file.txt + $ git branch new-branch + $ git switch new-branch + $ git commit + ``` + 3. ```console + $ git switch --create new-branch + $ git add file.txt + $ git commit + ``` + 4. ```console + $ git switch new-branch + $ git add file.txt + $ git commit + ``` + + ```{solution} + Both 2 and 3 would do the job. Note that in 2 we first stage the file, and then create the + branch and commit to it. In 1 we create the branch but do not switch to it, while in 4 we + don't give the `--create` flag to `git switch` to create the new branch. + ``` +```` + +```{keypoints} +- A branch is a division unit of work, to be merged with other units of work. +- A tag is a pointer to a moment in the history of a project. +``` diff --git a/branch/main/_sources/browsing.md.txt b/branch/main/_sources/browsing.md.txt new file mode 100644 index 00000000..538dfbe9 --- /dev/null +++ b/branch/main/_sources/browsing.md.txt @@ -0,0 +1,394 @@ +# Copy and browse an existing project + +In this episode, we will look at an **existing repository** to +understand how all the pieces work together. Along the way, we will make a copy +(a {term}`fork`) of the {term}`repository` for us, which will be used for our +own changes in the next episode. + +- We used to start by directly going and creating a repository from scratch. This + was abstract and hard to understand. +- Instead, we'll show you all the cool stuff in a Git repository + first, and then start adding files. +- We use an example recipe book we created just for this course. +- By the end of the course, you'll know how to contribute your own + recipes to it. + +:::{objectives} +* See a real Git repository and understand what is inside of it. +* Understand how version control allows advanced inspection of a + repository. +* See how Git allows multiple people to collaborate easily. +* See the big picture instead of remembering a bunch of commands. +::: + + +## GitHub, VS Code, Command line, and more + +We offer **three different paths** of how to do this exercise: +- **GitHub** (this is the one we will demonstrate on day 1) +- **VS Code** (if you prefer to follow along using an editor; we will + do this on day 2) +- **Command line** (for people comfortable with the command line; you + will see more of this on day 2) + +In the future we'll add more paths, for example Jupyter and RStudio +(contributions welcome!). + + +## Creating a copy of the repository by "forking" + +A {term}`repository` is a collection of files in one directory tracked +by git. A {term}`GitHub repository` is GitHub's copy, which adds +things like access control. Each GitHub repository is owned by a user +or organization, who controls what is in it. + +First, we need to make our own copy of the exercise repository. This will +become important later, when we make our own changes. + +1. Go to the repository view on GitHub: + - : you can use this one if you don't want your fork and contributions + to be visible on the stream or the recording + - : we will use this one for the demonstration which is streamed and recorded +1. First, on GitHub, click the button that says "Fork". It is towards + the top-right of the screen: + :::{figure} img/browsing/forking.png + :alt: Screenshot on GitHub before clicking on "Fork" + :width: 80% + :class: with-border + ::: +1. You should shortly be redirected to your copy of the repository + **YOUR_USER_NAME/recipe-book**. + +At all times you should be aware of if you looking at *your* repository +or the *CodeRefinery {term}`upstream`* repository. +* Your repository: https://github.com/**USERNAME**/recipe-book +* CodeRefinery upstream repository: https://github.com/**coderefinery**/recipe-book + +:::::{tabs} +::::{group-tab} GitHub +You only need to open your own view, as described above. The browser +URL should look like `https://github.com/USER/recipe-book`, where +`USER` is your GitHub username. +:::: + +::::{group-tab} VS Code +You need to have forked the repository as described above. + +We need to start by making a copy of this repository locally. + +1. Start VS Code. +1. If you don't have the default view (you already have a project +open), go to File → New Window. +1. Under "Start" on the screen, select "Clone Git Repository...". Alternatively + navigate to the "Source Control" tab on the left sidebar and click on the "Clone Repository" button. +1. Paste in this URL: `https://github.com/USER/recipe-book`, where + `USER` is your username. You can copy this from the browser. +1. Browse and select the folder in which you want to clone the + repository. +1. Say yes, you want to open this repository. +1. Select "Yes, I trust the authors" (the other option works too). +:::: + +::::{group-tab} Command line +**This path is advanced and we do not include all command line +information: you need to be somewhat +comfortable with the command line already.** + +We need to start by making a copy of this repository locally. You +need to have forked the repository as described above. + +1. Start the terminal in which you use Git (terminal application, or + Git Bash). +1. Change to the directory where you would want the repository to be + (`cd ~/code` for example, if the `~/code` directory is where you + store your files). +1. Run the following command: `git clone + https://github.com/USER/recipe-book`, where `USER` is your + username. You might need to use a SSH clone command instead of + HTTPS, depending on your setup. +1. Change to that directory: `cd recipe-book` +:::: +::::: + + +## Exercise + +Work on this by yourself or in your team. + +:::{instructor-note} +Before starting the exercise session: +- Make sure you have shown how to fork the repository to own account + (above). +::: + +:::{exercise} Exercise: Browsing an existing project (25 min) + +Browse the recipe-book project (introduced above) and explore commits and branches. Take notes +and prepare questions. The hints are for the GitHub path in the +browser. + +1. Browse the **commit history**: Are commit messages understandable? + (Hint: "Commit history", the timeline symbol, above the file list) +1. Compare the commit history with the **network graph** ("Insights" -> "Network"). Can you find the branches? +1. How can you find out when a recipe was **last modified**? +1. **How many changes** did the Guacamole recipe receive (you find it under "sides")? + Try to click on some of the commits to see what changed. + (Hint: "History" in the view of a single file) +1. **Which recipes include the ingredient "salt"**? + (Hint: the GitHub search. From the repository view, it should offer + the filter "repo:USER/recipe-book" by default. What if you + add a search term?) +1. In the Guacamole recipe, find out **who modified each line last and when** + (click on file, then click "Blame" button). Find out who added the cilantro + and in which commit. + (Hint: "Blame" view in the file view) +1. Can you use these recipes yourself? **Are you allowed to share + modifications**? + (Hint: look for a license file) +1. **Browse issues and pull requests** in the {term}`upstream` repository (the + repository you forked from). Any idea what these might be good for? + (Hint: tabs in the repository view) +::: + + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by +design. + + +## Solution and walk-through + +### (1) Basic browsing + +The most basic thing to look at is the history of commits. + +* This is visible from a button in the repository view. We see every + change, when, and who has committed. +* Every change has a unique identifier, such as `554c187`. This can + be used to identify both this change, and the whole project's + version as of that change. +* Clicking on a change in the view shows more. + +:::::{tabs} + +::::{group-tab} GitHub +Click on the timeline symbol in the repository view: + :::{figure} img/browsing/history.png + :alt: Screenshot on GitHub of where to find the commit history + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +This can be done from "Timeline", in the bottom of explorer, but only +for a single file. +:::: + +::::{group-tab} Command line +Run: +```console +$ git log +``` + +Try also: +```console +$ git log --oneline +``` +:::: + +::::: + + +### (2) Compare commit history with network graph + +The commit history we saw above looks linear: one commit after +another. But if we look at the network view, we see some branches and +merges. We'll see how to do these later. This is another one of the +basic Git views. + +:::::{tabs} +::::{group-tab} GitHub +In a new browser tab, open the "Insights" tab, and click on "Network". +You can hover over the commit dots to see the person who committed and +how they correspond with the commits in the other view: + :::{figure} img/browsing/network.png + :alt: Screenshot on GitHub of the network graph + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +We don't know how to do this without an extension. Try starting a terminal and using the +"Command Line" option. +:::: + +::::{group-tab} Command line +If you defined the `git graph` alias as in {doc}`configuration`, you +can view the network graph with: +```console +$ git graph +``` +If not, you can use the basic command: +```console +$ git log --graph --oneline --decorate --all +:::: + +::::: + + +### (3) When was a recipe last modified? + +We see the history for the whole repository, but we can also see it +for a single file. + +:::::{tabs} + +::::{group-tab} GitHub +Navigate to the file view: Main page → sides directory → +guacamole.md. Click the "History" button near the top right: + :::{figure} img/browsing/file-history.png + :alt: Screenshot on GitHub showing the history of a single file + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +Open sides/guacamole.md file in the editor. Under the file browser, +we see a "Timeline" view there. +:::: + +::::{group-tab} Command line +The `git log` command can take a filename and provide the log of only +a single file: + +``` +$ git log sides/guacamole.md +``` +:::: + +::::: + + +### (4) How many changes did the Guacamole recipe receive? + +According to the view above, it seems to have five changes (as of +2024-03-07). This could change later on. + + +### (5) Which recipes include the ingredient "salt" + +Version control makes it very easy to find all occurrences of a single +word. This is useful for things like finding where functions or +variables are defined or used. + +:::::{tabs} +::::{group-tab} GitHub +We go to the main recipe book view. We click the Search magnifying +class at the very top, type "salt", and click enter. We see every +instance, including the context. + ```{admonition} Searching in a forked repository will not work instantaneously! + + It usually takes a few minutes before one can search for keywords in a forked repository + since it first needs to build the search index the very first time we search. + Start it, continue with other steps, then come back to this. + ``` + + :::{figure} img/browsing/search.png + :alt: Screenshot on GitHub performing a search + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +If you use the "Search" magnifying class on the left sidebar, and +search for "Salt" it shows the occurrences in every file. You can +click to see the usage in context. +:::: + +::::{group-tab} Command line +`grep` is the command line tool that searches for lines matching a term +```console +$ git grep salt # only the lines +$ git grep -C 3 salt # three lines of context +$ git grep -i salt # case insensitive +``` +:::: + +::::: + + +### (6) Who modified each line last and when? + +This is called the "annotate" or "blame" view. The name "blame" +is very unfortunate, but it is the standard term for historical reasons +for this functionality and it is not meant to blame anyone. + +:::::{tabs} + +::::{group-tab} GitHub +From a recipe view, change preview to "Blame" towards the top-left. +To get the actual commit, click on the commit message. + :::{figure} img/browsing/annotate.png + :alt: Screenshot on GitHub showing the "Blame" view + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +This requires an extension. We recommend for now you use the command +line version, after opening a terminal. +:::: + +::::{group-tab} Command line +These two commands are similar but have slightly different output. +```console +$ git annotate sides/guacamole.md +$ git blame sides/guacamole.md +``` +:::: + +::::: + + +### (7) Can you use these recipes yourself? Are you allowed to share modifications? + +* Look at the file `LICENSE`. +* It says it is "Creative Commons Zero 1.0", which is equivalent to + public domain. You can use them without conditions. +* Note the GitHub view of the file `LICENSE` gives a nice summary of what it + means. Try it out: + :::{figure} img/browsing/license.png + :alt: Screenshot on GitHub summarizing license terms + :width: 100% + :class: with-border + ::: + + +### (8) Browse issues and pull requests in the {term}`upstream` repository + +This can only be done through the GitHub view. Go to the main +repository **coderefinery/recipe-book**, (not your fork): +. {term}`Issues ` +and {term}`Pull requests ` are different for each GitHub +copy. + +* Click on the "Issues" tab. These are notes that people have added, + which allow discussion about the project. Often they are used to communicate + problems or ideas. +* Click on the "Pull requests" tab. This allows anyone to *propose + changes*, but only the repository owners can accept. + + +## Summary + +- Git allowed us to understand this simple project much better than we + could, if it was just a few files on our own computer. +- It was also very easy to share the project with the course. +- By forking the repository, we created our own copy. This is + important for the next episode, where we will make changes to + our copy. diff --git a/branch/main/_sources/commits.md.txt b/branch/main/_sources/commits.md.txt new file mode 100644 index 00000000..20f65d6f --- /dev/null +++ b/branch/main/_sources/commits.md.txt @@ -0,0 +1,452 @@ +# Committing changes + +The first and most basic task to do in Git is *record changes* using +commits. In this part, we will record changes in two +ways: on a new branch (which supports multiple lines of work at once), and directly +on the "main" branch (which happens to be the default branch here). + +:::{objectives} +* Record new changes to our own copy of the project. +* Understand adding changes in two separate branches. +* See how to compare different versions. +::: + + +## Background + +- In the previous episode we have browsed an existing {term}`repository` and saw {term}`commits ` + and branches. +- Each commit is a snapshot of the entire project at a certain + point in time and has a unique identifier ({term}`hash`) . +- A {term}`branch` is a line of development, and the `main` branch or `master` branch + are often the default branch in Git. +- A branch in Git is like a sticky note that is attached to a commit. When we add + new commits to a branch, the sticky note moves to the new commit. +- {term}`Tags ` are a way to mark a specific commit as important, for example a release + version. They are also like a sticky note, but they don't move when new + commits are added. + +:::{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +What if two people, at the same time, make two different changes? Git +can merge them together easily. Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +::: + + +## Exercise + +We offer **three different paths** of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the **GitHub +path** only and recommend you do that. (You can get experience with +the other paths on day 2) + +:::{exercise} Exercise: Practice creating commits and branches (20 min) +1. Make sure that you now work **on your fork** of the recipe-book + repository (`USER/recipe-book`, *not* `coderefinery/recipe-book`) +1. First create a new branch and then add a recipe to the branch and commit the change. +1. In a new commit, modify the recipe you just added. +1. Switch to the `main` branch and modify a recipe there. +1. Browse the network and locate the commits that you just created ("Insights" -> "Network"). +1. Compare the branch that you created with the `main` branch. Can you find an easy way to see the differences? +1. Can you find a way to compare versions between two arbitrary commits in the repository? +1. Try to rename the branch that you created and then browse the network again. +1. Try to create a tag for one of the commits that you created (on GitHub, + create a "release"). +::: + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by +design. + + +## Solution and walk-through + + +### (1) Make sure you are on your fork + +:::{figure} img/commits/fork.png +:alt: Screenshot on GitHub where we verify that we are on our fork. +:width: 60% +:class: with-border + +You want to see your username in the URL and you want to see the "forked from +..." part. +::: + + +### (2) Create a branch and add a recipe to the branch + +A recipe template is below. This format is called "Markdown", but it +doesn't matter right now. You don't have to use this particular template. +```markdown +# Recipe name + +## Ingredients + +- Ingredient 1 +- Ingredient 2 + + +## Instructions + +- Step 1 +- Step 2 +``` + +There is a {term}`main` branch that is default. We want to create a +*different* {term}`branch` for our new commit, because we will *merge* it later. +{term}`Commit ` is the verb to describe recording more changes, and also the +name of the thing you make. A commit is identified by something such as +`554c187`. + +:::::{tabs} +::::{group-tab} GitHub +1. Where it says "main" at the top left, click, enter a new branch + name `new-recipe`, click on the offer to create the new branch + ("Create branch new-recipe from main"). + :::{figure} img/commits/github-create-branch.png + :alt: Screenshot on GitHub where we create a new branch. + :width: 60% + :class: with-border + ::: +1. Change to some sub-directory, for example `sides` +1. Make sure you are still on the `new-recipe` branch (it should say + it at the top), and click "Add file" → "Create new file" from the + upper right. +1. Enter a filename where it says "Name your file...", with a `.md` at + the end. Example: `mixed-nuts.md`. +1. Enter the recipe. You can use the template above. +1. Click "Commit changes" +1. Enter a commit message. Then click "Commit + changes". + +You should appear back at the file browser view, and see your new +recipe there. +:::: + +::::{group-tab} VS Code +1. Make sure that you are on the main branch. +1. Version control button on left sidebar → Three dots in upper right of source control → Branch → Create branch. +1. VS Code automatically switches to the new branch. + +:::{figure} img/commits/vscode-create-branch.png +:width: 80% +:class: with-border +:alt: VS Code screenshot of create branch + +Creating a new branch in VS Code. +::: + +4. Create a new file, for example `sides/mixed-nuts.md`. +4. In the version control sidebar, click the `+` sign to add the file for the next commit. +4. Enter a brief message and click "Commit". + +:::{figure} img/commits/vscode-add-and-commit.png +:alt: Screenshot of VS Code commit process +:width: 80% +:class: with-border + +Committing a new file in VS Code. +::: +:::: + +::::{group-tab} Command line +Create a new branch called `new-recipe` from `main` and switch to it: +```console +$ git switch --create new-recipe main +``` + +Then create the new file. Finally add and commit the file: +```console +$ git add sides/mixed-nuts.md +$ git commit -m "Add mixed nuts recipe" +``` +:::: +::::: + + +### (3) Modify the recipe with a new commit + +:::::{tabs} +::::{group-tab} GitHub +This is similar to before, but we click on the existing file to +modify. + +1. Click on your new recipe, for example `mixed-nuts.md`. +2. Click the edit button, the pencil icon at top-right. +3. Follow the "Commit changes" instructions as in the previous step. +:::: + +::::{group-tab} VS Code +Repeat as in the previous step. +:::: + +::::{group-tab} Command line +Modify the file. Then commit the new change: +```console +$ git add sides/mixed-nuts.md +$ git commit -m "Short summary of the change" +``` + +Make sure to replace "Short summary of the change" with a meaningful commit +message. +:::: +::::: + + +### (4) Switch to the main branch and modify a recipe there + +:::::{tabs} +::::{group-tab} GitHub +1. Go back to the main repository page (your user's page). +1. In the branch switch view (top left above the file view), switch to + `main`. +1. Modify another recipe that already exists, following the pattern + from above. Don't modify the one you just created (but it shouldn't + even be visible on the `main` branch). +:::: + +::::{group-tab} VS Code +Use the branch selector at the bottom to switch back to the main branch. Repeat the same steps as above. + +:::{figure} img/commits/vscode-change-branch.png +:class: with-border +:width: 80% +:alt: VS Code screenshot + +Switching branch via selector at bottom. +:::: + +::::{group-tab} Command line +First switch to the `main` branch: +```console +$ git switch main +``` + +Then modify a file. Finally `git add` and then commit the change: +```console +$ git commit -m "Short summary of the change" +``` +:::: +::::: + + +### (5) Browse the commits you just made + +Let's look at what we did. Now, the `main` and `new-recipe` branches +have diverged: both have some modifications. Try to find the commits +you created. + +:::::{tabs} +::::{group-tab} GitHub +Insights tab → Network view (just like we have done before). +:::: + +::::{group-tab} VS Code +This requires an extension. Opening the VS Code terminal lets you use the command line method. + +:::{figure} img/commits/vscode-open-terminal.png +:class: with-border +:width: 80% +:alt: VS Code screenshot as described + +View → Terminal will open a terminal at bottom. This is a normal command line interface and very useful for work. (Note the git-aware prompt that shows the current branch. This requires other setup.) +:::: + +::::{group-tab} Command line +```console +$ git graph +$ git log --graph --oneline --decorate --all # If you didn't define git graph yet. +``` + +In my case I got: +```{code-block} +--- +emphasize-lines: 1-3 +--- +* b4de93b (HEAD -> main) add spring onion to poke +| * dc5d6f0 (origin/new-recipe, new-recipe) adding chocolate to the mixed nuts recipe +| * b4035e3 add mixed nuts recipe +|/ +* 554c187 (origin/main, origin/HEAD) Merge branch 'alex/fruit-salad' +|\ +| * 89d5ef9 fruit salad: instructions +| * 3bd2468 fruit salad: ingredients +* | 8bcb766 a todo note to not forget the instructions +|/ +* b950c5c just fixing capitalization +* d18035e fix formatting +* 7051cca add some cilantro +* ae19e81 add categories for easier browsing +* a6fe629 we also need salad +* 30b89c4 document what this is about +* fd12dc1 Merge branch 'radovan/lasagna' +|\ +| * 7753d43 vegetarian lasagna: instructions +| * aa0473e vegetarian lasagna: ingredients +* | 1e5a24a Merge branch 'radovan/poke' +|\ \ +| * | 5aa6687 oh no! forgot onion - adding +| * | cc84e4f working on a poke recipe +| |/ +* | 9500901 a classic pumpkin pie recipe - yum! +* | 34ce939 drafting a recipe for a pasta, so far only ingredients +* | 28e5f26 recipe for a mushroom soup +|/ +* a550963 reduce amount of salt +* f2d6d58 don't forget to enjoy +* 1fde064 add half an onion +* 4c1873e drafting a guacamole recipe +* 2992443 this will be licensed under CC0 +* 084a1ea starting with an almost empty readme +``` +:::: +::::: + + +### (6) Compare the branches + +Comparing changes is an important thing we need to do. When using the +GitHub view only, this may not be so common, but we'll show it so that +it makes sense later on. + +:::::{tabs} + +::::{group-tab} GitHub +Next to the branch name switcher, click on "Branches" to get an overview. + +Another way to compare branches or commits on GitHub is to adjust the following URL: +`https://github.com/USER/recipe-book/compare/VERSION1..VERSION2` + +Replace `USER` with your username and `VERSION1` and `VERSION2` with a commit hash or branch name. +Please try it out. +:::: + +::::{group-tab} VS Code +This seems to require an extension. We recommend you use the command line method. +:::: + +::::{group-tab} Command line +```console +$ git diff main new-recipe +``` + +Try also the other way around: +```console +$ git diff new-recipe main +``` + +Try also this if you only want to see the file names that are different: +```console +$ git diff --name-only main new-recipe +``` +:::: +::::: + + +### (7) Compare two arbitrary commits + +This is similar to above, but not only between branches. + +:::::{tabs} +::::{group-tab} GitHub +Like above, one can compare commits on GitHub by adjusting the following URL: +`https://github.com/USER/recipe-book/compare/VERSION1..VERSION2` + +Replace `USER` with your username and `VERSION1` and `VERSION2` with a commit hash or branch name. +Please try it out. +:::: + +::::{group-tab} VS Code +Again, we recommend using the Command Line method. +:::: + +::::{group-tab} Command line +First try this to get a short overview of the commits: +```console +$ git log --oneline +``` + +Then try to compare any two commit identifiers with `git diff`. +:::: +::::: + + +### (8) Renaming a branch + +:::::{tabs} +::::{group-tab} GitHub + +Branch button → View all branches → three dots at right side → Rename branch. + +:::: +::::{group-tab} VS Code +Version control sidebar → Three dots (same as in step 2) → Branch → Rename branch. Make sure you are on the right branch before you start. +:::: + +::::{group-tab} Command line +Renaming the current branch: +```console +$ git branch -m better-recipe +``` + +Renaming a different branch: +```console +$ git branch -m new-recipe better-recipe +``` +:::: +::::: + + +### (9) Creating a tag + +Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don't move when new +commits are added. + +:::::{tabs} +::::{group-tab} GitHub +Click on the branch switcher, and then on "Tags", then on "View all tags", then +"Create a new release": + :::{figure} img/commits/github-create-tag.png + :alt: Screenshot on GitHub where we create a new tag. + :width: 60% + :class: with-border + ::: + +What GitHub calls releases are actually tags in Git with additional metadata. +For the purpose of this exercise we can use them interchangeably. +:::: + +::::{group-tab} VS Code +Version control sidebar → Three dots (same as in step 2) → Tags → Creat tag. Make sure you are on the expected commit before you do this. +:::: + +::::{group-tab} Command line +Creating a tag: +```console +$ git tag -a v1.0 -m "New manuscript version of my recipe for the pre-print" +``` +:::: +::::: + + +## Discussion + +In this part, we saw how we can make changes to our files. +With {term}`branches `, we can +track several lines of work at once, and can compare +their differences. + +- You could commit directly to `main` if there is only one single line + of work and it's only you. +- You could commit to branches if there are multiple lines of work at + once, and you don't want them to interfere with each other. +- Tags are useful to mark a specific commit as important, for example a + release version. +- In Git, commits form a so-called "graph". Branches are tags in Git function + like sticky notes that stick to specific commits. What this means for us is + that it does not cost any significant disk space to create new branches. diff --git a/branch/main/_sources/configuration.md.txt b/branch/main/_sources/configuration.md.txt new file mode 100644 index 00000000..b00b7a89 --- /dev/null +++ b/branch/main/_sources/configuration.md.txt @@ -0,0 +1,147 @@ +(configuration)= + +# Configuring Git command line and editor + +We have a longer version of this in the [installation +instructions](https://coderefinery.github.io/installation/git-in-terminal/). +But for clarity, we will review the most important parts here. + +You don't need to set these if you work only through the GitHub web interface. +If you use VS Code or other editors or integrated development environments, +the editor might prompt you to set these up. + +These configuration settings are saved in a file called `.gitconfig` in your +home directory. If this file exists, editors like VS Code will use this +configuration. + +If you want to see your configuration settings, you can use the +command (`--show-origin` means it shows the file *where* each setting +is defined): +```console +$ git config --list --show-origin +``` + + +## Name and email address for Git commit metadata + +Git commits carry metadata about the author and two things you will always need +to define somewhere are: +```console +$ git config --global user.name "Your Name" +$ git config --global user.email yourname@example.com +``` + +For the email address we recommend to use the one you use for your GitHub account. +If you prefer to not use it, you can instead use +`YOUR_GITHUB_USERNAME@users.noreply.github.com` as the email address (replace `YOUR_GITHUB_USERNAME`). +This means that nobody can write to this email address, but GitHub will still +be able to connect your contributions with your GitHub account. + +Note that these can, in theory, be anything: this is just data, not a +registration or identity requirement. + + +## Default branch name + +The default branch name in Git has been `master` for a long time, but it is +changing to `main` in many places. We recommend to set it to `main` for new +repositories that you create locally: +```console +$ git config --global init.defaultbranch main +``` + + +## Useful alias for the command line + +We recommend to define an {term}`alias` in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command: +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` + +We have an own section about aliases: {ref}`aliases`. + + +## Default text editor for commit messages + +Git sometimes needs to start a text editor for you to enter messages (unless you create +commits from inside an editor or on the web). +This may have already been set to something (like VS Code), but if not +`nano` is usually a safe choice: + +```console +$ git config --global core.editor nano +``` + +The [installation instructions text editor page](https://coderefinery.github.io/installation/editors/) gives ways +to set other editors, or do a web search for "git set editor to +[editor name]". + + +% This anchor used for linking from other lessons +(clone-method)= + +## Authenticating to GitHub: SSH or HTTPS or VS Code? + +**How does GitHub know who you are?** There are three options: +- **SSH** is the classic method, using [Secure Shell + Protocol](https://en.wikipedia.org/wiki/Secure_Shell) remote connection + keys. +- **HTTPS** works with the **Git Credential Manager**, which is an + extra add-on that works easily in Windows and Mac. +- **VS Code** editor can authenticate with GitHub using its own + authentication method. + +Read how to install them from the [installation +instructions](https://coderefinery.github.io/installation/ssh/). + +Test which one you should use: + +:::::{tabs} + ::::{group-tab} Command line: SSH + Try this command: + ```console + $ ssh -T git@github.com + ``` + + If it returns `Hi USERNAME! You've successfully authenticated, ...`, + then SSH is configured and the following steps will work with the SSH + cloning. + + See our [installation + instructions](https://coderefinery.github.io/installation/ssh/) to + set up SSH access. + + **From now on, if you know that SSH works, you should always select + SSH as the clone URL from GitHub, or translate the URL to start with + the right thing yourself:** `git@github.com:` (with the `:`). + :::: + + ::::{group-tab} Command line: HTTPS + Try this command: + ```console + $ git config --get credential.helper + ``` + + If this shows something, then the credential manager is probably + configured and HTTPS cloning will work (but you can't verify it until + you try using it). + + From now on, **if you know that HTTPS works, you should always select + HTTPS as the clone URL from GitHub, or translate the URL to start with + the right thing yourself:** `https://github.com/` + :::: + + ::::{group-tab} VS Code + VS Code has its own authentication method and the editor will guide you + through the process. If you are using VS Code, you can skip the SSH and + HTTPS checks. + + From now on, you should **Select HTTPS as the clone URL from + GitHub, or translate the URL to start with the right thing + yourself:** `https://github.com/` + + If you don't want VS Code to be connected to your GitHub account, + set up and use the SSH method instead. + :::: +::::: diff --git a/branch/main/_sources/conflicts.md.txt b/branch/main/_sources/conflicts.md.txt new file mode 100644 index 00000000..34b978ad --- /dev/null +++ b/branch/main/_sources/conflicts.md.txt @@ -0,0 +1,463 @@ +(conflict-resolution)= + +# Conflict resolution + +```{objectives} +- Understand merge conflicts sufficiently well to be able to fix them. +``` + +```{instructor-note} +- 20 min teaching/type-along +- 20 min exercise +``` + + +## Conflicts in Git and why they are good + +Imagine we start with the following text file: +```{code-block} +1 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1/2 onion +``` + +On branch A somebody modifies: +```{code-block} +--- +emphasize-lines: 1, 4 +--- +2 tbsp cilantro +2 avocados +1 chili +2 lime +1 tsp salt +1/2 onion +``` + +On branch B somebody else modifies: +```{code-block} +--- +emphasize-lines: 1, 6 +--- +1/2 tbsp cilantro +2 avocados +1 chili +1 lime +1 tsp salt +1 onion +``` + +When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro: +```{code-block} +--- +emphasize-lines: 1 +--- +????????????????? +2 avocados +1 chili +2 lime +1 tsp salt +1 onion +``` + +Git is very good at resolving modifications when merging branches and +in most cases a `git merge` runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see {ref}`exercise-branches-optional`) without you even noticing. + +But sometimes the **same portion** of the code/text is modified on two branches +**in two different ways** and Git issues a **conflict**. +Then you need to tell Git which version to keep (**resolve** it). + +There are several ways to do that as we will see. + +Please remember: + +- It is good that Git conflicts exist: Git will not silently overwrite one of + two differing modifications. +- Conflicts may look scary, but are not that bad after a little bit of + practice. Also they are luckily rare. +- Don't be afraid of Git because of conflicts. You may not meet some conflicts + using other systems because you simply can't do the kinds of things you do + in Git. +- You can take human measures to reduce them. + +--- + +```{discussion} The human side of conflicts +- What does it mean if two people do the same thing in two different ways? +- What if you work on the same file but do two different things in the different sections? +- What if you do something, don't tell someone from 6 months, and then try to combine it with other people's work? +- How are conflicts avoided in other work? (Only one person working at once? + Declaring what you are doing before you start, if there is any chance someone + else might do the same thing, helps.) +- Minor conflicts (two people revise spelling) vs semantic (two people rewrite + a function to add two different new features). How did Git solve these in + branching/merging easily? +``` + +Now we can go to show how Git controls when there is actually a conflict. + + +## Preparing a conflict + +```{instructor-note} +We do the following together as type-along/demo. +``` + +````{admonition} If you got stuck previously or joined later + **If you got stuck previously or joined later**, + you can apply the commands below. + But **skip this box if you managed to create branches**. + + ```console + $ cd .. # step out of the current directory + + $ git clone https://github.com/coderefinery/recipe-before-merge.git + $ cd recipe-before-merge + + $ git remote remove origin + + $ git graph + ``` + + Or call a helper to un-stuck it for you. +```` + +We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together. + +- Create two branches from `main`: one called `like-cilantro`, one called `dislike-cilantro`: + ```console + $ git branch like-cilantro main + $ git branch dislike-cilantro main + ``` + +- On the two branches make **different modifications** to the amount of the **same ingredient**: + +- On the branch `like-cilantro` we have the following change: + ```console + $ git diff main like-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6cacd50 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + +- And on the branch `dislike-cilantro` we have the following change: + ```console + $ git diff main dislike-cilantro + ``` + + ```diff + diff --git a/ingredients.txt b/ingredients.txt + index e83294b..6484462 100644 + --- a/ingredients.txt + +++ b/ingredients.txt + @@ -1,4 +1,4 @@ + -* 1 tbsp cilantro + +* 1/2 tbsp cilantro + * 2 avocados + * 1 chili + * 1 lime + ``` + + +## Merging conflicting changes + +What do you expect will happen when we try to merge these two branches into +main? + +```{note} +In case `git switch` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git switch`. +``` + +The first merge will work: + +```console +$ git switch main +$ git status +$ git merge like-cilantro + +Updating 4e03d4b..3caa632 +Fast-forward + ingredients.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +``` + +But the second will fail: + +```console +$ git merge dislike-cilantro + +Auto-merging ingredients.txt +CONFLICT (content): Merge conflict in ingredients.txt +Automatic merge failed; fix conflicts and then commit the result. +``` + +Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit: + +```{code-block} console +--- +emphasize-lines: 9 +--- +$ git status + +You have unmerged paths. + (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) + +Unmerged paths: + (use "git add ..." to mark resolution) + both modified: ingredients.txt + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +Git won't decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward. + +Let us inspect the conflicting file: + +```console +$ cat ingredients.txt + +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +* 2 avocados +* 1 chili +* 1 lime +* 1 tsp salt +* 1/2 onion +``` + +Git inserted resolution markers (the `<<<<<<<`, `>>>>>>>`, and `=======`). + +Try also `git diff`: + +```console +$ git diff +``` + +```diff +diff --cc ingredients.txt +index 6cacd50,6484462..0000000 +--- a/ingredients.txt ++++ b/ingredients.txt +@@@ -1,4 -1,4 +1,10 @@@ +++<<<<<<< HEAD + +* 2 tbsp cilantro +++======= ++ * 1/2 tbsp cilantro +++>>>>>>> dislike-cilantro + * 2 avocados + * 1 chili + * 1 lime +``` + +`git diff` now only shows the conflicting part, nothing else. + + +## Conflict resolution + +``` +<<<<<<< HEAD +* 2 tbsp cilantro +======= +* 1/2 tbsp cilantro +>>>>>>> dislike-cilantro +``` + +We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged. + +```{admonition} Steps to resolve a conflict + +- Check status with `git status` and `git diff`. +- Decide what you keep (the one, the other, or both or something + else). Edit the file to do this. + - Remove the resolution markers, if not already done. + - The file(s) should now look exactly how you want them. +- Check status with `git status` and `git diff`. +- Tell Git that you have resolved the conflict with `git add ingredients.txt` + (if you use the Emacs editor with a certain plugin the editor may stage the + change for you after you have removed the conflict markers). +- Verify the result with `git status`. +- Finally commit the merge with only `git commit`. Everything is pre-filled. +``` + +(exercise-conflicts)= + +## Exercise: Create and resolve a conflict + +````{exercise} Conflict-1: Create another conflict and resolve +In this exercise, we repeat almost exactly what we did above with a +different ingredient. + +1. Create two branches before making any modifications. +2. Again modify some ingredient on both branches. +3. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge. +4. What happens if you apply the same modification on both branches? +5. If you create a branch `like-avocados`, commit a change, then from this + branch create another banch `dislike-avocados`, commit again, and try to + merge both branches into `main` you will not see a conflict. Can you + explain, why it is different this time? +```{solution} +4: No conflict in this case if the change is the same. + +5: No conflict in this case since in Git history one change happened after the other. The two changes + are related and linked by Git history and one is a Git ancestor of the + other. Git will assume that since we applied one change after the other, + we meant this. There is nothing to resolve. +``` +```` + +(exercise-conflicts-optional)= + +## Optional exercises with conflict resolution + +````{exercise} (optional) Conflict-2: Resolve a conflict when rebasing a branch +1. Create two branches where you anticipate a conflict. +2. Try to merge them and observe that indeed they conflict. +3. Abort the merge with `git merge --abort`. +4. What do you expect will happen if you rebase one branch on top of the + other? Do you anticipate a conflict? Try it out. +```{solution} +Yes, this will conflict. If it conflicts during a merge, it will also conflict +during rebase but the conflict resolution looks slightly different: +You still need to look for conflict markers but you tell Git that you resolved +a conflict with `git add` and then you continue with `git rebase --continue`. +Follow instructions that you get from the Git command line. +``` +```` + +````{exercise} (optional) Conflict-3: Resolve a conflict using mergetool + - Again create a conflict (for instance disagree on the number of avocados). + - Stop at this stage: + + ```markdown + Auto-merging ingredients.txt + CONFLICT (content): Merge conflict in ingredients.txt + Automatic merge failed; fix conflicts and then commit the result. + ``` + + - Instead of resolving the conflict manually, use a visual tool + (requires installing one of the [visual diff tools](https://coderefinery.github.io/installation/difftools/)): + + ```console + $ git mergetool + ``` + + ```{figure} img/conflict-resolution/mergetool.png + :alt: Conflict resolution using mergetool + :width: 100% + ``` + + - Your current branch is left, the branch you merge is right, result is in the middle. + - After you are done, close and commit, `git add` is not needed when using `git mergetool`. + + If you have not instructed Git to avoid creating backups when using mergetool, then to be on + the safe side there will be additional temporary files created. To remove those you can do + a git clean after the merging. + + To view what will be removed: + + ```console + $ git clean -n + ``` + + To remove: + + ```console + $ git clean -f + ``` + + To configure Git to avoid creating backups at all: + + ```console + $ git config --global mergetool.keepBackup false + ``` +```` + +--- + +## Using "ours" or "theirs" strategy + +- Sometimes you know that you want to keep "ours" version (version on the branch you are on) + or "theirs" (version on the merged branch). +- Then you do not have to resolve conflicts manually. +- See [merge strategies](https://git-scm.com/docs/merge-strategies). + +Example (merge and in doubt take the changes from current branch): +```console +$ git merge -s recursive -Xours less-avocados +``` + +Or (merge and in doubt take the changes from less-avocados branch): +```console +$ git merge -s recursive -Xtheirs less-avocados +``` + +--- + +## Aborting a conflicting merge + +Sometimes you get a merge conflict but realize that you can't solve it without +talking to a colleague (who created the other change) first. What to do? + +You can abort the merge and postponing conflict resolution by resetting the +repository to `HEAD` (last committed state): + +```console +$ git merge --abort +``` + +The repository looks then exactly as it was before the merge. + +--- + +## Avoiding conflicts + +- Human measures + - Think and plan to which branch you will commit to. + - Do not put unrelated changes on the same branch. +- Collaboration measures + - Open an issue and discuss with collaborators before starting a long-living + branch. +- Project layout measures + - Modifying global data often causes conflicts. + - Modular programming reduces this risk. +- Technical measures + - **Share your changes early and often** - this is one of the happy, + rare circumstances when everyone doing the selfish thing (e.g. `git push` as + early as practical) results in best case for everyone! + - Pull/rebase often to keep up to date with upstream. + - Resolve conflicts early. + +```{discussion} +Discuss how Git handles conflicts compared to services like Google Drive. +``` + +```{keypoints} +- Conflicts often appear because of not enough communication or not optimal + branching strategy. +``` diff --git a/branch/main/_sources/customizing.md.txt b/branch/main/_sources/customizing.md.txt new file mode 100644 index 00000000..c8fdf72b --- /dev/null +++ b/branch/main/_sources/customizing.md.txt @@ -0,0 +1,25 @@ +# Customizing Git + +## Shell prompt + +```{instructor-note} +Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like. +``` + +You can make your shell display contextual information about +your Git state even at all times. + +Here are few example projects that make this possible and easy: +- (bash) +- (zsh) +- (fish) +- (bash and fish) + + +## More useful "diff" output + +[Delta](https://github.com/dandavison/delta) is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +"diff" output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more. diff --git a/branch/main/_sources/exercises.md.txt b/branch/main/_sources/exercises.md.txt new file mode 100644 index 00000000..fe455cfa --- /dev/null +++ b/branch/main/_sources/exercises.md.txt @@ -0,0 +1,10 @@ +# List of exercises + +This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests. + +```{exerciselist} +``` diff --git a/branch/main/_sources/guide.md.txt b/branch/main/_sources/guide.md.txt new file mode 100644 index 00000000..89b3eda7 --- /dev/null +++ b/branch/main/_sources/guide.md.txt @@ -0,0 +1,221 @@ +# Instructor guide + + +:::warning +## Exercise preparation: one day before the workshop + +- Create two exercise repository from + preserving history + (this means **not** using "generating from template") + - + - +- You can create these using `git clone --mirror` and `git push --mirror` to make sure to copy all branches. +- Create one or two issues to both +- Create one or two pull requests to both +- In both, try to search for something in the recipes to trigger a search index + update +::: + + +## Privacy + +When presenting the material in a streamed and recorded workshop, make sure to +only show the +repository. + + +## Schedule Day 1 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:20 (20 min) Welcome and practical information + +- 09:20 - 09:35 (15 min) [Motivation](https://coderefinery.github.io/git-intro/motivation/) +- 09:35 - 10:00 (25 min) [Copy and browse an existing project](https://coderefinery.github.io/git-intro/browsing/) + +- 10:00 - 10:10 (10 min) Break + +- 10:10 - 11:00 (50 min) [Committing changes](https://coderefinery.github.io/git-intro/commits/) + +- 11:00 - 12:00 (60 min) Break + +- 12:00 - 12:50 (50 min) [Merging changes and contributing to the project](https://coderefinery.github.io/git-intro/merging/) + +- 12:50 - 13:00 (10 min) Break + +- 13:00 - 13:30 (20 min) Demonstrating conflict resolution, Q&A, feedback, and what will we be doing tomorrow? + + +## Schedule Day 2 + +Times here are in CE(S)T. + +- 08:50 - 09:00 (10 min) Soft start and icebreaker question +- 09:00 - 09:50 (50 min) [Cloning a Git repository and working locally](https://coderefinery.github.io/git-intro/local-workflow/) + +- 09:50 - 10:00 (10 min) Break + +- 10:00 - 11:00 (60 min) [Inspecting history](https://coderefinery.github.io/git-intro/archaeology/) + +- 11:00 - 12:00 (60 min) Break + +- 12:00 - 12:50 (50 min) [How to turn your project to a Git repo and share it](https://coderefinery.github.io/git-intro/sharing/) + +- 12:50 - 13:00 (10 min) Break + +- 13:00 - 13:30 (20 min) Practical advice, Q&A, feedback, and what will we be doing tomorrow? + + +## Why we teach this lesson + +Everyone should be using a version control system for their work, even if they're working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories. + +Specific motivations: +- Code easily becomes a disaster without version control +- Mistakes happen - Git offers roll-back functionality and easy backup mechanism +- One often needs to work on multiple things in parallel - branches solve that problem +- Git enables people to collaborate on code or text without stepping on each other's toes +- Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, + and if bugs are found one can find out exactly when it was introduced + +Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices. + + +## Intended learning outcomes + +By the end of this lesson, learners should: +- realize that version control is very important and Git is a valuable tool to learn and use +- understand that Git is configurable and know how to set basic configurations +- be able to set up Git repositories and make commits +- know how to write good commit messages +- have an idea of how the staging area can be used to craft good commits +- know how to create branches and switch between branches +- have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way +- know how to merge branches and understand what that means in terms of combining different modifications +- realize that conflicts are generally a good thing since they prevent incorrect merges +- be able to set up a repository on GitHub and connect it with local repository +- push changes to a remote repository +- know a few ways to search through a repository and its history + + +## Inspecting history + +Key lesson is *how to find when something is broken or what commit has broken +the code*. + +It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that `git annotate` +and `git show` are available on GitHub and GitLab. + +When discussing `git annotate` and `git bisect` the "when" is more important +than "who". It is not to blame anybody but rather to find out whether published +results are affected. + +Discuss how one would find out this information without version control. + +**Questions to involve participants:** + +- Have you ever found a bug in your code and wondered whether it has affected published results? +- Have you ever wondered when, and by whom, a particular line of code was introduced? +- Have you ever found out that a code behaves differently than it used to but you are not sure when + precisely this changed? + + +**Confusion during `git bisect` exercise:** + +Learners may get stuck in the `git bisect` exercise if they incorrectly assign a commit +as *bad* or *good*. +To leave the bisect mode and return to the commit before `git bisect start` was issued, +one can do +```shell +$ git bisect reset +``` +and start over if needed. + + +### Live better than reading the website material + +It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier. + + +### Log your history in a separate window + +The screencasting (shell window cheatsheet) hints have been moved to +the [presenting +manual](https://coderefinery.github.io/manuals/instructor-tech-setup/). + + +### Create a cheatsheet on the board + +For in-person workshops, create a "cheatsheet" on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven't forgotten anything. Re-create and expand in future git lessons. +One strategy is: + +- a common section for basic commands: `init`, `config`, `clone`, `help`, `stash` +- info commands, can be run anytime: `status`, `log`, `diff`, `graph` +- A section for all the commands that move code from different states: + `add`, `commit`, etc. See the visual cheat sheet below. + +You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it's probably too confusing to use after this course. But, the idea +of commands moving from the "working dir", "staging area", "commits", +etc is good. + +```{figure} img/cheat-sheet.jpg +:alt: Example cheat sheet +:width: 100% + +Example cheat sheet. +``` + +We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to. + + +### Draw a graph on the board + +Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run `git graph`, then do the command, +then look at `git graph` again. + + +### Repeat the following points + +- Always check `git status`, `git diff`, and `git graph` (our alias) before and + after every command until you get used to things. These give you a clear view + into what is going on, the key to knowing what you are doing. Even + after you are used to things... anytime you do something you do + infrequently, it's good to check. + +- `git graph` is a direct representation of what we are drawing on the + board and should constantly be compared to it. + +- Once you `git add` something, it's almost impossible to lose it. + This is used all the time, for example once you commit or even add + it is hard to lose. Commit before you merge or rebase. And so on. + + +### Start from identical environment + +You probably have a highly optimized bash and git environment - one +that is different from students. Move `.gitconfig` and `.bashrc` out +of the way before you start so that your environment is identical to +what students have. diff --git a/branch/main/_sources/index.md.txt b/branch/main/_sources/index.md.txt new file mode 100644 index 00000000..ccbd5471 --- /dev/null +++ b/branch/main/_sources/index.md.txt @@ -0,0 +1,124 @@ +# Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version + +```{warning} +In February and March 2024 we rewrote this lesson from the ground up. +If you are looking for the previous version, you can browse the +[2023 version of this lesson](https://coderefinery.github.io/git-intro/branch/2023-version/). +``` + +This is the introductory lesson to version control using +[Git](https://git-scm.com/). + +We start with an existing repository on the web to visually explain the basic +concepts of version control. We later move to a local +repository. Our goal there is not only to be able to apply changes to an +existing repository but to also be able to turn own projects into Git +repositories and to share them with others. + +In the separate [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/), we teach more use +of remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with Git to +be able to work well. + +The goals of the module as a whole are that the learner will feel comfortable +about committing changes, branching, and merging. + +```{prereq} +We offer several options to go through the material: **on the web, in an editor, +or in the terminal**. +Please see the [installation instructions](https://coderefinery.github.io/installation/). + +We recommend to have a [GitHub](https://github.com) account. +**Why GitHub?** +Also [GitLab](https://gitlab.com) and [Bitbucket](https://bitbucket.org) would +allow similar workflows and basically everything that we will discuss is +transferable. With this material and these exercises we do not implicitly +endorse the company [GitHub](https://github.com). We have chosen to demonstrate +a number of concepts using examples with [GitHub](https://github.com) because +it is currently the most popular web platform for hosting Git repositories and +the chance is high that you will interact with +[GitHub](https://github.com)-based repositories even if you choose to host your +Git repository on another service. +``` + +```{toctree} +:maxdepth: 1 +:caption: Getting started + +motivation +configuration +``` + +```{toctree} +:maxdepth: 1 +:caption: Modifying an existing project + +browsing +commits +merging +local-workflow +``` + +```{toctree} +:maxdepth: 1 +:caption: Studying an existing project + +archaeology +``` + +```{toctree} +:maxdepth: 1 +:caption: Sharing your work + +sharing +``` + +```{toctree} +:maxdepth: 1 +:caption: Finding the balance + +level +what-to-avoid +``` + +```{toctree} +:maxdepth: 1 +:caption: Older episodes + +basics +branches +conflicts +``` + +```{toctree} +:maxdepth: 1 +:caption: Optional episodes + +staging-area +recovering +interrupted +aliases +under-the-hood +``` + +```{toctree} +:maxdepth: 1 +:caption: Reference + +reference +customizing +resources +exercises +guide +PDF version +``` + +```{toctree} +:maxdepth: 1 +:caption: About + +All lessons +CodeRefinery +Reusing +``` diff --git a/branch/main/_sources/interrupted.md.txt b/branch/main/_sources/interrupted.md.txt new file mode 100644 index 00000000..0516cad1 --- /dev/null +++ b/branch/main/_sources/interrupted.md.txt @@ -0,0 +1,106 @@ +# Interrupted work + +```{objectives} +- Learn to switch context or abort work without panicking. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{keypoints} +- There is almost never reason to clone a fresh copy to complete a task that + you have in mind. +``` + + +## Frequent situation: interrupted work + +We all wish that we could write beautiful perfect code. But the real world is +much more chaotic: + +- You are in the middle of a "Jackson-Pollock-style" debugging spree with 27 modified files + and debugging prints everywhere. +- Your colleague comes in and wants you to fix/commit something right now. +- What to do? + +Git provides lots of ways to switch tasks without ruining everything. + + +## Option 1: Stashing + +The **stash** is the first and easiest place to temporarily "stash" +things. + +- `git stash` will put working directory and staging area changes + away. Your code will be same as last commit. +- `git stash pop` will return to the state you were before. Can give it a list. +- `git stash list` will list the current stashes. +- `git stash save NAME` is like the first, but will give it a name. + Useful if it might last a while. +- `git stash save [-p] [filename]` will stash certain files files + and/or by patches. +- `git stash drop` will drop the most recent stash (or whichever stash + you give). +- The stashes form a stack, so you can stash several batches of modifications. + + +(exercise-stashing)= + +### Exercise: Stashing + +````{exercise} Interrupted-1: Stash some uncommitted work +1. Make a change. +2. Check status/diff, stash the change with `git stash`, check status/diff again. +3. Make a separate, unrelated change which doesn't touch the same + lines. Commit this change. +4. Pop off the stash you saved with `git stash pop`, and check status/diff. +5. Optional: Do the same but stash twice. Also check `git stash list`. + Can you pop the stashes in the opposite order? +6. Advanced: What happens if stashes conflict with other changes? Make + a change and stash it. Modify the same line or one right above or + below. Pop the stash back. Resolve the conflict. Note there is no + extra commit. +7. Advanced: what does `git graph` show when you have something + stashed? + +```{solution} +5: Yes you can. With `git stash pop INDEX` you can decie which stash +index to pop. + +6: In this case Git will ask us to resolve the conflict the same way +when resolving conflicts between two branches. + +7: It shows an additional commit hash with `refs/stash`. +``` +```` + + +## Option 2: Create branches + +You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch. + +You basically know how to do this: + +```console +$ git switch --create temporary # create a branch and switch to it +$ git add PATHS # stage changes +$ git commit # commit them +$ git switch main # back to main, continue your work there ... +$ git switch temporary # continue again on "temporary" where you left off +``` + +Later you can merge it to main or rebase it on top of main and resume work. + + +## Storing various junk you don't need but don't want to get rid of + +It happens often that you do something and don't need it, but you don't want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still. diff --git a/branch/main/_sources/level.md.txt b/branch/main/_sources/level.md.txt new file mode 100644 index 00000000..b191088c --- /dev/null +++ b/branch/main/_sources/level.md.txt @@ -0,0 +1,120 @@ +# Practical advice: how much Git is necessary? + +:::{instructor-note} +- 20 min teaching/discussion +::: + + +## Writing useful commit messages + +Useful commit messages summarize the change and provide context. + +If you need a commit message that is longer than one line, +then the convention is: **one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary**. + +Good example: +```text +increase alpha to 2.0 for faster convergence + +the motivation for this change is +to enable ... +... +(more context) +... +this is based on a discussion in #123 +``` + +- **Why something was changed is more important than what has changed.** +- Cross-reference to issues and discussions if possible/relevant. +- Bad commit messages: "fix", "oops", "save work" +- Bad examples: [http://whatthecommit.com](http://whatthecommit.com) +- Write commit messages in English that will be understood + 15 years from now by someone else than you. Or by your future you. +- Many projects start out as projects "just for me" and end up to be successful projects + that are developed by 50 people over decades. +- [Commits with multiple authors](https://help.github.com/articles/creating-a-commit-with-multiple-authors/) are possible. + +Good references: + +- ["My favourite Git commit"](https://fatbusinessman.com/2019/my-favourite-git-commit) +- ["On commit messages"](https://who-t.blogspot.com/2009/12/on-commit-messages.html) +- ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) + +```{note} +A great way to learn how to write commit messages and to get inspired by their +style choices: **browse repositories of codes that you use/like**: + +Some examples (but there are so many good examples): +- [SciPy](https://github.com/scipy/scipy/commits/main) +- [NumPy](https://github.com/numpy/numpy/commits/main) +- [Pandas](https://github.com/pandas-dev/pandas/commits/main) +- [Julia](https://github.com/JuliaLang/julia/commits/master) +- [ggplot2](https://github.com/tidyverse/ggplot2/commits/main), + compare with their [release + notes](https://github.com/tidyverse/ggplot2/releases) +- [Flask](https://github.com/pallets/flask/commits/main), + compare with their [release + notes](https://github.com/pallets/flask/blob/main/CHANGES.rst) + +When designing commit message styles consider also these: +- How will you easily generate a changelog or release notes? +- During code review, you can help each other improving commit messages. +``` + +But remember: it is better to make any commit, than no commit. Especially in small projects. +**Let not the perfect be the enemy of the good enough**. + + +## What level of branching complexity is necessary for each project? + +**Simple personal projects**: +- Typically start with just the `main` branch. +- Use branches for unfinished/untested ideas. +- Use branches when you are not sure about a change. +- Use tags to mark important milestones. +- If you are unsure what to do with unfinished and not working code, commit it + to a branch. + +**Projects with few persons: you accept things breaking sometimes** +- It might be reasonable to commit to the `main` branch and feature branches. + +**Projects with few persons: changes are reviewed by others** +- You create new feature branches for changes. +- Changes are reviewed before they are merged to the `main` branch + (more about that in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). +- Consider to write-protect the `main` branch so that it can only be changed + with pull requests or merge requests. + + +## How about staging and committing? + +- Commit early and often: rather create too many commits than too few. + You can always combine commits later. +- Once you commit, it is very, very hard to really lose your code. +- Always fully commit (or stash) before you do dangerous things, so that you know you are safe. + Otherwise it can be hard to recover. +- Later you can start using the staging area (where you first stage and then commit in a second step). +- Later start using `git add -p` and/or `git commit -p`. + + +## How large should a commit be? + +- Better too small than too large (easier to combine than to split). +- Often I make a commit at the end of the day (this is a unit I would not like to lose). +- Smaller sized commits may be easier to review for others than huge commits. +- Imperfect commits are better than no commits. +- A commit should not contain unrelated changes to simplify review and possible + repair/adjustments/undo later (but again: imperfect commits are better than no commits). + +--- + +:::{keypoints} +- There is no one size fits all - start simple and grow your project. +::: + +:::{discussion} +How do you [plan to] use Git? + +- Advanced users or beginners, please provide your input in the online collaborative document. +::: diff --git a/branch/main/_sources/local-workflow.md.txt b/branch/main/_sources/local-workflow.md.txt new file mode 100644 index 00000000..1414d608 --- /dev/null +++ b/branch/main/_sources/local-workflow.md.txt @@ -0,0 +1,371 @@ +# Cloning a Git repository and working locally + +If you've been following the main path, you have just had interacted +with repositories on GitHub. This might not be what you usually +do, so now we move to working on your own computer. + +:::{objectives} +- We are able to clone a repository from the web and modify it locally. +- We can do the same things we did before (commit, branch, merge), but locally. +- We get a feeling for remote repositories ([more later](https://coderefinery.github.io/git-collaborative/)). +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## What is in a Git repository and what are we cloning? + +**Git repository**: +- Contains all the files and directories of a project. +- Contains the complete history of all changes (commits) to these files and directories. +- Each commit is a snapshot of the entire project at a certain point in time and has a unique identifier ("hash"). +- Sometimes it contains multiple branches and tags. +- All the commits and history of a local repository are stored in a directory + called `.git` which is located at the root of the repository. + +**Cloning**: +- Copying (downloading) the entire repository with all commits, branches, and tags to your computer. +- It is a full backup of the repository, including all history. +- You can then work on your local clone of the repository. +- Changes on local clone will not automatically appear in the repository where + we cloned from. We have to actively "push" them there (we will practice this + in a later episode: {ref}`sharing-repositories`). + + +## Exercise + +Work on this by yourself or in your teams. Conceptually this episode should +seem familiar, from the browser-based exercises we did yesterday. + +We offer the **Command Line and VS Code** paths for this exercise. +GitHub isn't an option in this episode, since that is what we already +demonstrated in {doc}`commits` and {doc}`merging` and since the point of this +episode is to work **locally**. + +It is also possible to use the command line (terminal) from inside VS Code. + +```{exercise} Exercise: Cloning a Git repository and working locally (25 min) +1. {ref}`Configure Git command line and editor ` if you haven't done that already. +1. **Decide which repository you want to clone**: your fork or the original repository? Both will work for this exercise. + Then, **clone the recipe book**. +1. **Create a new branch**. +1. Make a **commit** on your new branch. +1. **Switch** back to the `main` branch and create one or two commits there. +1. **Merge** the new branch into `main`. +1. Compare the graph locally and on GitHub and observe that the **changes only exist locally on your computer**. +1. Where are the **remote branches**? Practice how you can see all remote branches + also locally and how you can fetch them and make local changes to them. +``` + +The solution below goes over most of the answer and should be used as +your guide (you can't figure it out just from the exercise instructions). + + +## Solution and walk-through + + +### (1) Configure Git command line and editor + +We have an own section for this: {ref}`configuration`. + + +### (2) Cloning a repository + +Now you need to decide which repository you want to clone. All of these options will work for this exercise +since we don't plan to push changes back (for step 8 it might be easier to use the original repository): +- Clone the recipe book from your fork. +- Or clone the recipe book from the original repository: +- Or first fork the original repository and then clone your fork. + +The examples below assume you are cloning the original repository. If you are cloning your fork, you should +replace `coderefinery` with your GitHub username. + +:::::::{tabs} +::::::{group-tab} Command line +If you are unsure whether you are using SSH or HTTPS, please read {ref}`clone-method`. + :::::{tabs} + ::::{group-tab} SSH + ```console + $ git clone git@github.com:coderefinery/recipe-book.git + ``` + :::: + + ::::{group-tab} HTTPS + ```console + $ git clone https://github.com/coderefinery/recipe-book.git + ``` + :::: + ::::: + +This creates a directory called "recipe-book" unless it already exists. You can also specify the target directory +on your computer (in this case "my-recipe-book"): + :::::{tabs} + ::::{group-tab} SSH + ```console + $ git clone git@github.com:coderefinery/recipe-book.git my-recipe-book + ``` + :::: + + ::::{group-tab} HTTPS + ```console + $ git clone https://github.com/coderefinery/recipe-book.git my-recipe-book + ``` + :::: + ::::: +:::::: + +::::::{group-tab} VS Code +Under "Start" on the screen, select "Clone Git Repository...". + +Alternatively navigate to the "Source Control" tab on the left sidebar and +click on the "Clone Repository" button. + +Paste in this URL: `https://github.com/USER/recipe-book` (replace `USER`) +:::::: +::::::: + + +### (3) Creating branches locally + +:::::{tabs} +::::{group-tab} Command line +Create a new branch called `another-recipe` from `main` and switch to it: +```console +$ git switch --create another-recipe main +``` + +If you leave out the last argument, it will create a branch from the current +branch: +```console +$ git switch --create another-recipe +``` +:::: + +::::{group-tab} VS Code +1. Make sure that you are on the main branch. +1. Source Control button on left sidebar → Three dots in upper right of source control → Branch → Create Branch. +1. VS Code automatically switches to the new branch. + +:::{figure} img/commits/vscode-create-branch.png +:width: 80% +:class: with-border +:alt: VS Code screenshot of create branch + +Creating a new branch in VS Code. +:::: +::::: + + +### (4) Creating commits locally + +:::::{tabs} +::::{group-tab} Command line +Create a new file. **After we have created it**, we can stage and commit +the change: +```console +$ git add new-file.md +$ git commit -m "Short summary of the change" +``` + +Make sure to replace "new-file.md" with the actual name of the file you created +and to replace "Short summary of the change" with a meaningful commit message. +:::: + +::::{group-tab} VS Code +1. Create a new file. +1. In the version control sidebar, click the `+` sign to add the file for the next commit. +1. Enter a brief message and click "Commit". + +:::{figure} img/commits/vscode-add-and-commit.png +:alt: Screenshot of VS Code commit process +:width: 80% +:class: with-border + +Committing a new file in VS Code. +::: +:::: +::::: + + +### (5) Switching branches and creating commits + +:::::{tabs} +::::{group-tab} Command line +First switch to the `main` branch: +```console +$ git switch main +``` + +Then modify a file. Finally `git add` and then commit the change: +```console +$ git commit -m "Short summary of the change" +``` +:::: + +::::{group-tab} VS Code +Use the branch selector at the bottom to switch back to the main branch. +Repeat the same steps as above. + +:::{figure} img/commits/vscode-change-branch.png +:class: with-border +:width: 80% +:alt: VS Code screenshot + +Switching branch via selector at bottom. +:::: +::::: + + +### (6) Merging branches locally + +:::::{tabs} +::::{group-tab} Command line +On the command line, when we merge, we always modify our current branch. + +If you are not sure anymore what your current branch is, type: +```console +$ git branch +``` + +Another way to find out where we are in Git: +```console +$ git status +``` + +In this case we merge the `another-recipe` branch into our current branch: +```console +$ git merge another-recipe +``` +:::: + +::::{group-tab} VS Code +Just like with the command line, when we merge we modify our *current* branch. Verify you are on the `main` branch. + +1. Verify current branch at the bottom. +1. From the version control sidebar → Three dots → Branch → Merge +1. In the selector that comes up, choose the branch you want to merge *from*. The commits on that branch will be added to the current branch. + +:::{figure} img/merging/vscode-merging.png +:alt: VSCode screenshot as described +:width: 80% +:class: with-border +:::: +::::: + + +### (7) How to compare the graph locally and on GitHub + +:::::{tabs} +::::{group-tab} Command line +```console +$ git log --graph --oneline --decorate --all +``` + +We recommend to define an {term}`alias` in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command: +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +``` +Then you can just type `git graph` from there on. We have an own section about +aliases: {ref}`aliases`. + +Compare this with the graph on GitHub: Insights tab → Network view (just like +we have done before). + +The result is that we should not be able to see the new branch and the new +commits on GitHub. +:::: + +::::{group-tab} VS Code +This requires an extension. Opening the VS Code terminal lets you use the command line method. + +:::{figure} img/commits/vscode-open-terminal.png +:class: with-border +:width: 80% +:alt: VS Code screenshot as described + +View → Terminal will open a terminal at bottom. This is a normal command line interface and very useful for work. (Note the git-aware prompt that shows the current branch. This requires other setup.) +:::: +::::: + + +### (8) Browsing remote branches and creating local branches from them + +:::::{tabs} +::::{group-tab} Command line +With `git branch` you can list all local branches: +```console +$ git branch + + another-recipe +* main +``` + +But where are the remote branches? We expect to see [a couple of +them](https://github.com/coderefinery/recipe-book/branches/all). + +We can see them by asking for all branches (your output might vary depending on +where you cloned from): +```console +$ git branch --all + + another-recipe +* main + remotes/origin/HEAD -> origin/main + remotes/origin/alex/fruit-salad + remotes/origin/main + remotes/origin/radovan/lasagna + remotes/origin/radovan/poke +``` + +You can create a local branch from a remote branch which will "track" the remote branch. +For instance, to create a local branch `alex/fruit-salad` from the remote branch `origin/alex/fruit-salad` +and switch to it, you can do: +```console +$ git switch --create alex/fruit-salad origin/alex/fruit-salad +``` + +This shortcut will do the same thing: +```console +$ git switch --track origin/alex/fruit-salad +``` + +Or even shorter: +```console +$ git switch alex/fruit-salad +``` + +If you want to create a branch and not switch to it, you can use `git branch`. +```console +$ git branch alex/fruit-salad +``` +:::: + +::::{group-tab} VS Code +To create a local branch from a remote branch: + +Source Control button on left sidebar → Three dots in upper right of source control → Branch → +"Create Branch From ...". + +Then select the remote branch you want to create a local branch from. +:::: +::::: + + +## Summary + +- When we clone a repository, we get a full backup of the repository, including + all history: all commits, branches, and tags. +- Yesterday we learned about branches and commits, and now we created and used them locally. +- **Creating local branches and commits does not automatically modify the remote + repository**. To "push" our local changes to the remote repository, we have to actively + "push" them there. We will practice this in a later episode: + {ref}`sharing-repositories` +- Remote branches and local branches are not the same thing. If we want to + create local commits, we always need to create a local branch first. But the local branch can + "track" the remote branch and we can push and pull changes to and from the + remote branch. diff --git a/branch/main/_sources/merging.md.txt b/branch/main/_sources/merging.md.txt new file mode 100644 index 00000000..8bfba557 --- /dev/null +++ b/branch/main/_sources/merging.md.txt @@ -0,0 +1,435 @@ +# Merging changes and contributing to the project + +Git allows us to have different development lines where we can try things out. +It also allows different people to work on the same project at the same. This +means that we have to somehow combine the changes later. In this part we will +practice this: {term}`merging`. + +:::{objectives} +- Understand that on GitHub merging is done through a {term}`pull request`. Think of it as a change proposal. +- Create and merge a pull request within your own repository. +- Understand (and optionally) do the same across repositories, to contribute to + the {term}`upstream` public repository. +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## Background + +* In the last episode, we added a new recipe on a branch. This allows + us to test it before it becomes "live". +* Now, we want to bring that change into the "main" branch. +* We will find it's not that hard! But you do have to keep track of the + steps and make sure that you work very precisely. + + +## Exercise + +In this exercise, we will show how we can **propose changes** and **merge +changes** within our own repository. Optionally, you can propose a recipe to +the {term}`upstream` recipe book - which shows the true purpose of this. But +this is only a preview and we will practice collaboration much more in the +[collaborative Git lesson](https://coderefinery.github.io/git-collaborative/). + +We offer **three different paths** of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the **GitHub +path** only and recommend you do that. The exercise text below has +some GitHub-specific notes, but most is possibly with any path. + +:::::{tabs} +::::{group-tab} GitHub + +First, we make something called a {term}`pull request`, which allows +review and commenting before the actual merge. + +:::{exercise} Exercise: Merging branches with pull requests (20 min) +We assume that in the previous exercise you have created a new branch +with a recipe. In our previous example, it is called `new-recipe`. +If not, create it first and add a recipe to your new branch, see +{doc}`commits`. + +We provide basic hints. You should refer to the solution as needed. + +1. Navigate to your branch from the previous episode + (Hint: the same branch view we used last time). + +1. Begin the pull request process. + (Hint: There is a "Contribute" button in the branch view). + +1. Add or modify the pull request title and description, and verify the other data. + In the pull request verify the target repository and the target + branch. Make sure that you are merging within your own repository. + **GitHub: By default, it will offer to make the change to the + upstream repository, `coderefinery`. You should change this**, you + shouldn't contribute your test recipe upstream yet. Where it says + `base repository`, select your own user's repository. + +1. Create the pull request by clicking "Create pull request". Browse + the network view to see if anything has changed yet. + +1. Merge the pull request, or if you are not on GitHub you can merge + the branch locally. Browse the network again. What has changed? + +1. Find out which branches are merged and thus safe to delete. Then remove them + and verify that the commits are still there, only the branch labels are + gone. (Hint: you can delete branches that have been merged into `main`). + +1. Optional: Try to create a new branch with a new change, then open a pull + request but towards the central repository. We will later merge few of + those. + (Hint: this is mostly the same as above, for the GitHub path. But, + you set the base repository as CodeRefinery. You might need to + compare across forks.) +::: +:::: + +::::{group-tab} Local (VS Code, Command line) + +When working locally, it's easier to merge branches: we can just do +the merge, without making a pull request. But we don't have that step +of review and commenting and possibly adjusting. + +:::{exercise} + +1. Switch to the `main` branch that you want to merge the *other* + branch into. (Note that this is the other way around from the + GitHub path). + +Then: + +5. Merge the other branch into `main` (which is then your current branch). + +6. Find out which branches are merged and thus safe to delete. Then remove them + and verify that the commits are still there, only the branch labels are + gone. (Hint: you can delete branches that have been merged into `main`). + +7. (optional, advanced) Try to create a new branch, and make a + GitHub pull request with your recipe, and contribute it to our + upstream repository. *This is very complex right now since your + change has to get to GitHub, and we haven't shown that yet. We + don't give a solution for this.* +::: + +:::: +::::: + +The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren't enough - this is by design. + + +## Solution and walk-through + +### (1) Navigate to your branch + +Before making the pull request, or doing a merge, it's important to +make sure that you are on the right branch. Many people have been +frustrated because they forgot this! + +:::::{tabs} +::::{group-tab} GitHub +On GitHub make sure you are on the branch you want to merge **from**: + :::{figure} img/merging/github-navigate-to-branch.png + :alt: Screenshot on GitHub where we navigate to the branch we wish to merge. + :width: 80% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +Remember, you need to switch to the `main` branch, the branch we want to merge **to**. +This is different from the GitHub path. +:::: + +::::{group-tab} Command line +Remember, you need to switch to the `main` branch, the branch we want to merge **to**. +This is different from the GitHub path: +```console +$ git switch main +``` +:::: +::::: + + +### (2) Begin the pull request process + +In GitHub, the pull request is the way we propose to merge two +branches together. We start the process of making one. + +:::::{tabs} +::::{group-tab} GitHub + :::{figure} img/merging/github-contribute.png + :alt: Screenshot on GitHub where we get to the pull request process. + :width: 80% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +It is possible to open pull requests from the editor, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +It is possible to open pull requests from the command line, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: +::::: + + +### (3) Fill out and verify the pull request + +Check that the pull request is directed to the right repository and branch +and that it contains the changes that you meant to merge. + +:::::{tabs} +::::{group-tab} GitHub +Things to check: +- Base repository: this should be your own +- Title: make it descriptive +- Description: make it informative +- Scroll down to see commits: are these the ones you want to merge? +- Scroll down to see the changes: are these the ones you want to merge? + :::{figure} img/merging/github-comparing-changes.png + :alt: Screenshot on GitHub where we verify the changes we want to merge. + :width: 80% + :class: with-border + + This screenshot only shows the top part. If you scroll down, you + can see the commits and the changes. We recommend to do this before + clicking on "Create pull request". + ::: +:::: + +::::{group-tab} VS Code +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +If you are working locally, continue to step 5. +:::: +::::: + + +### (4) Create the pull request + +We actually create the pull request. Don't forget to navigate to the Network +view after opening the pull request. Note that the changes proposed in the +pull request are not yet merged. + +:::::{tabs} +::::{group-tab} GitHub +Click on the green button "Create pull request". + +If you click on the little arrow next to "Create pull request", you can also +see the option to "Create draft pull request". This will be interesting later +when collaborating with others. It allows you to open a pull request that is +not ready to be merged yet, but you want to show it to others and get feedback. +:::: + +::::{group-tab} VS Code +It is possible to create pull requests from the editor, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: + +::::{group-tab} Command line +It is possible to create pull requests from the command line, but +we don't cover that here. + +If you are working locally, continue to step 5. +:::: +::::: + + +### (5) Merge the pull request + +Now, we do the actual merging. We see some effects now. + +:::::{tabs} +::::{group-tab} GitHub +Review it again (commits and changes), and then click "Merge pull request". + +After merging, verify the network view. Also navigate then to your "main" +branch and check that your new recipe is there. +:::: + +::::{group-tab} VS Code +Just like with the command line, when we merge we modify our *current* branch. Verify you are on the `main` branch. + +1. Verify current branch at the bottom. +1. From the version control sidebar → Three dots → Branch → Merge +1. In the selector that comes up, choose the branch you want to merge *from*. The commits on that branch will be added to the current branch. + +:::{figure} img/merging/vscode-merging.png +:alt: VSCode screenshot as described +:width: 80% +:class: with-border +:::: + +::::{group-tab} Command line +On the command line, when we merge, we always modify our *current* branch. + +If you are not sure anymore what your current branch is, type: +```console +$ git branch +``` +... or equally useful to see where we are right now: +```console +$ git status +``` + +In this case we merge the `new-recipe` branch into our current branch: +```console +$ git merge new-recipe +``` +:::: +::::: + + +### (6) Delete merged branches + +Before deleting branches, first check whether they are merged. + +If you delete an un-merged branch, it will be difficult to find the commits +that were on that branch. If you delete a merged branch, the commits are now +also part of the branch where we have merged to. + +:::::{tabs} +::::{group-tab} GitHub +One way to delete the branch is to click on the "Delete branch" button after the pull +request is merged: + :::{figure} img/merging/github-merged.png + :alt: Screenshot on GitHub suggesting us to delete a branch after it has been merged. + :width: 80% + :class: with-border + ::: + +But what if we forgot? Then navigate to the branch view: + :::{figure} img/merging/github-branches.png + :alt: Screenshot on GitHub where we navigate to the branches view. + :width: 80% + :class: with-border + ::: + +In the overview we can see that it has been merged and we can delete it: + :::{figure} img/merging/github-branches-overview.png + :alt: Screenshot on GitHub where we see an overview of branches and can delete them. + :width: 100% + :class: with-border + ::: +:::: + +::::{group-tab} VS Code +From the Source Control sidebar → the three dots (as before) → Branch → Delete Branch. Select the branch name to delete. +:::: + +::::{group-tab} Command line +Verify which branches are merged to the current branch: +```console +$ git branch --merged + +* main + new-recipe +``` + +This means that it is safe to delete the `new-recipe` branch: +```console +$ git branch -d new-recipe +``` + +Verify then that the branch is gone but that the commits are still there: +```console +$ git branch +$ git log --oneline +``` +:::: +::::: + + +### (7) Contribute to the original repository with a pull request + +Remember, this is an advanced step. If you do this, you are donating +a recipe to everyone. + +:::::{tabs} +::::{group-tab} GitHub +Now that you know how to create branches and opening a pull request, try to +open a new pull request with a new change but this time the base repository +should be the upstream one. + +In other words, you now send a pull request across repositories: from your fork +to the original repository. + +Another thing that is different now is that you might not have permissions to +merge the pull request. We can then together review and browse the pull +request. +:::: + +::::{group-tab} VS Code +Not described. We will return to this in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +You would create a new branch locally like above, {term}`push` it to GitHub to your own user's repository `USER/recipe-book`, then go to GitHub and open a pull request *to* `coderefinery/recipe-book`. Or you do it all through VS Code. +:::: + +::::{group-tab} Command line +Not described. We will return to this in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +You would create a new branch locally like above, {term}`push` it to GitHub to your own user's repository `USER/recipe-book`, then go to GitHub and open a pull request *to* `coderefinery/recipe-book`. + +:::: +::::: + + +## Resolving a conflict (demonstration) + +A conflict is when Git asks humans to decide during a merge which of two +changes to keep if the same portion of a file has been changed in two different +ways on two different branches. + +We will practice conflict resolution in the [collaborative Git +lesson](https://coderefinery.github.io/git-collaborative/). + +Here we will only demonstrate how to create a conflict and how to resolve it, +all on GitHub. Once we understand how this works, we will be more confident to +resolve conflicts also in the command line. + +How to create a conflict (please try this in your own time *and just watch now*): +- Create a new branch from `main` and on it make a change to a file. +- On `main`, make a different change to the same part of the same file. +- Now try to merge the new branch to `main`. You will get a conflict. + +How to resolve conflicts: +- On GitHub, you can resolve conflicts by clicking on the "Resolve conflicts" + button. This will open a text editor where you can choose which changes to + keep. + Make sure to remove the conflict markers. + After resolving the conflict, you can commit the changes and merge the + pull request. +- Sometimes a conflict is between your change and somebody else's change. In + that case, you might have to discuss with the other person which changes to + keep. + +How to avoid conflicts: +- We will talk about it in the [collaborative Git + lesson](https://coderefinery.github.io/git-collaborative/). + + +## Summary + +- We learned how to merge two branches together. +- When is this useful? This is not only useful to combine development lines in + your own work. Being able to merge branches also forms a basis for collaboration. +- Branches which are merged to other branches are safe to delete, since we only + delete the "sticky note" next to a commit, not the commits themselves. diff --git a/branch/main/_sources/motivation.md.txt b/branch/main/_sources/motivation.md.txt new file mode 100644 index 00000000..60c0e11c --- /dev/null +++ b/branch/main/_sources/motivation.md.txt @@ -0,0 +1,184 @@ +# Motivation + +```{objectives} +- Make sure nobody leaves the workshop without starting to use some form of version control. +- Discuss the reasons why we advocate distributed version control. +``` + +```{instructor-note} +- 15 min discussion/demonstration +``` + + +## Git is all about keeping track of changes + +We will learn how to keep track of changes first in the web browser. +Below are screenshots of **tracked changes with Git** +(from this [example repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): +```{figure} img/git-log-github.png +:alt: Screenshot of a git log on GitHub +:width: 80% +:class: with-border + +Web browser, GitHub view +``` +Later also using the terminal or the editor +(the same [example repository](https://github.com/bast/runtest/commits/main/runtest/run.py)): +```{figure} img/git-log-terminal.png +:alt: Screenshot of a git log in terminal +:width: 80% + +The same as above, but the terminal view +``` + + +## Why do we need to keep track of versions? + +**Problem: If you have to identify and find your code from 17 days +ago, can you?** + +Version control is an answer to the following questions (do you recognize some +of them?): + +- "It broke ... hopefully I have a working version somewhere?" + +- "Can you please send me the latest version?" + +- "Where is the latest version?" + +- "Which version are you using?" + +- "Which version have the authors used in the paper I am trying to reproduce?" + +- "Found a bug! Since when was it there?" + +- "I am sure it used to work. When did it change?" + +- "My laptop is gone. Is my thesis now gone?" + + +## Features: roll-back, branching, merging, collaboration + +**Problem: Your code worked two days ago, but is giving an error now. +You don't know what you changed.** + +**Problem: You and your colleague want to work on the same code at the +same time.** + + +- **Roll-back**: you can always go back to a previous version and compare + +- **Branching and merging**: + - Work on different ideas at the same time + - Different people can work on the same code/project without interfering + - You can experiment with an idea and discard it if it turns out to be a bad idea + +```{figure} img/gopher/gophers.png +:alt: Branching explained with a gopher +:width: 100% + +Image created using +([inspiration](https://twitter.com/jay_gee/status/703360688618536960)). +``` + +- **Collaboration**: review, compare, share, discuss + +- [Example network graph](https://github.com/coderefinery/git-intro/network) + + +## Reproducibility + +**Problem: Someone asks you about your results from 5 years ago. Can +you get the same results now?** + +- How do you indicate which version of your code you have used in your paper? +- When you find a bug, how do you know **when precisely** this bug was introduced + (Are published results affected? Do you need to inform collaborators or users of your code?). + +With version control we can "annotate" code +([browse this example online](https://github.com/networkx/networkx/blame/main/networkx/algorithms/boundary.py)): + +```{figure} img/git-annotate.png +:alt: Example of a git-annotated code with code and history side-by-side +:width: 100% +:class: with-border + +Example of a git-annotated code with code and history side-by-side. +``` + + +## Talking about code + +**Problem: You want to show someone a few lines from one of your projects.** + +Which of these two is more practical? +- "Clone the code, go to the file 'src/util.rs', and search for 'time_iso8601'". + Oh! But make sure you use the version from August 2023." +- Or I can send you a [permalink](https://github.com/NordicHPC/sonar/blob/75daafc86582feb06299d6a47c82112f39888152/src/util.rs#L40-L44): + +```{figure} img/code-portion.png +:alt: Screen-shot of a code portion +:width: 100% +:class: with-border + +Permalink that points to a code portion. +``` + + +## What we typically like to snapshot + +- Software (this is how it started but Git/GitHub can track a lot more) +- Scripts +- Documents (plain text files much better suitable than Word documents) +- Manuscripts (Git is great for collaborating/sharing LaTeX or [Quarto](https://quarto.org/) manuscripts) +- Configuration files +- Website sources +- Data + +````{discussion} + In this example somebody tried to keep track of versions without a version + control system tool like Git. Discuss the following directory listing. What + possible problems do you anticipate with this kind of "version control": + ```shell + myproject-2019.zip + myproject-2020-February.zip + myproject-2021-August.zip + myproject-2023-09-19-working.zip + myproject-2023-09-21.zip + myproject-2023-09-21-test.zip + myproject-2023-09-21-myversion.zip + myproject-2023-09-21-newfeature.zip + ... + ``` + + ```{solution} + - Giving a version to a collaborator and merging changes later with own + changes sounds like lots of work. + - What if you discover a bug and want to know since when the bug existed? + ``` +```` + + +## Difficulties of version control + +Despite the benefits, let's be honest, there are some difficulties: + +- One more thing to learn (it's probably worth it and will save you more time in the long run; basic career skill). +- Difficult if your collaborators don't want to use it (in the worst case, you can version control on your side and email them versions). +- Advanced things can be difficult, but basics are often enough (ask others for help when needed). + + +## Why Git and not another tool? + +- **Easy to set up**: no server needed. +- **Very popular**: chances are high you will need to contribute to somebody else's code which is tracked with Git. +- **Distributed**: good backup, no single point of failure, you can track and + clean-up changes offline, simplifies collaboration model for open-source + projects. +- Important **platforms** such as [GitHub](https://github.com), [GitLab](https://gitlab.com), and [Bitbucket](https://bitbucket.org) + build on top of Git. + +However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +[Subversion](https://subversion.apache.org), +[Mercurial](https://www.mercurial-scm.org), [Pijul](https://pijul.org/), or others. diff --git a/branch/main/_sources/recovering.md.txt b/branch/main/_sources/recovering.md.txt new file mode 100644 index 00000000..3c705f3e --- /dev/null +++ b/branch/main/_sources/recovering.md.txt @@ -0,0 +1,260 @@ +# Undoing and recovering + +```{objectives} +- Learn to undo changes safely +- See when undone changes are permanently deleted and when they can be retrieved +``` + +```{instructor-note} +- 25 min teaching/type-along +- 25 min exercise +``` + +One of the main points of version control is that you can *go back in +time to recover*. Unlike this xkcd comic implies: + +In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn't a "commit" permanent? + +- You can modify old commit history. +- But if you have shared that history already, *modifying it can make + a huge mess*. + +```{admonition} It is almost always possible to recover +As long as you commit something once (or at least `git add` it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru... *until that guru becomes you*. +``` + +```{admonition} Nice resource to visually simulate Git operation +[git-sim](https://github.com/initialcommit-com/git-sim#video-animation-examples) +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command. +``` + +--- + +## Undoing your recent, uncommitted and unstaged changes (preserves history) + +```{note} +In case `git restore` does not work, your Git version might be older than from 2019. +On older Git it is `git checkout` instead of `git restore`. +``` + +You do some work, and want to **undo your uncommitted and unstaged modifications**. +You can always do that with: + +- `git restore .` (the dot means "here and in all folders below") + +You can also undo things selectively: + +- `git restore -p` (decide which portions of changes to undo) or `git restore PATH` (decide which path/file) + +If you have staged changes, you have at least two options to undo the staging: +- `git restore --staged .` followed by `git status` and `git restore .` +- `git reset --hard HEAD` throws away everything that is not in last + commit (`HEAD` - this literal word, this isn't a placeholder) + +--- + +## Reverting commits (preserves history) + +Imagine we made a few commits. +We realize that the latest commit `e02efcd` was a mistake and we wish to undo it: +```console +$ git log --oneline + +e02efcd (HEAD -> main) not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +A safe way to undo the commit is to revert the commit with `git revert`: +```console +$ git revert e02efcd +``` + +This creates a **new commit** that does the opposite of the reverted commit. +The old commit remains in the history: +```console +$ git log --oneline + +d3fc63a (HEAD -> main) Revert "not sure this is a good idea" +e02efcd not sure this is a good idea +b4af65b improve the documentation +e7cf023 don't forget to enjoy +79161b6 add half an onion +a3394e3 adding README +3696246 adding instructions +f146d25 adding ingredients +``` + +You can revert any commit, no matter how old it is. It doesn't affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we'll learn about later). + +(exercise-revert)= + +### Exercise: Revert a commit + +```{exercise} Undoing-1: Revert a commit +- Create a commit (commit A). +- Revert the commit with `git revert` (commit B). +- Inspect the history with `git log --oneline`. +- Now try `git show` on both the reverted (commit A) and the newly created commit (commit B). +``` + + +## Adding to the previous commit (modifies history) + +Sometimes we commit but realize we forgot something. +We can amend to the last commit: + +```console +$ git commit --amend +``` + +This can also be used to modify the last commit message. + +Note that this **will change the commit hash**. This command **modifies the history**. +This means that we avoid this command on commits that we have shared with others. + +(exercise-amend)= + +### Exercise: Modify a previous commit + +````{exercise} Undoing-2: Modify a previous commit +1. Make an incomplete change to the recipe or a typo in your change, `git + add` and `git commit` the incomplete/unsatisfactory change. +2. Inspect the unsatisfactory but committed change with `git show`. Remember + or write down the commit hash. +3. Now complete/fix the change but instead of creating a new commit, add the + correction to the previous commit with `git add`, followed by `git commit + --amend`. What changed? + + ```{solution} + One thing that has changed now is the commit hash. Modifying the previous + commit has changed the history. This is OK to do on commits that other people + don't depend on yet. + ``` +```` + + +## Rewinding branches (modifies history) + +You can **reset branch history** to move your branch back to some +point in the past. + +* `git reset --hard HASH` will force a branch label to any other point. All + other changes are lost (but it is possible to recover if you force reset by mistake). +* Be careful if you do this - it can mess stuff up. Use `git graph` a + lot before and after. + + +(exercise-reset)= + +### Exercise: Git reset + +````{exercise} Undoing-3: Destroy our experimentation in this episode + After we have experimented with reverts and amending, let us destroy + all of that and get our repositories to a similar state. + + - First, we will look at our history (`git log`/`git graph`) and + find the last commit `HASH` before our tests. + - Then, we will `git reset --hard HASH` to that. + - Then, `git graph` again to see what happened. + + ```console + $ git log --oneline + + d3fc63a (HEAD -> main) Revert "not sure this is a good idea" + e02efcd not sure this is a good idea + b4af65b improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + + $ git reset --hard b4af65b + + HEAD is now at b4af65b improve the documentation + + $ git log --oneline + + b4af65b (HEAD -> main) improve the documentation + e7cf023 don't forget to enjoy + 79161b6 add half an onion + a3394e3 adding README + 3696246 adding instructions + f146d25 adding ingredients + ``` +```` + +--- + +## Recovering from committing to the wrong branch + +It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes. + +Here we assume that we made a couple of commits but we realize they went to the +wrong branch. + +**Solution 1 using git cherry-pick**: +1. Make sure that the correct branch exists and if not, create it. Make sure to + create it from the commit hash where you wish you had created it from: `git + branch BRANCHNAME HASH` +2. Switch to the correct branch. +3. `git cherry-pick HASH` can be used to take a specific commit to the + current branch. Cherry-pick all commits that should have gone to the correct + branch, **from oldest to most recent**. +4. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + +**Solution 2 using `git reset --hard`** (makes sense if the correct branch should +contain all commits of the accidentally modified branch): +1. Create the correct branch, pointing at the latest commit: `git branch BRANCHNAME`. +2. Check with `git log` or `git graph` that both branches point to the same, latest, commit. +3. Rewind the branch that accidentally got wrong commits with `git reset --hard` (see also above). + + +## Recovering from merging/pulling into the wrong branch + +`git merge`, `git rebase`, and `git pull` modify the **current** branch, never +the other branch. But sometimes we run this command on the wrong branch. + +1. Check with `git log` the commit hash that you would like to rewind the + wrongly modified branch to. +2. Rewind the branch that accidentally got wrong commits with `git reset --hard HASH` (see also above). + + +## Recovering from conflict after pulling changes + +Pulling changes with +`git pull` can create a conflict since `git pull` always also includes a `git merge` (more about this +in the [collaborative Git lesson](https://coderefinery.github.io/git-collaborative/)). + +The recovery is same as described in {ref}`conflict-resolution`. Either +resolve conflicts or abort the merge with `git merge --abort`. + +--- + +````{challenge} Undoing-4: Test your understanding + 1. What happens if you accidentally remove a tracked file with `git rm`, is it gone forever? + 2. Is it OK to modify commits that nobody has seen yet? + 3. What situations would justify to modify the Git history and possibly remove commits? + + ```{solution} + 1. It is not gone forever since `git rm` creates a new commit. You can revert the commit to get the file back. + 2. If you haven't shared your commits with anyone it can be alright to modify them. + 3. If you have shared your commits with others (e.g. pushed them to GitHub), only extraordinary + conditions would justify modifying history. For example to remove sensitive or secret information. + ``` +```` diff --git a/branch/main/_sources/reference.md.txt b/branch/main/_sources/reference.md.txt new file mode 100644 index 00000000..80a5cce8 --- /dev/null +++ b/branch/main/_sources/reference.md.txt @@ -0,0 +1,158 @@ +# Quick reference + +## Other cheatsheets + +* [Detailed 2-page Git + cheatsheet](https://aaltoscicomp.github.io/cheatsheets/git-the-way-you-need-it-cheatsheet.pdf) +* [Interactive Git cheatsheet](http://www.ndpsoftware.com/git-cheatsheet.html) + + +## Glossary + +:::::{glossary} + +alias + With aliases you can define your own shortcuts for Git commands. + +version control system + A system that records changes to a file or set of files over time so that + you can recall specific versions later. + +git + Implementation of a version control system. Currently the most popular one. + +commit + As a verb, the process of recording more changes. + As a noun, the name of the record of changes. + A commit is identified by something such as `554c187`. + +working directory +workspace + the actual files you see and edit + +staging area + Place files go after `git add` and before `git commit` + +hash + Unique reference of any commit or state. Comes from [hash + functions](https://en.wikipedia.org/wiki/Hash_function) such as MD5 + or SHA1. + +branch + One line of work. Different branches can exist at the same time + and split/merge. Committing on a branch updates that branch. + +tag + Like a {term}`branch` in that it points to a commit for reference. + It is designed to be permanent an not updated. + +HEAD + Pointer to the most recent commit on the current branch. + +remote + Roughly, another server that holds .git. + +origin + Default name for a remote repository. + +repository + One collection of files managed by Git. It contains entire history + of all files managed by git. GitHub has one repository as one + GitHub repository. VS Code has one repository as one directory you + can open. The command line has one repository as one directory. + +clone + As a verb, the process of making a copy of a repository locally. + It brings in all history and all files. (As a noun, the copy that + was made when cloning). + +GitHub repository + The files from the Git repository, but also other things from + GitHub such as access permissions, issues, and pull requests. + +upstream + The original repository from which the code comes. If you + {term}`fork` the repository, it is your upstream and it is easy to + send changes back to there. + +fork + As a noun: a one person's copy of a repository. + As a verb: making that copy. + As a verb on GitHub: Making a copy of a repository linked to the + original. It is easy to send changes to the original + +issue + Within a web repository like GitHub, discussion of a topic, for + example a problem or improvement suggestion. These are a property + of the web platform and not of the Git program itself. + +pull request + A GitHub concept: change proposal. A proposal to merge one branch + into another. Usually used to contribute code back to + {term}`upstream`. + +push + Moving changes from your local copy to another copy + +pull + Getting changes from another copy to your own copy. `git pull` + does this fetch, and also tries to automatically merge. + +master + Default name for main branch on Git. Depending on the configuration and service, + the default branch is sometimes **main**. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. + +main + Default name for main branch on GitLab and GitHub. + In this lesson we configure Git so that the default branch is + called **main** to be more consistent with GitHub and GitLab. + +merge +merging + Bringing changes from one branch into another, either as a noun or + verb. + +VS Code + A text editor and development environment by Microsoft. It's quite + popular, partly because it is powerful and easy to use. [VS + Codium](https://vscodium.com/) is the same but without Microsoft + tracking. +::::: + +## Commands we use + +Setup: + +* `git config`: edit configuration options +* `git init -b main`: create new repository with `main` as the default branch + +See our status: + +* `git status`: see status of files - use often! +* `git log`: see history of commits and their messages, newest first +* `git graph`: see a detailed graph of commits. Create this command + with `git config --global alias.graph "log --all --graph --decorate --oneline"` +* `git diff`: show difference between working directory and last commit +* `git diff --staged`: show difference between staging area and last commit +* `git show COMMIT`: inspect individual commits + +General work: + +* `git add FILE`: + - Add a new file + - Add a file to staging +* `git commit`: record a version, add it to current branch +* `git commit --amend`: amend our last commit +* `git branch`: show which branch we're on +* `git branch NAME`: create a new branch called "name" +* `git restore FILE`: restore last committed/staged version of FILE, losing unstaged changes +* `git switch --create BRANCH-NAME`: create a new branch and switch to it +* `git revert HASH`: create a new commit which reverts commit HASH +* `git reset --soft HASH`: remove all commits after HASH, but keep their modifications as staged changes +* `git reset --hard HASH`: remove all commits after HASH, permanently throwing away their changes +* `git merge BRANCH-NAME`: merge branch BRANCH-NAME into current branch +* `git grep PATTERN`: search for patterns in tracked files +* `git annotate FILE`: find out when a specific line got introduced and by whom +* `git bisect`: find a commit which broke some functionality diff --git a/branch/main/_sources/resources.md.txt b/branch/main/_sources/resources.md.txt new file mode 100644 index 00000000..564f5247 --- /dev/null +++ b/branch/main/_sources/resources.md.txt @@ -0,0 +1,11 @@ +# Other resources + +- [Learn Git branching](http://pcottle.github.io/learnGitBranching/) +- [The entire Pro Git book, written by Scott Chacon and Ben Straub](http://git-scm.com/book) +- [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) +- [Commit Often, Perfect Later, Publish Once: Git Best Practices](http://sethrobertson.github.io/GitBestPractices/) +- [PeepCode Git Internals](https://github.com/pluralsight/git-internals-pdf/releases) +- [Git Workflows for Pros: A Good Git Guide](https://www.toptal.com/git/git-workflows-for-pros-a-good-git-guide) +- [Branch-per-Feature](http://dymitruk.com/blog/2012/02/05/branch-per-feature/) +- [Git on XKCD](http://xkcd.com/1597/) +- [An efficient GIT workflow for mid/long term projects](http://fle.github.io/an-efficient-git-workflow-for-midlong-term-projects.html) diff --git a/branch/main/_sources/sharing.md.txt b/branch/main/_sources/sharing.md.txt new file mode 100644 index 00000000..661e96d7 --- /dev/null +++ b/branch/main/_sources/sharing.md.txt @@ -0,0 +1,300 @@ +(sharing-repositories)= + +# How to turn your project to a Git repo and share it + +:::{objectives} +- Turn our own coding project (small or large, finished or unfinished) into a + Git repository. +- Be able to share a repository on the web to have a backup or so that others + can reuse and collaborate or even just find it. +::: + +:::{instructor-note} +- 10 min introduction and setup +- 25 min exercise +- 15 min discussion +::: + + +## Exercise + +:::::{exercise} Exercise: Turn your project to a Git repo and share it (25 min) + +1. Create a new directory called **myproject** with one or few files in it. + This represents our own project. It is not yet a Git repository. You can try + that with your own project or use a simple placeholder example. +2. Turn this new directory into a Git repository. +3. Share this repository on GitHub (or GitLab, since it really works the same). + +We offer **three different paths** of how to do this exercise. +* Via **GitHub web interface**: easy and can be a good starting point if you are completely + new to Git. +* **VS Code** is quite easy, since VS Code can offer to create the + GitHub repositories for you. +* **Command line**: you need to create the + repository on GitHub and link it yourself. + +::::{tabs} + +:::{group-tab} Only using GitHub +### Create an repository on GitHub + +First log into GitHub, then follow the screenshots and descriptions below. +```{figure} img/sharing/new-repository.png +:alt: Screenshot on GitHub before a new repository form is opened +:width: 60% +:class: with-border + +Click on the "plus" symbol on top right, then on "New repository". +``` + +Then: +```{figure} img/sharing/create-repository-with-readme.png +:alt: Screenshot on GitHub just before a new repository is created +:width: 100% +:class: with-border + +Choose a repository name, add a short description, and in this case **make sure to check** "Add a +README file". Finally "Create repository". +``` + + +### Upload your files + +Now that the repository is created, you can upload your files: +```{figure} img/sharing/upload-files.png +:alt: Screenshot on GitHub just before uploading files +:width: 100% +:class: with-border + +Click on the "+" symbol and then on "Upload files". +``` +::: + +:::{group-tab} VS Code +In VS Code it only takes few clicks. + +First, open the folder in VS Code. My example project here contains two files. +Then click on the source control icon: +```{figure} img/sharing/vscode-start.png +:alt: Screenshot of VS Code before clicking on the source control icon +:width: 100% +:class: with-border + +Open the folder in VS Code. Then click on the source control icon. +``` + +```{figure} img/sharing/vscode-publish-to-github1.png +:alt: Screenshot of VS Code before publishing to GitHub +:width: 100% +:class: with-border + +Choose "Publish to GitHub". In this case I never even clicked on "Initialize Repository". +``` + +```{figure} img/sharing/vscode-publish-to-github2.png +:alt: Screenshot of VS Code before publishing to GitHub +:width: 100% +:class: with-border + +In my case I chose to "Publish to GitHub public repository". Here you can also rename +the repository if needed. +``` + +```{figure} img/sharing/vscode-authorize.png +:alt: Screenshot of VS Code asking for authorization +:width: 50% +:class: with-border + +First time you do this you might need to authorize VS Code to access your +GitHub account by redirecting you to https://github.com/login/oauth/authorize. +``` + +```{figure} img/sharing/vscode-publish-to-github3.png +:alt: Screenshot of VS Code after publishing to GitHub +:width: 100% +:class: with-border + +After it is published, click on "Open on GitHub". +``` +::: + +:::{group-tab} Command line +### Make sure your Git is configured + +We have an own section on this: {ref}`configuration`. + + +### Put your project under version control + +My example project here consists of two files. Replace this with your own +example files: +```console +$ ls -l + +.rw------- 19k user 7 Mar 17:36 LICENSE +.rw------- 21 user 7 Mar 17:36 myscript.py +``` + +I will first initialize a Git repository in this directory. +If you get an error, try without the `-b main` (and your default branch will +then be called `master`, this will happen for Git versions older than +2.28): +```console +$ git init -b main +``` + +Now add and commit the two files to the Git repository: +```console +$ git add LICENSE myscript.py +$ git commit -m "putting my project under version control" +``` + +If you want to add all files in one go, you can use `git +add .` instead of `git add LICENSE myscript.py`. + +Now you have a Git repository with one commit. Verify this with `git log`. +But it's still only on your computer. Let's put it on GitHub next. + + +### Create an empty repository on GitHub + +First log into GitHub, then follow the screenshots and descriptions below. +```{figure} img/sharing/new-repository.png +:alt: Screenshot on GitHub before a new repository form is opened +:width: 60% +:class: with-border + +Click on the "plus" symbol on top right, then on "New repository". +``` + +Then create an empty repository without any files and without any commits: +```{figure} img/sharing/create-repository.png +:alt: Screenshot on GitHub just before a new repository is created +:width: 100% +:class: with-border + +Choose a repository name, add a short description, but please **do not check** "Add a +README file". For "Add .gitignore" and "Choose a license" also leave as "None". Finally "Create repository". +``` + +Once you click the green "Create repository", you will see a page similar to: +```{figure} img/sharing/bare-repository.png +:alt: Screenshot on GitHub after a bare repository was created +:width: 100% +:class: with-border +``` + +What this means is that we have now an empty project with either an HTTPS or an +SSH address: click on the HTTPS and SSH buttons to see what happens. + + +### Push an existing repository from your computer to GitHub + +We now want to follow the "**... or push an existing repository from the command line**": + +1. In your terminal make sure you are still in your myproject directory. +2. Copy paste the three lines below the red arrow to the terminal and execute + those, in my case (**you need to replace the "USER" part and possibly also + the repository name**): + +`````{tabs} + ````{group-tab} SSH + ```console + $ git remote add origin git@github.com:USER/myproject.git + ``` + ```` + ````{group-tab} HTTPS + ```console + $ git remote add origin https://github.com/USER/myproject.git + ``` + ```` +````` + +Then: +```console +$ git branch -M main +$ git push -u origin main +``` + +The meaning of the above lines: +- Add a remote reference with the name "origin" +- Rename current branch to "main" +- Push branch "main" to "origin" + +You should now see: + +```text +Enumerating objects: 4, done. +Counting objects: 100% (4/4), done. +Delta compression using up to 12 threads +Compressing objects: 100% (3/3), done. +Writing objects: 100% (4/4), 6.08 KiB | 6.08 MiB/s, done. +Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 +To github.com:USER/myproject.git + * [new branch] main -> main +branch 'main' set up to track 'origin/main'. +``` + +Reload your GitHub project website and your commits should now be +online! + + +### Troubleshooting + +**error: remote origin already exists** +- Explanation: You probably ran a `git remote add origin ...` command, then changed your + mind about HTTPS or SSH and then tried to run the other `git remote add + origin ...` command but "origin" then already exists. +- Recovery: + - First remove "origin" with `git remote remove origin` + - Then run the correct `git remote add origin ...` command + +**remote contains work that you do not have** +- Explanation: You probably clicked on "Add a README file" and now the + repository on GitHub is not empty but contains one commit and locally you + have a different history. Git now prevents you from accidentally overwriting + the history on GitHub. +- Recovery: + - Use `git push --force` instead of `git push`, which will force Git to overwrite the history on GitHub + - Note that this is a powerful but also possibly dangerous option but here it + helps us. If it's a brand new repo, it probably is fine to do this. For real + repositories, don't do this unless you are very sure what is happening. +::: + +:::: +::::: + + +## Remote repositories + +In this exercise we have pushed our local repository to a remote repository. +We will learn how to work with remote repositories in detail in the +[collaborative distributed version +control](https://coderefinery.github.io/git-collaborative/) lesson. To store +your git data on another server, you use **remotes**. A remote is a repository +on its own, with its own branches. We can **push** changes to the remote and +**pull** from the remote. + +You might use remotes to: +- Back up your own work or make your work findable. +- To collaborate with other people. + +There are different types of remotes: +- If you have a server you can SSH to, you can use that as a remote. +- [GitHub](https://github.com) is a popular, closed-source commercial site. +- [GitLab](https://about.gitlab.com) is a popular, open-core + commercial site. Many universities have their own private GitLab servers + set up. +- [Bitbucket](https://bitbucket.org) is yet another popular commercial site. +- Another option is [NotABug](https://notabug.org). +- There are more ... + + +## Is putting software on GitHub/GitLab/... publishing? + +It is a good first step but to make your code truly **findable and +accessible**, condider making your code **citable and persistent**: Get a +persistent identifier (PID) such as DOI in addition to sharing the code +publicly, by using services like [Zenodo](https://zenodo.org) or similar +services. diff --git a/branch/main/_sources/staging-area.md.txt b/branch/main/_sources/staging-area.md.txt new file mode 100644 index 00000000..94d0fe83 --- /dev/null +++ b/branch/main/_sources/staging-area.md.txt @@ -0,0 +1,330 @@ +# Using the Git staging area + +```{objectives} +- Learn how to tell a story with your commit history. +- Demystify the Git staging area. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 10 min exercise +``` + + +## Commit history is telling a story + +Your *current code* is very important, but the *history* can be just +as important - it tells a story about how your code came to be. + +- Each individual line of code rarely stands alone. +- You often want to see all the related changes together. +- But you also hardly ever do one thing at once. + +Along with your code, Git creates a *history* for you, and if your +history is clear then you are a long way to organized code. + +````{discussion} + Here are five types of history. What are the advantages and + disadvantages of each, when you look at it later? + + **Example 1**: + ```shell + b135ec8 add features A, B, and C + ``` + + **Example 2** (newest commit is on top): + ```shell + 6f0d49f implement feature C + fee1807 implement feature B + 6fe2f23 implement feature A + ``` + + **Example 3**: + ```shell + ab990f4 saving three months of miscellaneous work I forgot to commit + ``` + + **Example 4** (newest commit is on top): + ```shell + bf39f9d more work on feature B + 45831a5 removing debug prints for feature A and add new file + bddb280 more work on feature B and make feature A compile again + 72d78e7 feature A did not work and started work on feature B + b135ec8 now feature A should work + 72e0211 another fix to make it compile + 61dd3a3 forgot file and bugfix + 49dc419 wip (work in progress) + ``` + + **Example 5** (newest commit is on top): + ```shell + 1949dc4 Work of 2020-04-07 + a361dd3 Work of 2020-04-06 + 1172e02 Work of 2020-04-03 + e772d78 Work of 2020-04-02 + ``` + + Discuss these examples. Can you anticipate problems? +```` + +We want to have nice commits. But we also want to "save often" +(checkpointing) - how can we have both? + +- We will now learn to create nice commits using `git commit --patch` and/or the staging area. +- Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits. +- The staging area isn't the only way to organize your history nicely, some alternatives are discussed at the end of the lesson. + + +## Interactive commits + +- The simplest ways to solve this is to do **interactive commits**: + the `git commit --patch` option (or `git commit -p` for short). +- It will present you with every change you have made individually, + and you can decide which ones to commit right now. +- Reference and key commands + - `git commit --patch` to start the interactive commit + - `y` to use the change + - `n` to skip the change + - `s` (split) if there are several changes grouped together, but + separated by a blank line, split them into separate choices. + - `q` aborts everything. + - `?` for more options. +- The `-p` option is also available on `commit`, `restore`, `checkout`, `reset`, and `add`. + + +(exercise-interactive-commits)= + +## Exercise: Interactive commits + +````{exercise} Staging-1: Perform an interactive commit +One option to help us create nice logical commits is to stage *interactively* +with `git commit --patch`: + +1. Make two changes in `instructions.txt`, at the top and bottom + of the file. + **Make sure that they are separated by at least several unmodified lines.** +2. Run `git commit --patch`. Using the keystrokes above, commit one of + the changes. +3. Do it again for the other change. +4. When you're done, inspect the situation with `git log`, `git status`, `git diff` and `git diff --staged`. +5. When would this be useful? + + ```{solution} + This can be useful if you have several modification in a file (or several + files) but you decide that it would be beneficial to save them as two (or + more) separate commits. + ``` +```` + + +## The staging area + +- The interactive commits above are great, but what if there are so + many changes that you can't sort them out in one shot? +- What if you make progress and want to record it somehow, but it's + not ready to be committed? +- The **staging area** is a place to record things before committing. + +```{instructor-note} +We give two examples and the instructor can pick one or both: +- Analogy using moving boxes +- Analogy using shopping receipts +``` + +```{discussion} + **Analogy using moving boxes** + + - You're moving and you have a box to pack your things in. + - You can put stuff into the box, but you can also take stuff out of the box. + - You wouldn't want to mix items from the bathroom, kitchen, and living room + into the same box. + - The box corresponds to the staging area of Git, where you can craft your commits. + - Committing is like sealing the box and sticking a label on it. + - You wouldn't want to label your box with "stuff", but rather give a more + descriptive label. + - See also + + + **Analogy using shopping receipts** + + - You need to go shopping and buy some stuff for work and for home. + You need two separate receipts. + - Bad idea: go through the store get home stuff, pay, start at the + beginning and go through the store again. This is inefficient and + annoying. + - What you actually do: + - Go through the store and put everything you need in your shopping + basket. + - Get to the check-out. Put your home stuff on the conveyor belt + (`git add`). Check both the belt (`git diff --staged`) and your + basket (`git diff`) to make sure you got all your home stuff. + - Pay (`git commit`) + - Repeat for work stuff. + + In order to keep organized, you have to use multiple locations to + stage things in sequence. +``` + + +## Staging area commands + +The staging area is a middle ground between what you have done to your files +(the **working directory**) and what you have last committed (the **HEAD commit**). +Just like the name implies, it lets you prepare (**stage**) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since **you can modify and stage several times before committing**. + +**git add** stages/prepares for the next commit: +```text + git add + [project*] <------------ project* + ^ + | modify with editor + | + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git commit** creates a new commit: +```text + + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + HEAD~2 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +**git reset \\--soft HEAD~1** (move HEAD back by one but keep changes and stage +them) would do the opposite of **git commit**. (in this case, `HEAD` +is literally this - not a replacement) + +Going back to the last staged version: +```text + git restore + [project*] ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Unstaging changes with **git restore \\--staged**: +```text + git restore --staged + ------------> project* + + + + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Discarding unstaged changes: +```text + + project* + | + | git restore + v + HEAD . project + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +Comparing: +```text + git diff + [project*] <-----------> project* + ^ ^ + | git diff --staged | git diff HEAD + v v + HEAD . + | . + | . + | . + HEAD~1 . + | . + | . + | . + . + .git . working directory +(history) . (files we see) +``` + +```{figure} img/staging-basics.svg +:alt: Staging basics +:width: 100% + +The different states of the repository and the commands to move from one to +another. +``` + +(exercise-staging-area)= + +## Exercise: Using the staging area + +```{exercise} Staging-2: Use the staging area to make a commit in two steps +1. In your recipe example, make two different changes to + `ingredients.txt` and `instructions.txt` which do not go together. +2. Use `git add` to stage one of the changes. +3. Use `git status` to see what's going on, and use `git diff` and `git diff --staged` to see the changes. +4. Feel some regret and unstage the staged change. +``` + +```{discussion} +- When is it better to "save" a change as commit, when is it better to "save" + it with `git add`? +- Is it a problem to commit many small changes? +``` + +```{keypoints} +- The staging area helps us to create well-defined commits. +``` diff --git a/branch/main/_sources/under-the-hood.md.txt b/branch/main/_sources/under-the-hood.md.txt new file mode 100644 index 00000000..977968da --- /dev/null +++ b/branch/main/_sources/under-the-hood.md.txt @@ -0,0 +1,185 @@ +# Git under the hood + +```{objectives} +- Verify that branches are pointers to commits and extremely lightweight. +``` + +```{instructor-note} +- 10 min teaching/type-along +- 15 min exercise +``` + +```{figure} img/stranger.jpg +:alt: Git under the hood +:width: 100% +``` + + +## Down the rabbit hole + +When working with Git, **you will never need to go inside .git**, but in this +exercise we will, in order to learn about how branches are implemented in Git. + +For this exercise create a new repository and commit a couple of changes. + +Now that we've made a couple of commits let us look at what is happening under +the hood. + +```console +$ cd .git +$ ls -l + +drwxr-xr-x - user 25 Aug 15:51 branches +.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG +.rw-r--r-- 92 user 25 Aug 15:51 config +.rw-r--r-- 73 user 25 Aug 15:51 description +.rw-r--r-- 21 user 25 Aug 15:51 HEAD +drwxr-xr-x - user 25 Aug 15:51 hooks +.rw-r--r-- 137 user 25 Aug 15:52 index +drwxr-xr-x - user 25 Aug 15:51 info +drwxr-xr-x - user 25 Aug 15:52 logs +drwxr-xr-x - user 25 Aug 15:52 objects +drwxr-xr-x - user 25 Aug 15:51 refs +``` + +Git stores everything under the .git folder in your repository. In fact, **the +.git directory is the Git repository.** + +Previously when you wrote the commit messages using your text editor, they +were in fact saved to `COMMIT_EDITMSG`. + +Each commit in Git is stored as a "blob". This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file. + +Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string). + +```{figure} img/commit-and-tree.png +:alt: A commit inside Git +:width: 100% + +States of a Git file. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a [directed acyclic +graph](http://eagain.net/articles/git-for-computer-scientists/) (do not worry +if the term is not familiar). + +```{figure} img/commits-and-parents.png +:alt: A commit and its parents +:width: 100% + +A commit and its parents. Image from the [Pro Git book](https://git-scm.com/book/). License CC BY 3.0. +``` + +All branches and tags in Git are pointers to commits. + + +## Git is basically a content-addressed storage system + +- CAS: ["mechanism for storing information that can be retrieved based on its content, not its storage location"](https://en.wikipedia.org/wiki/Content-addressable_storage) +- Content address is the content digest (SHA-1 checksum) +- Stored data does not change - so when we modify commits, we always create new + commits. Git doesn't delete these right away, which is why it is *very hard + to lose data if you commit it once*. + +Let us poke a bit into raw objects! Start with: + +```console +$ git cat-file -p HEAD +``` + +Then explore the `tree` object, then the `file` object, etc. recursively using the hashes you see. + + +## Demonstration: experimenting with branches + +Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an "Aha!" moment and provide us a +good understanding of the underlying model. + +We are starting from the `main` branch and create an `idea` branch: + +```console +$ git status + +On branch main +nothing to commit, working tree clean +``` + +```console +$ git switch --create idea + +Switched to a new branch 'idea' +``` + +```console +$ git branch + +* idea + main +``` + +Now let us go in: + +```console +$ cd .git +$ cd refs/heads +$ ls -l + +.rw-r--r-- 41 user 25 Aug 15:54 idea +.rw-r--r-- 41 user 25 Aug 15:52 main +``` + +Let us check what the `idea` file looks like +(do not worry if the hash is different): +```console +$ cat idea + +045e3db14740c60684d745e5fb891ae71e335611 +``` + +Now let us replicate this file: +```console +$ cp idea idea-2 +$ cp idea idea-3 +$ cp idea idea-4 +$ cp idea idea-5 +``` + +Let us go up two levels and inspect the file `HEAD`: +```console +$ cd ../.. +$ cat HEAD + +ref: refs/heads/idea +``` + +Let us open this file and change it to: +``` +ref: refs/heads/idea-3 +``` + +**Now we are ready for the aha moment!** +First let us go back to the working area: +```console +$ cd .. +``` + +Now - on which branch are we? +```console +$ git branch + + idea + idea-2 +* idea-3 + idea-4 + idea-5 + main +``` + +```{discussion} +Discuss the findings with other course participants. +``` diff --git a/branch/main/_sources/what-to-avoid.md.txt b/branch/main/_sources/what-to-avoid.md.txt new file mode 100644 index 00000000..ed76c118 --- /dev/null +++ b/branch/main/_sources/what-to-avoid.md.txt @@ -0,0 +1,62 @@ +# What to avoid + +The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas. + +**Postponing commits because the changes are "unfinished"/"ugly"**: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all. + +**Not updating your branch before starting new work**: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later. +So update your branch before adding new commits. + +**Commit unrelated changes together**: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects. + +**Too ambitious branch which risks to never get completed**: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere. + +**Committing generated files**: Compiled and generated files are not +committed to version control. There are many reasons for this: + +- These files can make it more difficult to run on different platforms. +- These files are automatically generated and thus do not contribute in any meaningful way. +- When tracking generated files you could see differences in the code although you haven't touched the code. + +For this we use [.gitignore files](https://git-scm.com/docs/gitignore) where +you can list which files and paths should be ignored by Git. You can also use +wild-cards to ignore files with a certain extension or files in a certain +directory. + +**Over-engineering the branch layout and safeguards in small projects**: This +may prevent people from contributing (maybe even including yourself?). Add more +restrictions and safeguards only as the project and the group of collaborators +grows. + +**Commit messages that explain what has been changed but do not explain why it has been +changed**: This is as useful as code comments which describe the "obvious" such +as "this is a loop" instead of explaining why something is done this way. +But don't let perfect commit messages stop you from the most important point, committing often (first point). + +**Commit huge files**: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent `git rm` does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request. + +:::{discussion} +Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements. +::: diff --git a/branch/main/_static/_sphinx_javascript_frameworks_compat.js b/branch/main/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/branch/main/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/branch/main/_static/basic.css b/branch/main/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/branch/main/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/branch/main/_static/check-solid.svg b/branch/main/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/branch/main/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/main/_static/clipboard.min.js b/branch/main/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/branch/main/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/branch/main/_static/copybutton.css b/branch/main/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/branch/main/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/branch/main/_static/copybutton.js b/branch/main/_static/copybutton.js new file mode 100644 index 00000000..f3ecd034 --- /dev/null +++ b/branch/main/_static/copybutton.js @@ -0,0 +1,241 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos, .gp'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/branch/main/_static/copybutton_funcs.js b/branch/main/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/branch/main/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/branch/main/_static/css/badge_only.css b/branch/main/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/branch/main/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/branch/main/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.eot b/branch/main/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.svg b/branch/main/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/branch/main/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.ttf b/branch/main/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.woff b/branch/main/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/branch/main/_static/css/fonts/fontawesome-webfont.woff2 b/branch/main/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/branch/main/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-bold-italic.woff b/branch/main/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold-italic.woff differ diff --git a/branch/main/_static/css/fonts/lato-bold-italic.woff2 b/branch/main/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-bold.woff b/branch/main/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold.woff differ diff --git a/branch/main/_static/css/fonts/lato-bold.woff2 b/branch/main/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-bold.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-normal-italic.woff b/branch/main/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal-italic.woff differ diff --git a/branch/main/_static/css/fonts/lato-normal-italic.woff2 b/branch/main/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/branch/main/_static/css/fonts/lato-normal.woff b/branch/main/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal.woff differ diff --git a/branch/main/_static/css/fonts/lato-normal.woff2 b/branch/main/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/branch/main/_static/css/fonts/lato-normal.woff2 differ diff --git a/branch/main/_static/css/theme.css b/branch/main/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/branch/main/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/branch/main/_static/doctools.js b/branch/main/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/branch/main/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/branch/main/_static/documentation_options.js b/branch/main/_static/documentation_options.js new file mode 100644 index 00000000..87fc516a --- /dev/null +++ b/branch/main/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/branch/main/_static/file.png b/branch/main/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/branch/main/_static/file.png differ diff --git a/branch/main/_static/jquery.js b/branch/main/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/branch/main/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/main/_static/js/html5shiv.min.js b/branch/main/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/branch/main/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/main/_static/js/theme.js b/branch/main/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/branch/main/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/branch/main/_static/minipres.js b/branch/main/_static/minipres.js new file mode 100644 index 00000000..ad11c871 --- /dev/null +++ b/branch/main/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/branch/main/_static/minus.png b/branch/main/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/branch/main/_static/minus.png differ diff --git a/branch/main/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/branch/main/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 00000000..33566310 --- /dev/null +++ b/branch/main/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/branch/main/_static/plus.png b/branch/main/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/branch/main/_static/plus.png differ diff --git a/branch/main/_static/pygments.css b/branch/main/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/branch/main/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/branch/main/_static/searchtools.js b/branch/main/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/branch/main/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/branch/main/_static/sphinx_highlight.js b/branch/main/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/branch/main/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/branch/main/_static/sphinx_lesson.css b/branch/main/_static/sphinx_lesson.css new file mode 100644 index 00000000..14b20c64 --- /dev/null +++ b/branch/main/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/branch/main/_static/sphinx_rtd_theme_ext_color_contrast.css b/branch/main/_static/sphinx_rtd_theme_ext_color_contrast.css new file mode 100644 index 00000000..e68feb82 --- /dev/null +++ b/branch/main/_static/sphinx_rtd_theme_ext_color_contrast.css @@ -0,0 +1,47 @@ +/* The following are for web accessibility of sphinx_rtd_theme: they + * solve some of the most frequent contrast issues. Remove when this + * solved: + * https://github.com/readthedocs/sphinx_rtd_theme/issues/971 + */ +/* background: #fcfcfc, note boxes #E7F2FA */ +a { color: #2573A7; } /* original #2980B9, #1F5C84; */ +body { color: #242424; } /* original #404040, #383838 */ +.wy-side-nav-search>a, .wy-side-nav-search .wy-dropdown>a { + color: #ffffff; +} /* original #fcfcfc */ +footer { color: #737373; } /* original gray=#808080*/ +footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { + color: #737373; +} /* original gray=#808080*/ +.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { + color: #AB2314; +} +/* Sidebar background */ +.wy-side-nav-search { background-color: #277CB4;} + +/* Same, but for pygments */ +.highlight .ch { color: #3E7A89; } /* #! line */ +.highlight .c1 { color: #3E7A89; } /* also comments */ +.highlight .nv { color: #AD3ECC; } /* variable */ +.highlight .gp { color: #B45608; } /* prompt character, $*/ +.highlight .si { color: #3975B1; } /* ${} variable text */ +.highlight .nc { color: #0C78A7; } + +/* Sphinx admonitions */ +/* warning */ +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { + background: #B15E16; } +/* important */ +.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { + background: #12826C; } +/* seealso, note, etc */ +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { + background: #277CB4; } +/* error, danger */ +.rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { + background: #e31704; +} + +/* Generic admonition titles */ +.wy-alert-title, .rst-content .admonition-title { + background: #277CB4; } diff --git a/branch/main/_static/tabs.css b/branch/main/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/branch/main/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/branch/main/_static/tabs.js b/branch/main/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/branch/main/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/branch/main/_static/term_role_formatting.css b/branch/main/_static/term_role_formatting.css new file mode 100644 index 00000000..0b66095c --- /dev/null +++ b/branch/main/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/branch/main/_static/togglebutton.css b/branch/main/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/branch/main/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/branch/main/_static/togglebutton.js b/branch/main/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/branch/main/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/branch/main/aliases/index.html b/branch/main/aliases/index.html new file mode 100644 index 00000000..6213cc4b --- /dev/null +++ b/branch/main/aliases/index.html @@ -0,0 +1,337 @@ + + + + + + + Aliases and configuration — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Aliases and configuration

+
+

Objectives

+
    +
  • Learn to use aliases for most common commands.

  • +
+
+

Are you getting tired of typing so much? In Git you can define aliases (shortcuts):

+
    +
  • These are great because they can save you time typing.

  • +
  • But it’s easy to forget them, get confused, or be inconsistent with your colleagues.

  • +
+

There is plenty of other configuration for Git, that can make it nicer.

+
+

Aliases

+
    +
  • Aliases offer a way to improve the usability of Git: for +example git ci instead of git commit.

  • +
  • Aliases are based on simple string replacement in the command.

  • +
  • Aliases can either be specific to a repository or global.

    +
      +
    • Global aliases help you do the things you are used to across Git projects.

    • +
    • Per-project aliases can also be created.

    • +
    +
  • +
  • Global aliases are stored in ~/.gitconfig.

  • +
+
+
+

Example alias: git graph

+

A very useful shortcut which we use a lot in our workshops:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ cd your_git_repository
+$ git graph
+
+
+
+
+

Using external commands

+

It is possible to call external commands using the exclamation mark character “!”. +In this example here we create a local alias which is +stored in .git/config and not synchronized with remotes:

+
$ cd your_git_repository
+$ git config alias.hi '!echo hello'
+$ git hi
+
+
+
+

Food for thought: When to alias?

+
    +
  • How many times should you wait before aliasing a command?

  • +
  • Do you believe a list of generic two-letter acronyms for common commands will +save your time?

  • +
+
+
+
+

List of aliases the instructors use

+

You are welcome to reuse, suggest, improve. +You can see your current aliases in ~/.gitconfig.

+
$ git config --global alias.ap "add --patch"
+$ git config --global alias.br branch
+$ git config --global alias.ci "commit -v"
+$ git config --global alias.cip "commit --patch -v"
+$ git config --global alias.cl "clone --recursive"
+$ git config --global alias.di diff
+$ git config --global alias.dic "diff --staged --color-words"
+$ git config --global alias.diw "diff --color-words"
+$ git config --global alias.dis "!git --no-pager diff --stat"
+$ git config --global alias.fe fetch
+$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ git config --global alias.rem remote
+$ git config --global alias.st status
+$ git config --global alias.su "submodule update --init --recursive"
+
+
+

Here is what they do:

+
    +
  • ap: add, selecting parts individually, interactively.

  • +
  • br: branch (obvious)

  • +
  • ci: commit (check in), with -v option for clarity

  • +
  • cip: commit, selecting parts individually, interactively.

  • +
  • cl: clone, init submodules (submodules are an advanced topic)

  • +
  • di: diff (obvious)

  • +
  • dic: diff of staging area vs last commit (what is about to be committed)

  • +
  • diw: a word diff, color. Useful for small changes.

  • +
  • dis: a “diffstat”: what files are changed, not contents

  • +
  • fe: fetch (obvious)

  • +
  • graph: show whole git graph (so useful, some of us call it l)

  • +
  • rem: remote (obvious)

  • +
  • st: status (obvious)

  • +
  • su: submodule update (advanced)

  • +
+

A useful setting for the p aliases:

+
$ git config --global interactive.singlekey true
+
+
+
+
+

Advanced aliases

+

These are advanced aliases and configuration options. We won’t explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages!

+
$ git config --global alias.cif "commit -v -p --fixup"
+$ git config --global alias.rb "rebase --autosquash"
+$ git config --global alias.rbi "rebase --interactive --autosquash"
+$ git config --global alias.rbis "rebase --interactive --autosquash --autostash"
+$ git config --global alias.rbs "rebase --autosquash --autostash"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard"
+$ git config --global alias.new "log HEAD..HEAD@{upstream}"
+$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}"
+$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}"
+$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all"
+$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD"
+$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat"
+
+
+
+
+

Advanced Git configuration

+

Besides aliases, you can do plenty of other configuration of git. +Here are some of the most common ones:

+
$ git config --global interactive.singlekey true
+$ git config --global core.pager "less -RS"
+$ git config --global core.excludesfile ~/.gitignore
+$ git config --global merge.conflictstyle diff3
+$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]"
+$ git config --global diff.mnemonicPrefix true
+
+
+

Do you get tired of typing and copying and pasting your remote names +all the time, like git@github.com:myusername? You can create remote +aliases like this:

+
$ git config --global url.git@github.com:.insteadOf gh:
+$ git config --global url.git@github.com:/username/.insteadOf ghu:
+
+
+

Then, when you add a remote ghu:recipe, it will automatically be +translated to git@github.com:/username/recipe using a simple prefix +matching.

+
+

Keypoints

+
    +
  • If you are frustrated about remembering a command, you should create an alias.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/archaeology/index.html b/branch/main/archaeology/index.html new file mode 100644 index 00000000..1855a63a --- /dev/null +++ b/branch/main/archaeology/index.html @@ -0,0 +1,595 @@ + + + + + + + Inspecting history — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Inspecting history

+
+

Objectives

+
    +
  • Be able find a line of code, find out why it was introduced and when.

  • +
  • Be able to quickly find the commit that changed a behavior.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Command line, GitHub, and VS Code

+

As usual, we offer ways to do this with the command line, VS Code, and +GitHub.

+
    +
  • Command line is most powerful and relatively easy with this. +You may also use it along with other things. If you haven’t tried +it yet, we’d recommend you to give it a try.

  • +
  • The GitHub web interface allows many things to be done, but not +everything.

  • +
  • VS Code allows some of these, but for some it’s easier to open +the VS Code terminal and run git there.

  • +
+
+
+

Our toolbox for history inspection

+
+

Instructor note

+

First the instructor demonstrates few commands on a real life example +repository https://github.com/networkx/networkx (mentioned in the amazing site The +Programming Historian). +Later we will practice these in an archaeology exercise (below).

+
+
+

Warm-up: “Git History” browser

+

As a warm-up we can try the “Git History” browser +on the README.rst file of the networkx repository:

+ +
+
+

Searching text patterns in the repository

+

With git grep you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or +some error message printed.

+
+

The Git command is as described above:

+
$ git grep TEXT
+$ git grep "some text with spaces"
+
+
+

In the networkx repository you can try:

+
$ git clone https://github.com/networkx/networkx
+$ cd networkx
+$ git grep -i fixme
+
+
+

While git grep searches the current state of the repository, +it is also possible to search through all changes with git log -S sometext +which can be useful to find where something got removed.

+
+
+
+

Inspecting individual commits

+
+

We have seen this one before already. Using git show we can inspect an individual commit if +we know its hash:

+
$ git show HASH
+
+
+

For instance:

+
$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7
+
+
+
+
+
+

Line-by-line code annotation with metadata

+

With git annotate you can see line by line who and when the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility.

+
+
$ git annotate FILE
+
+
+

Example:

+
$ git annotate networkx/convert_matrix.py
+
+
+

If you annotate in a terminal and the file is longer than the screen, Git by default uses the program less to +scroll the output. +Use /sometext <ENTER> to find “sometext” and you can cycle through the results with n (next) and N (last). +You can also use page up/down to scroll. You can quit with q.

+
+
+

Discussion

+

Discuss how these relatively trivial changes affect the annotation:

+
    +
  • Wrapping long lines of text/code into shorter lines

  • +
  • Auto-formatting tools such as black

  • +
  • Editors that automatically remove trailing whitespace

  • +
+
+
+
+

Inspecting code in the past

+
+

We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code:

+
$ git switch --create BRANCHNAME HASH
+
+
+

Example (lines starting with “#” are only comments):

+
$ # create branch called "older-code" from hash 347e6292419b
+$ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9
+
+$ # now you can navigate and inspect the code as it was back then
+$ # ...
+
+$ # after we are done we can switch back to "main"
+$ git switch main
+
+$ # if we like we can delete the "older-code" branch
+$ git branch -d older-code
+
+
+

On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

+
$ git checkout -b BRANCHNAME SOMEHASH
+
+
+
+
+
+
+

Exercise

+

This is described with the command line method, but by looking above +you can translate to the other options.

+
+

Exercise: Explore basic archaeology commands (20 min)

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Make sure you are not inside another Git repository when running this +exercise. If you are, first step “outside” of it. +We want to avoid creating a Git repository inside another Git repository.

    +
    +

    You can check if you are inside a Git repository with:

    +
    $ git status
    +
    +fatal: not a git repository (or any of the parent directories): .git
    +
    +
    +

    You want to see the above message which tells us that this is not a Git repository.

    +
    +
  • +
  • Clone this repository: +https://github.com/networkx/networkx.git.

    +
    +
    $ git clone https://github.com/networkx/networkx.git
    +
    +
    +
    +
  • +
  • Then let us all make sure we are working on a well-defined version of the repository.

    +
    +

    Step into the new directory and create an exercise branch from the +networkx-2.6.3 tag/release:

    +
    $ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+
+
+
+

Finding out when something broke/changed with git bisect

+

This only works with the command line.

+
+

“But I am sure it used to work! Strange.”

+
+

Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke.

+
+

How would you solve this?

+

Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now.

+
    +
  • How would you find the commit which changed it?

  • +
  • Why could it be useful to know the commit that changed it?

  • +
+
+

We will probably arrive at a solution which is similar to git bisect:

+
    +
  • First find out a commit in past when it worked.

    +
    $ git bisect start
    +$ git bisect good f0ea950  # this is a commit that worked
    +$ git bisect bad main      # last commit is broken
    +
    +
    +
  • +
  • Now compile and/or run and/or test and decide whether “good” or “bad”.

  • +
  • This is how you can tell Git that this was a working commit:

    +
    $ git bisect good
    +
    +
    +
  • +
  • And this is how you can tell Git that this was not a working commit:

    +
    $ git bisect bad
    +
    +
    +
  • +
  • Then bisect/iterate your way until you find the commit that broke it.

  • +
  • If you want to go back to start, type git bisect reset.

  • +
  • This can even be automatized with git bisect run SCRIPT. +For this you write a script that returns zero/non-zero (success/failure).

  • +
+
+
+

Optional exercise: Git bisect

+

This only works with the command line.

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+
+

Summary

+
    +
  • git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project on the command line.

  • +
  • git switch --create NAME HASH is the recommended mechanism to inspect old code on the command line.

  • +
  • Most of these commands can be used in the GitHub web interface (except git bisect).

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/basics/index.html b/branch/main/basics/index.html new file mode 100644 index 00000000..e0659e5e --- /dev/null +++ b/branch/main/basics/index.html @@ -0,0 +1,837 @@ + + + + + + + Basics — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Basics

+
+

Objectives

+
    +
  • Learn to create Git repositories and make commits.

  • +
  • Get a grasp of the structure of a repository.

  • +
  • Learn how to inspect the project history.

  • +
  • Learn how to write useful commit log messages.

  • +
+
+
+

Instructor note

+
    +
  • 35 min teaching/type-along

  • +
  • 40 min exercise

  • +
+
+
+

What is Git, and what is a Git repository?

+
    +
  • Git is a version control system: can record/save snapshots and track the content of a folder as it changes over time.

  • +
  • Every time we commit a snapshot, Git records a snapshot of the entire project, saves it, and assigns it a version.

  • +
  • These snapshots are kept inside a sub-folder called .git.

  • +
  • If we remove .git, we remove the repository and history (but keep the working directory!).

  • +
  • The directory .git uses relative paths - you can move the whole repository somewhere else and it will still work.

  • +
  • Git doesn’t do anything unless you ask it to (it does not record anything automatically).

  • +
  • Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces).

  • +
+
+
+

Recording a snapshot with Git

+
    +
  • Git takes snapshots only if we request it.

  • +
  • We will record changes in two steps (we will later explain why this is a recommended practice).

  • +
  • Example (we don’t need to type yet):

    +
    $ git add FILE.txt
    +$ git commit
    +
    +$ git add FILE.txt ANOTHERFILE.txt
    +$ git commit
    +
    +
    +
  • +
  • We first focus (git add, we “stage” the change), then record (git commit):

  • +
+
+Git staging +
+

Git staging and committing.

+
+
+
+

Question for the more advanced participants

+

What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end.

+
+
+
+

Configuring Git command line

+

Before we start using Git on the command line, we need to configure Git. +This is also part of the +installation instructions +but we need to make sure we all have +set name, email address, editor, and +default branch:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+$ git config --global core.editor nano
+$ git config --global init.defaultBranch main
+
+
+

Verify with:

+
$ git config --list
+
+
+
+

Instructor note

+

Instructors, give learners enough time to do the above configuration steps.

+
+
+
+

Type-along: Tracking a guacamole recipe with Git

+

We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list)

+

The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language.

+
+

Instructor note

+

Instructors, please encourage now that participants type along.

+
+
+

Note

+

It is possible to go through this lesson in the command line or in the browser +(on GitHub).

+
    +
  • We recommend to start with the command line but later to also try in the browser.

  • +
  • If you get really stuck in the command line, try following in the browser and +later you can try to return to the command line.

  • +
+
+
+
+

Creating a repository

+

One of the basic principles of Git is that it is easy to create repositories:

+
+
$ mkdir recipe
+$ cd recipe
+$ git init -b main
+
+
+

That’s it! With git init -b main have now created an empty Git repository +where main is the default branch (more about branches later).

+

We will use git status a lot to check out what is going on:

+
$ git status
+
+On branch main
+
+No commits yet
+
+nothing to commit (create/copy files and use "git add" to track)
+
+
+

We will make sense of this information during this workshop.

+
+
+
+

Adding files and committing changes

+

Let us now create two files.

+

One file is called ingredients.txt and contains:

+
* 2 avocados
+* 1 chili
+* 1 lime
+* 2 tsp salt
+
+
+

The second file is called instructions.txt and contains:

+
* chop avocados
+* chop onion
+* chop chili
+* squeeze lime
+* add salt
+* and mix well
+
+
+
+

As mentioned above, in Git you can always check the status of files in your repository using +git status. It is always a safe command to run and in general a good idea to +do when you are trying to figure out what to do next:

+
$ git status
+
+On branch main
+
+No commits yet
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    ingredients.txt
+    instructions.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+
+

The two files are untracked in the repository (directory). You want to add the files (focus the camera) +to the list of files tracked by Git. Git does not track +any files automatically and you need make a conscious decision to add a file. Let’s do what +Git hints at, and add the files, one by one:

+
$ git add ingredients.txt
+$ git status
+
+On branch main
+
+No commits yet
+
+Changes to be committed:
+  (use "git rm --cached <file>..." to unstage)
+    new file:   ingredients.txt
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    instructions.txt
+
+
+

Now this change is staged and ready to be committed. +Let us now commit the change to the repository:

+
$ git commit -m "adding ingredients"
+
+[main (root-commit) f146d25] adding ingredients
+ 1 file changed, 4 insertions(+)
+ create mode 100644 ingredients.txt
+
+
+

Right after we query the status to get this useful command into our muscle memory:

+
$ git status
+
+
+

Now stage and commit also the other file:

+
$ git add instructions.txt
+$ git commit -m "adding instructions"
+
+
+

We will add a third file to the repository, README.md, containing:

+
# recipe
+
+This is an exercise repository.
+
+
+

Now stage and commit also the README.md file:

+
$ git add README.md
+$ git commit -m "adding README"
+
+
+

What does the -m flag mean? Let us check the help page for that command:

+
$ git help commit
+
+
+

You should see a very long help page as the tool is very versatile (press q to quit). +Do not worry about this now but keep in mind that you can always read the help files +when in doubt. Searching online can also be useful, but choosing search terms +to find relevant information takes some practice and discussions in some +online threads may be confusing. +Note that help pages also work when you don’t have a network connection!

+
+
+
+

Exercise: Record changes

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+
+
+

Git history and log

+
+

If you haven’t yet, please try now git log:

+
$ git log
+
+commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main)
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:47 2023 +0200
+
+    don't forget to enjoy
+
+commit 79161b6e67c62ad4688a58c1e54183334611a390
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:32 2023 +0200
+
+    add half an onion
+
+commit a3394e39535343c4dae3bb4f703741a31aa8b78a
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:47:14 2023 +0200
+
+    adding README
+
+commit 369624674e63de48055a65bf63055bd59c985d22
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:46:58 2023 +0200
+
+    adding instructions
+
+commit f146d25b94569a15e94d7f0da6f15d7554f76c49
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:35:52 2023 +0200
+
+    adding ingredients
+
+
+
+
    +
  • We can browse the development and access each state that we have committed.

  • +
  • The long hashes uniquely label a state of the code.

  • +
  • They are not just integers counting 1, 2, 3, 4, … (why?).

  • +
  • Output is in reverse chronological order, i.e. newest commits on top.

  • +
  • We will use them when comparing versions and when going back in time.

  • +
  • git log --oneline only shows the first 7 characters of the commit hash and is good to get an overview.

  • +
  • If the first characters of the hash are unique it is not necessary to type the entire hash.

  • +
  • git log --stat is nice to show which files have been modified.

  • +
+
+
+

Optional exercises: Comparing changes

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+
+
+

Writing useful commit messages

+

Using git log --oneline or browsing a repository on the web, we better +understand that the first line of the commit message is very important.

+

Good example:

+
increase threshold alpha to 2.0
+
+the motivation for this change is
+to enable ...
+...
+this is based on a discussion in #123
+
+
+

Convention: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

Ignoring files and paths with .gitignore

+
+

Discussion

+
    +
  • Should we add and track all files in a project?

  • +
  • How about generated files?

  • +
  • Why is it considered a bad idea to commit compiled binaries to version control?

  • +
  • What types of generated files do you know?

  • +
+
+

Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files. Example:

+
# ignore compiled python 2 files
+*.pyc
+# ignore compiled python 3 files
+__pycache__
+
+
+

An example taken from the official Git documentation:

+
# ignore objects and archives, anywhere in the tree.
+*.[oa]
+# ignore generated html files,
+*.html
+# except foo.html which is maintained by hand
+!foo.html
+# ignore everything under build directory
+build/
+
+
+
    +
  • .gitignore should be part of the repository because we want to make sure that all developers see the same behavior.

  • +
  • All files should be either tracked or ignored.

  • +
  • .gitignore uses something called a +shell glob syntax for +determining file patterns to ignore. You can read more about the syntax in the +documentation.

  • +
  • You can have .gitignore files in lower level directories and they affect the paths below.

  • +
+
+
+

Graphical user interfaces

+

We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI):

+ +
+
+

Summary

+

Now we know how to save snapshots:

+
$ git add FILE(S)
+$ git commit
+
+
+

And this is what we do as we program.

+

Every state is then saved and later we will learn how to go back to these “checkpoints” +and how to undo things.

+
$ git init -b main  # initialize new repository (main is default branch)
+$ git add           # add files or stage file(s)
+$ git commit        # commit staged file(s)
+$ git status        # see what is going on
+$ git log           # see history
+$ git diff          # show unstaged/uncommitted modifications
+$ git show          # show the change for a specific commit
+$ git mv            # move/rename tracked files
+$ git rm            # remove tracked files
+
+
+

Git is not ideal for large binary files +(for this consider git-annex).

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • It takes only one command to initialize a Git repository: git init -b main.

  • +
  • Commits should be used to tell a story.

  • +
  • Git uses the .git folder to store the snapshots.

  • +
  • Don’t be afraid to stage and commit often. Better too often than not often enough.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/branches/index.html b/branch/main/branches/index.html new file mode 100644 index 00000000..1d6d27f6 --- /dev/null +++ b/branch/main/branches/index.html @@ -0,0 +1,758 @@ + + + + + + + Branching and merging — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Branching and merging

+
+

Objectives

+
    +
  • Be able to create and merge branches.

  • +
  • Know the difference between a branch and a tag.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Motivation for branches

+

In the previous section we tracked a guacamole recipe with Git.

+

Up until now our repository had only one branch with one commit coming +after the other:

+
+Linear Git repository +
+

Linear Git repository.

+
+
+
    +
  • Commits are depicted here as little boxes with abbreviated hashes.

  • +
  • Here the branch main points to a commit.

  • +
  • “HEAD” is the current position (remember the recording head of tape +recorders?). When we say HEAD, we mean those literal letters - +this isn’t a placeholder for something else.

  • +
  • When we talk about branches, we often mean all parent commits, not only the commit pointed to.

  • +
+

Now we want to do this:

+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+

Software development is often not linear:

+
    +
  • We typically need at least one version of the code to “work” (to compile, to give expected results, …).

  • +
  • At the same time we work on new features, often several features concurrently. +Often they are unfinished.

  • +
  • We need to be able to separate different lines of work really well.

  • +
+

The strength of version control is that it permits the researcher to isolate +different tracks of work, which can later be merged to create a composite +version that contains all changes:

+
+Isolated tracks of work +
+

Isolated tracks of work.

+
+
+
    +
  • We see branching points and merging points.

  • +
  • Main line development is often called main or master.

  • +
  • Other than this convention there is nothing special about main or master, it is a branch like any other.

  • +
  • Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow).

  • +
+

A group of commits that create a single narrative are called a branch. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. “fast sequence extraction” or “Python interface” or “fixing bug in +matrix inversion algorithm”.

+
+

An important alias

+

We will now define an alias in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). This is extensively used in the rest of this +and other lessons:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+
+
+

Instructor note

+

Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative.

+
+

Let us inspect the project history using the git graph alias:

+
$ git graph
+
+* e7cf023 (HEAD -> main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • We have a couple commits and only +one development line (branch) and this branch is called main.

  • +
  • Commits are states characterized by a 40-character hash (checksum).

  • +
  • git graph print abbreviations of these checksums.

  • +
  • Branches are pointers that point to a commit.

  • +
  • Branch main points to a commit (in this example it is e7cf023efe382340e5284c278c6ae2c087dd3ff7 but on your computer +the hash will be different).

  • +
  • HEAD is another pointer, it points to where we are right now (currently main)

  • +
+

In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards.

+
+
+

Creating and working with branches

+
+

Instructor note

+

We do the following part together. Encourage participants to type along.

+
+
+

It is possible to create and merge branches directly on GitHub

+
    +
  • However, we do not have screenshots for that in this episode

  • +
  • But if you prefer to work in the browser, please try it

  • +
  • Please contribute screenshots to this lesson

  • +
+
+

Let’s create a branch called experiment where we add cilantro to ingredients.txt +(text after “#” are comments and not part of the command).

+
$ git branch experiment main  # creates branch "experiment" from "main"
+$ git switch experiment       # switch to branch "experiment"
+$ git branch                  # list all local branches and show on which branch we are
+
+
+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+
    +
  • Verify that you are on the experiment branch (note that git graph also +makes it clear what branch you are on: HEAD -> branchname):

    +
    $ git branch
    +
    +* experiment
    +  main
    +
    +
    +

    This command shows where we are, it does not create a branch.

    +
  • +
  • Then add 2 tbsp cilantro on top of the ingredients.txt:

    +
    * 2 tbsp cilantro
    +* 2 avocados
    +* 1 chili
    +* 1 lime
    +* 2 tsp salt
    +* 1/2 onion
    +
    +
    +
  • +
  • Stage this and commit it with the message “let us try with some cilantro”.

  • +
  • Then reduce the amount of cilantro to 1 tbsp, stage and commit again with “maybe little bit less cilantro”.

  • +
+

We have created two new commits:

+
$ git graph
+
+* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro
+* f6ec7b7 let us try with some cilantro
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • The branch experiment is two commits ahead of main.

  • +
  • We commit our changes to this branch.

  • +
+
+
+

Exercise: Create and commit to branches

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+../_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+../_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+
+
+

Exercise: Merging branches

+

It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge experiment into main.

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+
+

If you got stuck in the above exercises or joined later

+

If you got stuck in the above exercises or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git switch experiment
+$ git switch less-salt
+$ git switch main
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

First we make sure we are on the branch we wish to merge into:

+
$ git branch
+
+  experiment
+  less-salt
+* main
+
+
+

Then we merge experiment into main:

+
$ git merge experiment
+
+
+
+../_images/git-merge-1.svg
+

We can verify the result:

+
$ git graph
+
+*   81fcc0c (HEAD -> main) Merge branch 'experiment'
+|\
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+* | b4af65b improve the documentation
+|/
+| * bf28166 (less-salt) reduce amount of salt
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents.

+

To view the branches that are merged into the current branch we can use the command:

+
$ git branch --merged
+
+  experiment
+* main
+
+
+

We are also happy with the work on the less-salt branch. Let us merge that +one, too, into main:

+
$ git branch  # make sure you are on main
+$ git merge less-salt
+
+
+
+Commit graph after merge
+

Commit graph after merge.

+
+
+

We can verify the result in the terminal:

+
$ git graph
+
+*   4e03d4b (HEAD -> main) Merge branch 'less-salt'
+|\
+| * bf28166 (less-salt) reduce amount of salt
+* |   81fcc0c Merge branch 'experiment'
+|\ \
+| * | bcb8b78 (experiment) maybe little bit less cilantro
+| * | f6ec7b7 let us try with some cilantro
+| |/
+* / b4af65b improve the documentation
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Observe how Git nicely merged the changed amount of salt and the new ingredient in the same file +without us merging it manually:

+
$ cat ingredients.txt
+
+* 1 tbsp cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually settle merge conflicts (we will do that later).

+
+
+

Deleting branches safely

+

Both feature branches are merged:

+
$ git branch --merged
+
+  experiment
+  less-salt
+* main
+
+
+

This means we can delete the branches:

+
$ git branch -d experiment
+$ git branch -d less-salt
+
+
+

This is the result:

+
+Commit graph after merged branches were deleted
+

Commit graph after merged branches were deleted.

+
+
+

We observe that when deleting branches, +only the pointers (“sticky notes”) disappeared, not the commits.

+

Git will not let you delete a branch which has not been reintegrated unless you +insist using git branch -D. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them.

+
+
+

Optional exercises with branches

+

The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section.

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +../_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+
+
+

Tags

+
    +
  • A tag is a pointer to a commit but in contrast to a branch it does not ever +move when creating new commits later.

  • +
  • It can be useful to think of branches as sticky notes and of tags as +commemorative plaques.

  • +
  • We use tags to record particular states or milestones of a project at a given +point in time, like for instance versions (have a look at semantic versioning, +v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a).

  • +
  • There are two basic types of tags: annotated and lightweight.

  • +
  • Use annotated tags since they contain the author and can be cryptographically signed using +GPG, timestamped, and a message attached.

  • +
+

Let’s add an annotated tag to our current state of the guacamole recipe:

+
$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet"
+
+
+

As you may have found out already, git show is a very versatile command. Try this:

+
$ git show nobel-2023
+
+
+

For more information about tags see for example +the Pro Git book chapter on the +subject.

+
+
+
+

Summary

+

Let us pause for a moment and recapitulate what we have just learned:

+
$ git branch               # see where we are
+$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+$ git merge NAME           # merge branch NAME (to current branch)
+$ git branch -d NAME       # delete branch NAME
+$ git branch -D NAME       # delete unmerged branch NAME
+
+
+

Since the following command combo is so frequent:

+
$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+
+
+

There is a shortcut for it:

+
$ git switch --create NAME  # create branch NAME and switch to it
+
+
+
+

Typical workflows

+

With this there are two typical workflows:

+
$ git switch --create new-feature  # create branch, switch to it
+$ git commit                       # work, work, work, ..., and test
+$ git switch main                  # once feature is ready, switch to main
+$ git merge new-feature            # merge work to main
+$ git branch -d new-feature        # remove branch
+
+
+

Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging:

+
$ git switch --create wild-idea    # create branch, switch to it, work, work, work ...
+$ git switch main                  # realize it was a bad idea, back to main
+$ git branch -D wild-idea          # it is gone, off to a new idea
+
+
+
+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • A branch is a division unit of work, to be merged with other units of work.

  • +
  • A tag is a pointer to a moment in the history of a project.

  • +
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/browsing/index.html b/branch/main/browsing/index.html new file mode 100644 index 00000000..ebd9421f --- /dev/null +++ b/branch/main/browsing/index.html @@ -0,0 +1,515 @@ + + + + + + + Copy and browse an existing project — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Copy and browse an existing project

+

In this episode, we will look at an existing repository to +understand how all the pieces work together. Along the way, we will make a copy +(a fork) of the repository for us, which will be used for our +own changes in the next episode.

+
    +
  • We used to start by directly going and creating a repository from scratch. This +was abstract and hard to understand.

  • +
  • Instead, we’ll show you all the cool stuff in a Git repository +first, and then start adding files.

  • +
  • We use an example recipe book we created just for this course.

  • +
  • By the end of the course, you’ll know how to contribute your own +recipes to it.

  • +
+
+

Objectives

+
    +
  • See a real Git repository and understand what is inside of it.

  • +
  • Understand how version control allows advanced inspection of a +repository.

  • +
  • See how Git allows multiple people to collaborate easily.

  • +
  • See the big picture instead of remembering a bunch of commands.

  • +
+
+
+

GitHub, VS Code, Command line, and more

+

We offer three different paths of how to do this exercise:

+
    +
  • GitHub (this is the one we will demonstrate on day 1)

  • +
  • VS Code (if you prefer to follow along using an editor; we will +do this on day 2)

  • +
  • Command line (for people comfortable with the command line; you +will see more of this on day 2)

  • +
+

In the future we’ll add more paths, for example Jupyter and RStudio +(contributions welcome!).

+
+
+

Creating a copy of the repository by “forking”

+

A repository is a collection of files in one directory tracked +by git. A GitHub repository is GitHub’s copy, which adds +things like access control. Each GitHub repository is owned by a user +or organization, who controls what is in it.

+

First, we need to make our own copy of the exercise repository. This will +become important later, when we make our own changes.

+
    +
  1. Go to the repository view on GitHub:

    + +
  2. +
  3. First, on GitHub, click the button that says “Fork”. It is towards +the top-right of the screen:

    +
    +Screenshot on GitHub before clicking on "Fork" +
    +
  4. +
  5. You should shortly be redirected to your copy of the repository +YOUR_USER_NAME/recipe-book.

  6. +
+

At all times you should be aware of if you looking at your repository +or the CodeRefinery upstream repository.

+
    +
  • Your repository: https://github.com/USERNAME/recipe-book

  • +
  • CodeRefinery upstream repository: https://github.com/coderefinery/recipe-book

  • +
+
+

You only need to open your own view, as described above. The browser +URL should look like https://github.com/USER/recipe-book, where +USER is your GitHub username.

+
+
+
+

Exercise

+

Work on this by yourself or in your team.

+
+

Instructor note

+

Before starting the exercise session:

+
    +
  • Make sure you have shown how to fork the repository to own account +(above).

  • +
+
+
+

Exercise: Browsing an existing project (25 min)

+

Browse the recipe-book project (introduced above) and explore commits and branches. Take notes +and prepare questions. The hints are for the GitHub path in the +browser.

+
    +
  1. Browse the commit history: Are commit messages understandable? +(Hint: “Commit history”, the timeline symbol, above the file list)

  2. +
  3. Compare the commit history with the network graph (“Insights” -> “Network”). Can you find the branches?

  4. +
  5. How can you find out when a recipe was last modified?

  6. +
  7. How many changes did the Guacamole recipe receive (you find it under “sides”)? +Try to click on some of the commits to see what changed. +(Hint: “History” in the view of a single file)

  8. +
  9. Which recipes include the ingredient “salt”? +(Hint: the GitHub search. From the repository view, it should offer +the filter “repo:USER/recipe-book” by default. What if you +add a search term?)

  10. +
  11. In the Guacamole recipe, find out who modified each line last and when +(click on file, then click “Blame” button). Find out who added the cilantro +and in which commit. +(Hint: “Blame” view in the file view)

  12. +
  13. Can you use these recipes yourself? Are you allowed to share +modifications? +(Hint: look for a license file)

  14. +
  15. Browse issues and pull requests in the upstream repository (the +repository you forked from). Any idea what these might be good for? +(Hint: tabs in the repository view)

  16. +
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by +design.

+
+
+

Solution and walk-through

+
+

(1) Basic browsing

+

The most basic thing to look at is the history of commits.

+
    +
  • This is visible from a button in the repository view. We see every +change, when, and who has committed.

  • +
  • Every change has a unique identifier, such as 554c187. This can +be used to identify both this change, and the whole project’s +version as of that change.

  • +
  • Clicking on a change in the view shows more.

  • +
+
+

Click on the timeline symbol in the repository view:

+
+Screenshot on GitHub of where to find the commit history +
+
+
+
+

(2) Compare commit history with network graph

+

The commit history we saw above looks linear: one commit after +another. But if we look at the network view, we see some branches and +merges. We’ll see how to do these later. This is another one of the +basic Git views.

+
+

In a new browser tab, open the “Insights” tab, and click on “Network”. +You can hover over the commit dots to see the person who committed and +how they correspond with the commits in the other view:

+
+Screenshot on GitHub of the network graph +
+
+
+
+

(3) When was a recipe last modified?

+

We see the history for the whole repository, but we can also see it +for a single file.

+
+

Navigate to the file view: Main page → sides directory → +guacamole.md. Click the “History” button near the top right:

+
+Screenshot on GitHub showing the history of a single file +
+
+
+
+

(4) How many changes did the Guacamole recipe receive?

+

According to the view above, it seems to have five changes (as of +2024-03-07). This could change later on.

+
+
+

(5) Which recipes include the ingredient “salt”

+

Version control makes it very easy to find all occurrences of a single +word. This is useful for things like finding where functions or +variables are defined or used.

+
+

We go to the main recipe book view. We click the Search magnifying +class at the very top, type “salt”, and click enter. We see every +instance, including the context.

+
+

Searching in a forked repository will not work instantaneously!

+

It usually takes a few minutes before one can search for keywords in a forked repository +since it first needs to build the search index the very first time we search. +Start it, continue with other steps, then come back to this.

+
+
+Screenshot on GitHub performing a search +
+
+
+
+

(6) Who modified each line last and when?

+

This is called the “annotate” or “blame” view. The name “blame” +is very unfortunate, but it is the standard term for historical reasons +for this functionality and it is not meant to blame anyone.

+
+

From a recipe view, change preview to “Blame” towards the top-left. +To get the actual commit, click on the commit message.

+
+Screenshot on GitHub showing the "Blame" view +
+
+
+
+

(7) Can you use these recipes yourself? Are you allowed to share modifications?

+
    +
  • Look at the file LICENSE.

  • +
  • It says it is “Creative Commons Zero 1.0”, which is equivalent to +public domain. You can use them without conditions.

  • +
  • Note the GitHub view of the file LICENSE gives a nice summary of what it +means. Try it out:

    +
    +Screenshot on GitHub summarizing license terms +
    +
  • +
+
+
+

(8) Browse issues and pull requests in the upstream repository

+

This can only be done through the GitHub view. Go to the main +repository coderefinery/recipe-book, (not your fork): +https://github.com/coderefinery/recipe-book. Issues +and Pull requests are different for each GitHub +copy.

+
    +
  • Click on the “Issues” tab. These are notes that people have added, +which allow discussion about the project. Often they are used to communicate +problems or ideas.

  • +
  • Click on the “Pull requests” tab. This allows anyone to propose +changes, but only the repository owners can accept.

  • +
+
+
+
+

Summary

+
    +
  • Git allowed us to understand this simple project much better than we +could, if it was just a few files on our own computer.

  • +
  • It was also very easy to share the project with the course.

  • +
  • By forking the repository, we created our own copy. This is +important for the next episode, where we will make changes to +our copy.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/commits/index.html b/branch/main/commits/index.html new file mode 100644 index 00000000..1f0a6126 --- /dev/null +++ b/branch/main/commits/index.html @@ -0,0 +1,550 @@ + + + + + + + Committing changes — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Committing changes

+

The first and most basic task to do in Git is record changes using +commits. In this part, we will record changes in two +ways: on a new branch (which supports multiple lines of work at once), and directly +on the “main” branch (which happens to be the default branch here).

+
+

Objectives

+
    +
  • Record new changes to our own copy of the project.

  • +
  • Understand adding changes in two separate branches.

  • +
  • See how to compare different versions.

  • +
+
+
+

Background

+
    +
  • In the previous episode we have browsed an existing repository and saw commits +and branches.

  • +
  • Each commit is a snapshot of the entire project at a certain +point in time and has a unique identifier (hash) .

  • +
  • A branch is a line of development, and the main branch or master branch +are often the default branch in Git.

  • +
  • A branch in Git is like a sticky note that is attached to a commit. When we add +new commits to a branch, the sticky note moves to the new commit.

  • +
  • Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don’t move when new +commits are added.

  • +
+
+Branching explained with a gopher +
+

What if two people, at the same time, make two different changes? Git +can merge them together easily. Image created using https://gopherize.me/ +(inspiration).

+
+
+
+
+

Exercise

+

We offer three different paths of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the GitHub +path only and recommend you do that. (You can get experience with +the other paths on day 2)

+
+

Exercise: Practice creating commits and branches (20 min)

+
    +
  1. Make sure that you now work on your fork of the recipe-book +repository (USER/recipe-book, not coderefinery/recipe-book)

  2. +
  3. First create a new branch and then add a recipe to the branch and commit the change.

  4. +
  5. In a new commit, modify the recipe you just added.

  6. +
  7. Switch to the main branch and modify a recipe there.

  8. +
  9. Browse the network and locate the commits that you just created (“Insights” -> “Network”).

  10. +
  11. Compare the branch that you created with the main branch. Can you find an easy way to see the differences?

  12. +
  13. Can you find a way to compare versions between two arbitrary commits in the repository?

  14. +
  15. Try to rename the branch that you created and then browse the network again.

  16. +
  17. Try to create a tag for one of the commits that you created (on GitHub, +create a “release”).

  18. +
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by +design.

+
+
+

Solution and walk-through

+
+

(1) Make sure you are on your fork

+
+Screenshot on GitHub where we verify that we are on our fork. +
+

You want to see your username in the URL and you want to see the “forked from +…” part.

+
+
+
+
+

(2) Create a branch and add a recipe to the branch

+

A recipe template is below. This format is called “Markdown”, but it +doesn’t matter right now. You don’t have to use this particular template.

+
# Recipe name
+
+## Ingredients
+
+- Ingredient 1
+- Ingredient 2
+
+
+## Instructions
+
+- Step 1
+- Step 2
+
+
+

There is a main branch that is default. We want to create a +different branch for our new commit, because we will merge it later. +Commit is the verb to describe recording more changes, and also the +name of the thing you make. A commit is identified by something such as +554c187.

+
+
    +
  1. Where it says “main” at the top left, click, enter a new branch +name new-recipe, click on the offer to create the new branch +(“Create branch new-recipe from main”).

    +
    +Screenshot on GitHub where we create a new branch. +
    +
  2. +
  3. Change to some sub-directory, for example sides

  4. +
  5. Make sure you are still on the new-recipe branch (it should say +it at the top), and click “Add file” → “Create new file” from the +upper right.

  6. +
  7. Enter a filename where it says “Name your file…”, with a .md at +the end. Example: mixed-nuts.md.

  8. +
  9. Enter the recipe. You can use the template above.

  10. +
  11. Click “Commit changes”

  12. +
  13. Enter a commit message. Then click “Commit +changes”.

  14. +
+

You should appear back at the file browser view, and see your new +recipe there.

+
+
+
+

(3) Modify the recipe with a new commit

+
+

This is similar to before, but we click on the existing file to +modify.

+
    +
  1. Click on your new recipe, for example mixed-nuts.md.

  2. +
  3. Click the edit button, the pencil icon at top-right.

  4. +
  5. Follow the “Commit changes” instructions as in the previous step.

  6. +
+
+
+
+

(4) Switch to the main branch and modify a recipe there

+
+
    +
  1. Go back to the main repository page (your user’s page).

  2. +
  3. In the branch switch view (top left above the file view), switch to +main.

  4. +
  5. Modify another recipe that already exists, following the pattern +from above. Don’t modify the one you just created (but it shouldn’t +even be visible on the main branch).

  6. +
+
+
+
+

(5) Browse the commits you just made

+

Let’s look at what we did. Now, the main and new-recipe branches +have diverged: both have some modifications. Try to find the commits +you created.

+
+

Insights tab → Network view (just like we have done before).

+
+
+
+

(6) Compare the branches

+

Comparing changes is an important thing we need to do. When using the +GitHub view only, this may not be so common, but we’ll show it so that +it makes sense later on.

+
+

Next to the branch name switcher, click on “Branches” to get an overview.

+

Another way to compare branches or commits on GitHub is to adjust the following URL: +https://github.com/USER/recipe-book/compare/VERSION1..VERSION2

+

Replace USER with your username and VERSION1 and VERSION2 with a commit hash or branch name. +Please try it out.

+
+
+
+

(7) Compare two arbitrary commits

+

This is similar to above, but not only between branches.

+
+

Like above, one can compare commits on GitHub by adjusting the following URL: +https://github.com/USER/recipe-book/compare/VERSION1..VERSION2

+

Replace USER with your username and VERSION1 and VERSION2 with a commit hash or branch name. +Please try it out.

+
+
+
+

(8) Renaming a branch

+
+

Branch button → View all branches → three dots at right side → Rename branch.

+
+
+
+

(9) Creating a tag

+

Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don’t move when new +commits are added.

+
+

Click on the branch switcher, and then on “Tags”, then on “View all tags”, then +“Create a new release”:

+
+Screenshot on GitHub where we create a new tag. +
+

What GitHub calls releases are actually tags in Git with additional metadata. +For the purpose of this exercise we can use them interchangeably.

+
+
+
+
+

Discussion

+

In this part, we saw how we can make changes to our files. +With branches, we can +track several lines of work at once, and can compare +their differences.

+
    +
  • You could commit directly to main if there is only one single line +of work and it’s only you.

  • +
  • You could commit to branches if there are multiple lines of work at +once, and you don’t want them to interfere with each other.

  • +
  • Tags are useful to mark a specific commit as important, for example a +release version.

  • +
  • In Git, commits form a so-called “graph”. Branches are tags in Git function +like sticky notes that stick to specific commits. What this means for us is +that it does not cost any significant disk space to create new branches.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/configuration/index.html b/branch/main/configuration/index.html new file mode 100644 index 00000000..65fceaeb --- /dev/null +++ b/branch/main/configuration/index.html @@ -0,0 +1,298 @@ + + + + + + + Configuring Git command line and editor — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Configuring Git command line and editor

+

We have a longer version of this in the installation +instructions. +But for clarity, we will review the most important parts here.

+

You don’t need to set these if you work only through the GitHub web interface. +If you use VS Code or other editors or integrated development environments, +the editor might prompt you to set these up.

+

These configuration settings are saved in a file called .gitconfig in your +home directory. If this file exists, editors like VS Code will use this +configuration.

+

If you want to see your configuration settings, you can use the +command (--show-origin means it shows the file where each setting +is defined):

+
$ git config --list --show-origin
+
+
+
+

Name and email address for Git commit metadata

+

Git commits carry metadata about the author and two things you will always need +to define somewhere are:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+
+
+

For the email address we recommend to use the one you use for your GitHub account. +If you prefer to not use it, you can instead use +YOUR_GITHUB_USERNAME@users.noreply.github.com as the email address (replace YOUR_GITHUB_USERNAME). +This means that nobody can write to this email address, but GitHub will still +be able to connect your contributions with your GitHub account.

+

Note that these can, in theory, be anything: this is just data, not a +registration or identity requirement.

+
+
+

Default branch name

+

The default branch name in Git has been master for a long time, but it is +changing to main in many places. We recommend to set it to main for new +repositories that you create locally:

+
$ git config --global init.defaultbranch main
+
+
+
+
+

Useful alias for the command line

+

We recommend to define an alias in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+

We have an own section about aliases: Aliases and configuration.

+
+
+

Default text editor for commit messages

+

Git sometimes needs to start a text editor for you to enter messages (unless you create +commits from inside an editor or on the web). +This may have already been set to something (like VS Code), but if not +nano is usually a safe choice:

+
$ git config --global core.editor nano
+
+
+

The installation instructions text editor page gives ways +to set other editors, or do a web search for “git set editor to +[editor name]”.

+
+
+

Authenticating to GitHub: SSH or HTTPS or VS Code?

+

How does GitHub know who you are? There are three options:

+
    +
  • SSH is the classic method, using Secure Shell +Protocol remote connection +keys.

  • +
  • HTTPS works with the Git Credential Manager, which is an +extra add-on that works easily in Windows and Mac.

  • +
  • VS Code editor can authenticate with GitHub using its own +authentication method.

  • +
+

Read how to install them from the installation +instructions.

+

Test which one you should use:

+
+

Try this command:

+
$ ssh -T git@github.com
+
+
+

If it returns Hi USERNAME! You've successfully authenticated, ..., +then SSH is configured and the following steps will work with the SSH +cloning.

+

See our installation +instructions to +set up SSH access.

+

From now on, if you know that SSH works, you should always select +SSH as the clone URL from GitHub, or translate the URL to start with +the right thing yourself: git@github.com: (with the :).

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/conflicts/index.html b/branch/main/conflicts/index.html new file mode 100644 index 00000000..56d4b4d0 --- /dev/null +++ b/branch/main/conflicts/index.html @@ -0,0 +1,621 @@ + + + + + + + Conflict resolution — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Conflict resolution

+
+

Objectives

+
    +
  • Understand merge conflicts sufficiently well to be able to fix them.

  • +
+
+
+

Instructor note

+
    +
  • 20 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Conflicts in Git and why they are good

+

Imagine we start with the following text file:

+
1 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch A somebody modifies:

+
2 tbsp cilantro
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch B somebody else modifies:

+
1/2 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1 onion
+
+
+

When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro:

+
?????????????????
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1 onion
+
+
+

Git is very good at resolving modifications when merging branches and +in most cases a git merge runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see Optional exercises with branches) without you even noticing.

+

But sometimes the same portion of the code/text is modified on two branches +in two different ways and Git issues a conflict. +Then you need to tell Git which version to keep (resolve it).

+

There are several ways to do that as we will see.

+

Please remember:

+
    +
  • It is good that Git conflicts exist: Git will not silently overwrite one of +two differing modifications.

  • +
  • Conflicts may look scary, but are not that bad after a little bit of +practice. Also they are luckily rare.

  • +
  • Don’t be afraid of Git because of conflicts. You may not meet some conflicts +using other systems because you simply can’t do the kinds of things you do +in Git.

  • +
  • You can take human measures to reduce them.

  • +
+
+
+

The human side of conflicts

+
    +
  • What does it mean if two people do the same thing in two different ways?

  • +
  • What if you work on the same file but do two different things in the different sections?

  • +
  • What if you do something, don’t tell someone from 6 months, and then try to combine it with other people’s work?

  • +
  • How are conflicts avoided in other work? (Only one person working at once? +Declaring what you are doing before you start, if there is any chance someone +else might do the same thing, helps.)

  • +
  • Minor conflicts (two people revise spelling) vs semantic (two people rewrite +a function to add two different new features). How did Git solve these in +branching/merging easily?

  • +
+
+

Now we can go to show how Git controls when there is actually a conflict.

+
+
+

Preparing a conflict

+
+

Instructor note

+

We do the following together as type-along/demo.

+
+
+

If you got stuck previously or joined later

+

If you got stuck previously or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together.

+
    +
  • Create two branches from main: one called like-cilantro, one called dislike-cilantro:

    +
    $ git branch like-cilantro main
    +$ git branch dislike-cilantro main
    +
    +
    +
  • +
  • On the two branches make different modifications to the amount of the same ingredient:

  • +
  • On the branch like-cilantro we have the following change:

    +
    $ git diff main like-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6cacd50 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
  • And on the branch dislike-cilantro we have the following change:

    +
    $ git diff main dislike-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6484462 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 1/2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
+
+
+

Merging conflicting changes

+

What do you expect will happen when we try to merge these two branches into +main?

+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+

The first merge will work:

+
$ git switch main
+$ git status
+$ git merge like-cilantro
+
+Updating 4e03d4b..3caa632
+Fast-forward
+ ingredients.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+
+

But the second will fail:

+
$ git merge dislike-cilantro
+
+Auto-merging ingredients.txt
+CONFLICT (content): Merge conflict in ingredients.txt
+Automatic merge failed; fix conflicts and then commit the result.
+
+
+

Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit:

+
$ git status
+
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+  (use "git merge --abort" to abort the merge)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+	both modified:   ingredients.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+
+
+

Git won’t decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward.

+

Let us inspect the conflicting file:

+
$ cat ingredients.txt
+
+<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

Git inserted resolution markers (the <<<<<<<, >>>>>>>, and =======).

+

Try also git diff:

+
$ git diff
+
+
+
diff --cc ingredients.txt
+index 6cacd50,6484462..0000000
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@@ -1,4 -1,4 +1,10 @@@
+++<<<<<<< HEAD
+ +* 2 tbsp cilantro
+++=======
++ * 1/2 tbsp cilantro
+++>>>>>>> dislike-cilantro
+  * 2 avocados
+  * 1 chili
+  * 1 lime
+
+
+

git diff now only shows the conflicting part, nothing else.

+
+
+

Conflict resolution

+
<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+
+
+

We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged.

+
+

Steps to resolve a conflict

+
    +
  • Check status with git status and git diff.

  • +
  • Decide what you keep (the one, the other, or both or something +else). Edit the file to do this.

    +
      +
    • Remove the resolution markers, if not already done.

    • +
    • The file(s) should now look exactly how you want them.

    • +
    +
  • +
  • Check status with git status and git diff.

  • +
  • Tell Git that you have resolved the conflict with git add ingredients.txt +(if you use the Emacs editor with a certain plugin the editor may stage the +change for you after you have removed the conflict markers).

  • +
  • Verify the result with git status.

  • +
  • Finally commit the merge with only git commit. Everything is pre-filled.

  • +
+
+
+
+

Exercise: Create and resolve a conflict

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+
+
+

Optional exercises with conflict resolution

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+
+

Using “ours” or “theirs” strategy

+
    +
  • Sometimes you know that you want to keep “ours” version (version on the branch you are on) +or “theirs” (version on the merged branch).

  • +
  • Then you do not have to resolve conflicts manually.

  • +
  • See merge strategies.

  • +
+

Example (merge and in doubt take the changes from current branch):

+
$ git merge -s recursive -Xours less-avocados
+
+
+

Or (merge and in doubt take the changes from less-avocados branch):

+
$ git merge -s recursive -Xtheirs less-avocados
+
+
+
+
+
+

Aborting a conflicting merge

+

Sometimes you get a merge conflict but realize that you can’t solve it without +talking to a colleague (who created the other change) first. What to do?

+

You can abort the merge and postponing conflict resolution by resetting the +repository to HEAD (last committed state):

+
$ git merge --abort
+
+
+

The repository looks then exactly as it was before the merge.

+
+
+
+

Avoiding conflicts

+
    +
  • Human measures

    +
      +
    • Think and plan to which branch you will commit to.

    • +
    • Do not put unrelated changes on the same branch.

    • +
    +
  • +
  • Collaboration measures

    +
      +
    • Open an issue and discuss with collaborators before starting a long-living +branch.

    • +
    +
  • +
  • Project layout measures

    +
      +
    • Modifying global data often causes conflicts.

    • +
    • Modular programming reduces this risk.

    • +
    +
  • +
  • Technical measures

    +
      +
    • Share your changes early and often - this is one of the happy, +rare circumstances when everyone doing the selfish thing (e.g. git push as +early as practical) results in best case for everyone!

    • +
    • Pull/rebase often to keep up to date with upstream.

    • +
    • Resolve conflicts early.

    • +
    +
  • +
+
+

Discussion

+

Discuss how Git handles conflicts compared to services like Google Drive.

+
+
+

Keypoints

+
    +
  • Conflicts often appear because of not enough communication or not optimal +branching strategy.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/customizing/index.html b/branch/main/customizing/index.html new file mode 100644 index 00000000..111371ed --- /dev/null +++ b/branch/main/customizing/index.html @@ -0,0 +1,207 @@ + + + + + + + Customizing Git — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Customizing Git

+
+

Shell prompt

+
+

Instructor note

+

Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like.

+
+

You can make your shell display contextual information about +your Git state even at all times.

+

Here are few example projects that make this possible and easy:

+ +
+
+

More useful “diff” output

+

Delta is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +“diff” output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/exercises/index.html b/branch/main/exercises/index.html new file mode 100644 index 00000000..1bae01d3 --- /dev/null +++ b/branch/main/exercises/index.html @@ -0,0 +1,1260 @@ + + + + + + + List of exercises — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

List of exercises

+

This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests.

+
+

Motivation

+

In motivation.md:

+ +
+
+

Copy and browse an existing project

+

In browsing.md:

+
+

Exercise: Browsing an existing project (25 min)

+

Browse the recipe-book project (introduced above) and explore commits and branches. Take notes +and prepare questions. The hints are for the GitHub path in the +browser.

+
    +
  1. Browse the commit history: Are commit messages understandable? +(Hint: “Commit history”, the timeline symbol, above the file list)

  2. +
  3. Compare the commit history with the network graph (“Insights” -> “Network”). Can you find the branches?

  4. +
  5. How can you find out when a recipe was last modified?

  6. +
  7. How many changes did the Guacamole recipe receive (you find it under “sides”)? +Try to click on some of the commits to see what changed. +(Hint: “History” in the view of a single file)

  8. +
  9. Which recipes include the ingredient “salt”? +(Hint: the GitHub search. From the repository view, it should offer +the filter “repo:USER/recipe-book” by default. What if you +add a search term?)

  10. +
  11. In the Guacamole recipe, find out who modified each line last and when +(click on file, then click “Blame” button). Find out who added the cilantro +and in which commit. +(Hint: “Blame” view in the file view)

  12. +
  13. Can you use these recipes yourself? Are you allowed to share +modifications? +(Hint: look for a license file)

  14. +
  15. Browse issues and pull requests in the upstream repository (the +repository you forked from). Any idea what these might be good for? +(Hint: tabs in the repository view)

  16. +
+
+
+
+

Committing changes

+

In commits.md:

+
+

Exercise: Practice creating commits and branches (20 min)

+
    +
  1. Make sure that you now work on your fork of the recipe-book +repository (USER/recipe-book, not coderefinery/recipe-book)

  2. +
  3. First create a new branch and then add a recipe to the branch and commit the change.

  4. +
  5. In a new commit, modify the recipe you just added.

  6. +
  7. Switch to the main branch and modify a recipe there.

  8. +
  9. Browse the network and locate the commits that you just created (“Insights” -> “Network”).

  10. +
  11. Compare the branch that you created with the main branch. Can you find an easy way to see the differences?

  12. +
  13. Can you find a way to compare versions between two arbitrary commits in the repository?

  14. +
  15. Try to rename the branch that you created and then browse the network again.

  16. +
  17. Try to create a tag for one of the commits that you created (on GitHub, +create a “release”).

  18. +
+
+
+
+

Merging changes and contributing to the project

+

In merging.md:

+
+

Exercise: Merging branches with pull requests (20 min)

+

We assume that in the previous exercise you have created a new branch +with a recipe. In our previous example, it is called new-recipe. +If not, create it first and add a recipe to your new branch, see +Committing changes.

+

We provide basic hints. You should refer to the solution as needed.

+
    +
  1. Navigate to your branch from the previous episode +(Hint: the same branch view we used last time).

  2. +
  3. Begin the pull request process. +(Hint: There is a “Contribute” button in the branch view).

  4. +
  5. Add or modify the pull request title and description, and verify the other data. +In the pull request verify the target repository and the target +branch. Make sure that you are merging within your own repository. +GitHub: By default, it will offer to make the change to the +upstream repository, coderefinery. You should change this, you +shouldn’t contribute your test recipe upstream yet. Where it says +base repository, select your own user’s repository.

  6. +
  7. Create the pull request by clicking “Create pull request”. Browse +the network view to see if anything has changed yet.

  8. +
  9. Merge the pull request, or if you are not on GitHub you can merge +the branch locally. Browse the network again. What has changed?

  10. +
  11. Find out which branches are merged and thus safe to delete. Then remove them +and verify that the commits are still there, only the branch labels are +gone. (Hint: you can delete branches that have been merged into main).

  12. +
  13. Optional: Try to create a new branch with a new change, then open a pull +request but towards the central repository. We will later merge few of +those. +(Hint: this is mostly the same as above, for the GitHub path. But, +you set the base repository as CodeRefinery. You might need to +compare across forks.)

  14. +
+
+

In merging.md:

+
+

Exercise

+
    +
  1. Switch to the main branch that you want to merge the other +branch into. (Note that this is the other way around from the +GitHub path).

  2. +
+

Then:

+
    +
  1. Merge the other branch into main (which is then your current branch).

  2. +
  3. Find out which branches are merged and thus safe to delete. Then remove them +and verify that the commits are still there, only the branch labels are +gone. (Hint: you can delete branches that have been merged into main).

  4. +
  5. (optional, advanced) Try to create a new branch, and make a +GitHub pull request with your recipe, and contribute it to our +upstream repository. This is very complex right now since your +change has to get to GitHub, and we haven’t shown that yet. We +don’t give a solution for this.

  6. +
+
+
+
+

Cloning a Git repository and working locally

+

In local-workflow.md:

+
+

Exercise: Cloning a Git repository and working locally (25 min)

+
    +
  1. Configure Git command line and editor if you haven’t done that already.

  2. +
  3. Decide which repository you want to clone: your fork or the original repository? Both will work for this exercise. +Then, clone the recipe book.

  4. +
  5. Create a new branch.

  6. +
  7. Make a commit on your new branch.

  8. +
  9. Switch back to the main branch and create one or two commits there.

  10. +
  11. Merge the new branch into main.

  12. +
  13. Compare the graph locally and on GitHub and observe that the changes only exist locally on your computer.

  14. +
  15. Where are the remote branches? Practice how you can see all remote branches +also locally and how you can fetch them and make local changes to them.

  16. +
+
+
+
+

Inspecting history

+

In archaeology.md:

+
+

Exercise: Explore basic archaeology commands (20 min)

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Make sure you are not inside another Git repository when running this +exercise. If you are, first step “outside” of it. +We want to avoid creating a Git repository inside another Git repository.

    +
    +

    You can check if you are inside a Git repository with:

    +
    $ git status
    +
    +fatal: not a git repository (or any of the parent directories): .git
    +
    +
    +

    You want to see the above message which tells us that this is not a Git repository.

    +
    +
  • +
  • Clone this repository: +https://github.com/networkx/networkx.git.

    +
    +
    $ git clone https://github.com/networkx/networkx.git
    +
    +
    +
    +
  • +
  • Then let us all make sure we are working on a well-defined version of the repository.

    +
    +

    Step into the new directory and create an exercise branch from the +networkx-2.6.3 tag/release:

    +
    $ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+

In archaeology.md:

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+
+

How to turn your project to a Git repo and share it

+

In sharing.md:

+
+

Exercise: Turn your project to a Git repo and share it (25 min)

+
    +
  1. Create a new directory called myproject with one or few files in it. +This represents our own project. It is not yet a Git repository. You can try +that with your own project or use a simple placeholder example.

  2. +
  3. Turn this new directory into a Git repository.

  4. +
  5. Share this repository on GitHub (or GitLab, since it really works the same).

  6. +
+

We offer three different paths of how to do this exercise.

+
    +
  • Via GitHub web interface: easy and can be a good starting point if you are completely +new to Git.

  • +
  • VS Code is quite easy, since VS Code can offer to create the +GitHub repositories for you.

  • +
  • Command line: you need to create the +repository on GitHub and link it yourself.

  • +
+
+

Create an repository on GitHub

+

First log into GitHub, then follow the screenshots and descriptions below.

+
+Screenshot on GitHub before a new repository form is opened +
+

Click on the “plus” symbol on top right, then on “New repository”.

+
+
+

Then:

+
+Screenshot on GitHub just before a new repository is created +
+

Choose a repository name, add a short description, and in this case make sure to check “Add a +README file”. Finally “Create repository”.

+
+
+

Upload your files

+

Now that the repository is created, you can upload your files:

+
+Screenshot on GitHub just before uploading files +
+

Click on the “+” symbol and then on “Upload files”.

+
+
+
+
+
+
+

Basics

+

In basics.md:

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+

In basics.md:

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+

In basics.md:

+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+

In basics.md:

+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+

In basics.md:

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+
+

Branching and merging

+

In branches.md:

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+../_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+../_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+

In branches.md:

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+

In branches.md:

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +../_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+

In branches.md:

+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+

In branches.md:

+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+
+

Conflict resolution

+

In conflicts.md:

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+

In conflicts.md:

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+

In conflicts.md:

+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+

Using the Git staging area

+

In staging-area.md:

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+

In staging-area.md:

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+
+

Undoing and recovering

+

In recovering.md:

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+

In recovering.md:

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+

In recovering.md:

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+

In recovering.md:

+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+

Interrupted work

+

In interrupted.md:

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/genindex/index.html b/branch/main/genindex/index.html new file mode 100644 index 00000000..6ae2ef4d --- /dev/null +++ b/branch/main/genindex/index.html @@ -0,0 +1,359 @@ + + + + + + Index — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | F + | G + | H + | I + | M + | O + | P + | R + | S + | T + | U + | V + | W + +
+

A

+ + +
+ +

B

+ + +
+ +

C

+ + + +
+ +

F

+ + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + +
+ +

M

+ + + +
+ +

O

+ + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + +
+ +

T

+ + +
+ +

U

+ + +
+ +

V

+ + + +
+ +

W

+ + + +
+ + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/guide/index.html b/branch/main/guide/index.html new file mode 100644 index 00000000..11ffba7b --- /dev/null +++ b/branch/main/guide/index.html @@ -0,0 +1,386 @@ + + + + + + + Instructor guide — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor guide

+
+

Exercise preparation: one day before the workshop

+ +
+
+

Privacy

+

When presenting the material in a streamed and recorded workshop, make sure to +only show the https://github.com/coderefinery/recipe-book-recorded +repository.

+
+
+

Schedule Day 1

+

Times here are in CE(S)T.

+ +
+
+

Schedule Day 2

+

Times here are in CE(S)T.

+ +
+
+

Why we teach this lesson

+

Everyone should be using a version control system for their work, even if they’re working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories.

+

Specific motivations:

+
    +
  • Code easily becomes a disaster without version control

  • +
  • Mistakes happen - Git offers roll-back functionality and easy backup mechanism

  • +
  • One often needs to work on multiple things in parallel - branches solve that problem

  • +
  • Git enables people to collaborate on code or text without stepping on each other’s toes

  • +
  • Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, +and if bugs are found one can find out exactly when it was introduced

  • +
+

Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices.

+
+
+

Intended learning outcomes

+

By the end of this lesson, learners should:

+
    +
  • realize that version control is very important and Git is a valuable tool to learn and use

  • +
  • understand that Git is configurable and know how to set basic configurations

  • +
  • be able to set up Git repositories and make commits

  • +
  • know how to write good commit messages

  • +
  • have an idea of how the staging area can be used to craft good commits

  • +
  • know how to create branches and switch between branches

  • +
  • have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way

  • +
  • know how to merge branches and understand what that means in terms of combining different modifications

  • +
  • realize that conflicts are generally a good thing since they prevent incorrect merges

  • +
  • be able to set up a repository on GitHub and connect it with local repository

  • +
  • push changes to a remote repository

  • +
  • know a few ways to search through a repository and its history

  • +
+
+
+

Inspecting history

+

Key lesson is how to find when something is broken or what commit has broken +the code.

+

It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that git annotate +and git show are available on GitHub and GitLab.

+

When discussing git annotate and git bisect the “when” is more important +than “who”. It is not to blame anybody but rather to find out whether published +results are affected.

+

Discuss how one would find out this information without version control.

+

Questions to involve participants:

+
    +
  • Have you ever found a bug in your code and wondered whether it has affected published results?

  • +
  • Have you ever wondered when, and by whom, a particular line of code was introduced?

  • +
  • Have you ever found out that a code behaves differently than it used to but you are not sure when +precisely this changed?

  • +
+

Confusion during git bisect exercise:

+

Learners may get stuck in the git bisect exercise if they incorrectly assign a commit +as bad or good. +To leave the bisect mode and return to the commit before git bisect start was issued, +one can do

+
$ git bisect reset
+
+
+

and start over if needed.

+
+

Live better than reading the website material

+

It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier.

+
+
+

Log your history in a separate window

+

The screencasting (shell window cheatsheet) hints have been moved to +the presenting +manual.

+
+
+

Create a cheatsheet on the board

+

For in-person workshops, create a “cheatsheet” on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven’t forgotten anything. Re-create and expand in future git lessons. +One strategy is:

+
    +
  • a common section for basic commands: init, config, clone, help, stash

  • +
  • info commands, can be run anytime: status, log, diff, graph

  • +
  • A section for all the commands that move code from different states: +add, commit, etc. See the visual cheat sheet below.

  • +
+

You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it’s probably too confusing to use after this course. But, the idea +of commands moving from the “working dir”, “staging area”, “commits”, +etc is good.

+
+Example cheat sheet +
+

Example cheat sheet.

+
+
+

We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to.

+
+
+

Draw a graph on the board

+

Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run git graph, then do the command, +then look at git graph again.

+
+
+

Repeat the following points

+
    +
  • Always check git status, git diff, and git graph (our alias) before and +after every command until you get used to things. These give you a clear view +into what is going on, the key to knowing what you are doing. Even +after you are used to things… anytime you do something you do +infrequently, it’s good to check.

  • +
  • git graph is a direct representation of what we are drawing on the +board and should constantly be compared to it.

  • +
  • Once you git add something, it’s almost impossible to lose it. +This is used all the time, for example once you commit or even add +it is hard to lose. Commit before you merge or rebase. And so on.

  • +
+
+
+

Start from identical environment

+

You probably have a highly optimized bash and git environment - one +that is different from students. Move .gitconfig and .bashrc out +of the way before you start so that your environment is identical to +what students have.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/index.html b/branch/main/index.html new file mode 100644 index 00000000..7dda5cff --- /dev/null +++ b/branch/main/index.html @@ -0,0 +1,286 @@ + + + + + + + Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version

+
+

Warning

+

In February and March 2024 we rewrote this lesson from the ground up. +If you are looking for the previous version, you can browse the +2023 version of this lesson.

+
+

This is the introductory lesson to version control using +Git.

+

We start with an existing repository on the web to visually explain the basic +concepts of version control. We later move to a local +repository. Our goal there is not only to be able to apply changes to an +existing repository but to also be able to turn own projects into Git +repositories and to share them with others.

+

In the separate collaborative Git +lesson, we teach more use +of remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with Git to +be able to work well.

+

The goals of the module as a whole are that the learner will feel comfortable +about committing changes, branching, and merging.

+
+

Prerequisites

+

We offer several options to go through the material: on the web, in an editor, +or in the terminal. +Please see the installation instructions.

+

We recommend to have a GitHub account. +Why GitHub? +Also GitLab and Bitbucket would +allow similar workflows and basically everything that we will discuss is +transferable. With this material and these exercises we do not implicitly +endorse the company GitHub. We have chosen to demonstrate +a number of concepts using examples with GitHub because +it is currently the most popular web platform for hosting Git repositories and +the chance is high that you will interact with +GitHub-based repositories even if you choose to host your +Git repository on another service.

+
+ + +
+

Studying an existing project

+ +
+ + + + + + +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/interrupted/index.html b/branch/main/interrupted/index.html new file mode 100644 index 00000000..1673c90f --- /dev/null +++ b/branch/main/interrupted/index.html @@ -0,0 +1,291 @@ + + + + + + + Interrupted work — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interrupted work

+
+

Objectives

+
    +
  • Learn to switch context or abort work without panicking.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+

Keypoints

+
    +
  • There is almost never reason to clone a fresh copy to complete a task that +you have in mind.

  • +
+
+
+

Frequent situation: interrupted work

+

We all wish that we could write beautiful perfect code. But the real world is +much more chaotic:

+
    +
  • You are in the middle of a “Jackson-Pollock-style” debugging spree with 27 modified files +and debugging prints everywhere.

  • +
  • Your colleague comes in and wants you to fix/commit something right now.

  • +
  • What to do?

  • +
+

Git provides lots of ways to switch tasks without ruining everything.

+
+
+

Option 1: Stashing

+

The stash is the first and easiest place to temporarily “stash” +things.

+
    +
  • git stash will put working directory and staging area changes +away. Your code will be same as last commit.

  • +
  • git stash pop will return to the state you were before. Can give it a list.

  • +
  • git stash list will list the current stashes.

  • +
  • git stash save NAME is like the first, but will give it a name. +Useful if it might last a while.

  • +
  • git stash save [-p] [filename] will stash certain files files +and/or by patches.

  • +
  • git stash drop will drop the most recent stash (or whichever stash +you give).

  • +
  • The stashes form a stack, so you can stash several batches of modifications.

  • +
+
+

Exercise: Stashing

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+
+

Option 2: Create branches

+

You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch.

+

You basically know how to do this:

+
$ git switch --create temporary  # create a branch and switch to it
+$ git add PATHS                  # stage changes
+$ git commit                     # commit them
+$ git switch main                # back to main, continue your work there ...
+$ git switch temporary           # continue again on "temporary" where you left off
+
+
+

Later you can merge it to main or rebase it on top of main and resume work.

+
+
+

Storing various junk you don’t need but don’t want to get rid of

+

It happens often that you do something and don’t need it, but you don’t want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/lesson.pdf b/branch/main/lesson.pdf new file mode 100644 index 00000000..be932471 Binary files /dev/null and b/branch/main/lesson.pdf differ diff --git a/branch/main/level/index.html b/branch/main/level/index.html new file mode 100644 index 00000000..973ee734 --- /dev/null +++ b/branch/main/level/index.html @@ -0,0 +1,312 @@ + + + + + + + Practical advice: how much Git is necessary? — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Practical advice: how much Git is necessary?

+
+

Instructor note

+
    +
  • 20 min teaching/discussion

  • +
+
+
+

Writing useful commit messages

+

Useful commit messages summarize the change and provide context.

+

If you need a commit message that is longer than one line, +then the convention is: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+

Good example:

+
increase alpha to 2.0 for faster convergence
+
+the motivation for this change is
+to enable ...
+...
+(more context)
+...
+this is based on a discussion in #123
+
+
+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

What level of branching complexity is necessary for each project?

+

Simple personal projects:

+
    +
  • Typically start with just the main branch.

  • +
  • Use branches for unfinished/untested ideas.

  • +
  • Use branches when you are not sure about a change.

  • +
  • Use tags to mark important milestones.

  • +
  • If you are unsure what to do with unfinished and not working code, commit it +to a branch.

  • +
+

Projects with few persons: you accept things breaking sometimes

+
    +
  • It might be reasonable to commit to the main branch and feature branches.

  • +
+

Projects with few persons: changes are reviewed by others

+
    +
  • You create new feature branches for changes.

  • +
  • Changes are reviewed before they are merged to the main branch +(more about that in the collaborative Git lesson).

  • +
  • Consider to write-protect the main branch so that it can only be changed +with pull requests or merge requests.

  • +
+
+
+

How about staging and committing?

+
    +
  • Commit early and often: rather create too many commits than too few. +You can always combine commits later.

  • +
  • Once you commit, it is very, very hard to really lose your code.

  • +
  • Always fully commit (or stash) before you do dangerous things, so that you know you are safe. +Otherwise it can be hard to recover.

  • +
  • Later you can start using the staging area (where you first stage and then commit in a second step).

  • +
  • Later start using git add -p and/or git commit -p.

  • +
+
+
+

How large should a commit be?

+
    +
  • Better too small than too large (easier to combine than to split).

  • +
  • Often I make a commit at the end of the day (this is a unit I would not like to lose).

  • +
  • Smaller sized commits may be easier to review for others than huge commits.

  • +
  • Imperfect commits are better than no commits.

  • +
  • A commit should not contain unrelated changes to simplify review and possible +repair/adjustments/undo later (but again: imperfect commits are better than no commits).

  • +
+
+
+

Keypoints

+
    +
  • There is no one size fits all - start simple and grow your project.

  • +
+
+
+

Discussion

+

How do you [plan to] use Git?

+
    +
  • Advanced users or beginners, please provide your input in the online collaborative document.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/local-workflow/index.html b/branch/main/local-workflow/index.html new file mode 100644 index 00000000..412d6950 --- /dev/null +++ b/branch/main/local-workflow/index.html @@ -0,0 +1,495 @@ + + + + + + + Cloning a Git repository and working locally — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cloning a Git repository and working locally

+

If you’ve been following the main path, you have just had interacted +with repositories on GitHub. This might not be what you usually +do, so now we move to working on your own computer.

+
+

Objectives

+
    +
  • We are able to clone a repository from the web and modify it locally.

  • +
  • We can do the same things we did before (commit, branch, merge), but locally.

  • +
  • We get a feeling for remote repositories (more later).

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

What is in a Git repository and what are we cloning?

+

Git repository:

+
    +
  • Contains all the files and directories of a project.

  • +
  • Contains the complete history of all changes (commits) to these files and directories.

  • +
  • Each commit is a snapshot of the entire project at a certain point in time and has a unique identifier (“hash”).

  • +
  • Sometimes it contains multiple branches and tags.

  • +
  • All the commits and history of a local repository are stored in a directory +called .git which is located at the root of the repository.

  • +
+

Cloning:

+
    +
  • Copying (downloading) the entire repository with all commits, branches, and tags to your computer.

  • +
  • It is a full backup of the repository, including all history.

  • +
  • You can then work on your local clone of the repository.

  • +
  • Changes on local clone will not automatically appear in the repository where +we cloned from. We have to actively “push” them there (we will practice this +in a later episode: How to turn your project to a Git repo and share it).

  • +
+
+
+

Exercise

+

Work on this by yourself or in your teams. Conceptually this episode should +seem familiar, from the browser-based exercises we did yesterday.

+

We offer the Command Line and VS Code paths for this exercise. +GitHub isn’t an option in this episode, since that is what we already +demonstrated in Committing changes and Merging changes and contributing to the project and since the point of this +episode is to work locally.

+

It is also possible to use the command line (terminal) from inside VS Code.

+
+

Exercise: Cloning a Git repository and working locally (25 min)

+
    +
  1. Configure Git command line and editor if you haven’t done that already.

  2. +
  3. Decide which repository you want to clone: your fork or the original repository? Both will work for this exercise. +Then, clone the recipe book.

  4. +
  5. Create a new branch.

  6. +
  7. Make a commit on your new branch.

  8. +
  9. Switch back to the main branch and create one or two commits there.

  10. +
  11. Merge the new branch into main.

  12. +
  13. Compare the graph locally and on GitHub and observe that the changes only exist locally on your computer.

  14. +
  15. Where are the remote branches? Practice how you can see all remote branches +also locally and how you can fetch them and make local changes to them.

  16. +
+
+

The solution below goes over most of the answer and should be used as +your guide (you can’t figure it out just from the exercise instructions).

+
+
+

Solution and walk-through

+
+

(1) Configure Git command line and editor

+

We have an own section for this: Configuring Git command line and editor.

+
+
+

(2) Cloning a repository

+

Now you need to decide which repository you want to clone. All of these options will work for this exercise +since we don’t plan to push changes back (for step 8 it might be easier to use the original repository):

+ +

The examples below assume you are cloning the original repository. If you are cloning your fork, you should +replace coderefinery with your GitHub username.

+
+

If you are unsure whether you are using SSH or HTTPS, please read Authenticating to GitHub: SSH or HTTPS or VS Code?.

+
+
$ git clone git@github.com:coderefinery/recipe-book.git
+
+
+
+

This creates a directory called “recipe-book” unless it already exists. You can also specify the target directory +on your computer (in this case “my-recipe-book”):

+
+
$ git clone git@github.com:coderefinery/recipe-book.git my-recipe-book
+
+
+
+
+
+
+

(3) Creating branches locally

+
+

Create a new branch called another-recipe from main and switch to it:

+
$ git switch --create another-recipe main
+
+
+

If you leave out the last argument, it will create a branch from the current +branch:

+
$ git switch --create another-recipe
+
+
+
+
+
+

(4) Creating commits locally

+
+

Create a new file. After we have created it, we can stage and commit +the change:

+
$ git add new-file.md
+$ git commit -m "Short summary of the change"
+
+
+

Make sure to replace “new-file.md” with the actual name of the file you created +and to replace “Short summary of the change” with a meaningful commit message.

+
+
+
+

(5) Switching branches and creating commits

+
+

First switch to the main branch:

+
$ git switch main
+
+
+

Then modify a file. Finally git add and then commit the change:

+
$ git commit -m "Short summary of the change"
+
+
+
+
+
+

(6) Merging branches locally

+
+

On the command line, when we merge, we always modify our current branch.

+

If you are not sure anymore what your current branch is, type:

+
$ git branch
+
+
+

Another way to find out where we are in Git:

+
$ git status
+
+
+

In this case we merge the another-recipe branch into our current branch:

+
$ git merge another-recipe
+
+
+
+
+
+

(7) How to compare the graph locally and on GitHub

+
+
$ git log --graph --oneline --decorate --all
+
+
+

We recommend to define an alias in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+

Then you can just type git graph from there on. We have an own section about +aliases: Aliases and configuration.

+

Compare this with the graph on GitHub: Insights tab → Network view (just like +we have done before).

+

The result is that we should not be able to see the new branch and the new +commits on GitHub.

+
+
+
+

(8) Browsing remote branches and creating local branches from them

+
+

With git branch you can list all local branches:

+
$ git branch
+
+  another-recipe
+* main
+
+
+

But where are the remote branches? We expect to see a couple of +them.

+

We can see them by asking for all branches (your output might vary depending on +where you cloned from):

+
$ git branch --all
+
+  another-recipe
+* main
+  remotes/origin/HEAD -> origin/main
+  remotes/origin/alex/fruit-salad
+  remotes/origin/main
+  remotes/origin/radovan/lasagna
+  remotes/origin/radovan/poke
+
+
+

You can create a local branch from a remote branch which will “track” the remote branch. +For instance, to create a local branch alex/fruit-salad from the remote branch origin/alex/fruit-salad +and switch to it, you can do:

+
$ git switch --create alex/fruit-salad origin/alex/fruit-salad
+
+
+

This shortcut will do the same thing:

+
$ git switch --track origin/alex/fruit-salad
+
+
+

Or even shorter:

+
$ git switch alex/fruit-salad
+
+
+

If you want to create a branch and not switch to it, you can use git branch.

+
$ git branch alex/fruit-salad
+
+
+
+
+
+
+

Summary

+
    +
  • When we clone a repository, we get a full backup of the repository, including +all history: all commits, branches, and tags.

  • +
  • Yesterday we learned about branches and commits, and now we created and used them locally.

  • +
  • Creating local branches and commits does not automatically modify the remote +repository. To “push” our local changes to the remote repository, we have to actively +“push” them there. We will practice this in a later episode: +How to turn your project to a Git repo and share it

  • +
  • Remote branches and local branches are not the same thing. If we want to +create local commits, we always need to create a local branch first. But the local branch can +“track” the remote branch and we can push and pull changes to and from the +remote branch.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/merging/index.html b/branch/main/merging/index.html new file mode 100644 index 00000000..41772a30 --- /dev/null +++ b/branch/main/merging/index.html @@ -0,0 +1,520 @@ + + + + + + + Merging changes and contributing to the project — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

Merging changes and contributing to the project

+

Git allows us to have different development lines where we can try things out. +It also allows different people to work on the same project at the same. This +means that we have to somehow combine the changes later. In this part we will +practice this: merging.

+
+

Objectives

+
    +
  • Understand that on GitHub merging is done through a pull request. Think of it as a change proposal.

  • +
  • Create and merge a pull request within your own repository.

  • +
  • Understand (and optionally) do the same across repositories, to contribute to +the upstream public repository.

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

Background

+
    +
  • In the last episode, we added a new recipe on a branch. This allows +us to test it before it becomes “live”.

  • +
  • Now, we want to bring that change into the “main” branch.

  • +
  • We will find it’s not that hard! But you do have to keep track of the +steps and make sure that you work very precisely.

  • +
+
+
+

Exercise

+

In this exercise, we will show how we can propose changes and merge +changes within our own repository. Optionally, you can propose a recipe to +the upstream recipe book - which shows the true purpose of this. But +this is only a preview and we will practice collaboration much more in the +collaborative Git lesson.

+

We offer three different paths of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the GitHub +path only and recommend you do that. The exercise text below has +some GitHub-specific notes, but most is possibly with any path.

+
+

First, we make something called a pull request, which allows +review and commenting before the actual merge.

+
+

Exercise: Merging branches with pull requests (20 min)

+

We assume that in the previous exercise you have created a new branch +with a recipe. In our previous example, it is called new-recipe. +If not, create it first and add a recipe to your new branch, see +Committing changes.

+

We provide basic hints. You should refer to the solution as needed.

+
    +
  1. Navigate to your branch from the previous episode +(Hint: the same branch view we used last time).

  2. +
  3. Begin the pull request process. +(Hint: There is a “Contribute” button in the branch view).

  4. +
  5. Add or modify the pull request title and description, and verify the other data. +In the pull request verify the target repository and the target +branch. Make sure that you are merging within your own repository. +GitHub: By default, it will offer to make the change to the +upstream repository, coderefinery. You should change this, you +shouldn’t contribute your test recipe upstream yet. Where it says +base repository, select your own user’s repository.

  6. +
  7. Create the pull request by clicking “Create pull request”. Browse +the network view to see if anything has changed yet.

  8. +
  9. Merge the pull request, or if you are not on GitHub you can merge +the branch locally. Browse the network again. What has changed?

  10. +
  11. Find out which branches are merged and thus safe to delete. Then remove them +and verify that the commits are still there, only the branch labels are +gone. (Hint: you can delete branches that have been merged into main).

  12. +
  13. Optional: Try to create a new branch with a new change, then open a pull +request but towards the central repository. We will later merge few of +those. +(Hint: this is mostly the same as above, for the GitHub path. But, +you set the base repository as CodeRefinery. You might need to +compare across forks.)

  14. +
+
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by design.

+
+
+

Solution and walk-through

+ +
+

(2) Begin the pull request process

+

In GitHub, the pull request is the way we propose to merge two +branches together. We start the process of making one.

+
+
+Screenshot on GitHub where we get to the pull request process. +
+
+
+
+

(3) Fill out and verify the pull request

+

Check that the pull request is directed to the right repository and branch +and that it contains the changes that you meant to merge.

+
+

Things to check:

+
    +
  • Base repository: this should be your own

  • +
  • Title: make it descriptive

  • +
  • Description: make it informative

  • +
  • Scroll down to see commits: are these the ones you want to merge?

  • +
  • Scroll down to see the changes: are these the ones you want to merge?

    +
    +Screenshot on GitHub where we verify the changes we want to merge. +
    +

    This screenshot only shows the top part. If you scroll down, you +can see the commits and the changes. We recommend to do this before +clicking on “Create pull request”.

    +
    +
    +
  • +
+
+
+
+

(4) Create the pull request

+

We actually create the pull request. Don’t forget to navigate to the Network +view after opening the pull request. Note that the changes proposed in the +pull request are not yet merged.

+
+

Click on the green button “Create pull request”.

+

If you click on the little arrow next to “Create pull request”, you can also +see the option to “Create draft pull request”. This will be interesting later +when collaborating with others. It allows you to open a pull request that is +not ready to be merged yet, but you want to show it to others and get feedback.

+
+
+
+

(5) Merge the pull request

+

Now, we do the actual merging. We see some effects now.

+
+

Review it again (commits and changes), and then click “Merge pull request”.

+

After merging, verify the network view. Also navigate then to your “main” +branch and check that your new recipe is there.

+
+
+
+

(6) Delete merged branches

+

Before deleting branches, first check whether they are merged.

+

If you delete an un-merged branch, it will be difficult to find the commits +that were on that branch. If you delete a merged branch, the commits are now +also part of the branch where we have merged to.

+
+

One way to delete the branch is to click on the “Delete branch” button after the pull +request is merged:

+
+Screenshot on GitHub suggesting us to delete a branch after it has been merged. +
+

But what if we forgot? Then navigate to the branch view:

+
+Screenshot on GitHub where we navigate to the branches view. +
+

In the overview we can see that it has been merged and we can delete it:

+
+Screenshot on GitHub where we see an overview of branches and can delete them. +
+
+
+
+

(7) Contribute to the original repository with a pull request

+

Remember, this is an advanced step. If you do this, you are donating +a recipe to everyone.

+
+

Now that you know how to create branches and opening a pull request, try to +open a new pull request with a new change but this time the base repository +should be the upstream one.

+

In other words, you now send a pull request across repositories: from your fork +to the original repository.

+

Another thing that is different now is that you might not have permissions to +merge the pull request. We can then together review and browse the pull +request.

+
+
+
+
+

Resolving a conflict (demonstration)

+

A conflict is when Git asks humans to decide during a merge which of two +changes to keep if the same portion of a file has been changed in two different +ways on two different branches.

+

We will practice conflict resolution in the collaborative Git +lesson.

+

Here we will only demonstrate how to create a conflict and how to resolve it, +all on GitHub. Once we understand how this works, we will be more confident to +resolve conflicts also in the command line.

+

How to create a conflict (please try this in your own time and just watch now):

+
    +
  • Create a new branch from main and on it make a change to a file.

  • +
  • On main, make a different change to the same part of the same file.

  • +
  • Now try to merge the new branch to main. You will get a conflict.

  • +
+

How to resolve conflicts:

+
    +
  • On GitHub, you can resolve conflicts by clicking on the “Resolve conflicts” +button. This will open a text editor where you can choose which changes to +keep. +Make sure to remove the conflict markers. +After resolving the conflict, you can commit the changes and merge the +pull request.

  • +
  • Sometimes a conflict is between your change and somebody else’s change. In +that case, you might have to discuss with the other person which changes to +keep.

  • +
+

How to avoid conflicts:

+ +
+
+

Summary

+
    +
  • We learned how to merge two branches together.

  • +
  • When is this useful? This is not only useful to combine development lines in +your own work. Being able to merge branches also forms a basis for collaboration.

  • +
  • Branches which are merged to other branches are safe to delete, since we only +delete the “sticky note” next to a commit, not the commits themselves.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/motivation/index.html b/branch/main/motivation/index.html new file mode 100644 index 00000000..194c9d9c --- /dev/null +++ b/branch/main/motivation/index.html @@ -0,0 +1,363 @@ + + + + + + + Motivation — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Motivation

+
+

Objectives

+
    +
  • Make sure nobody leaves the workshop without starting to use some form of version control.

  • +
  • Discuss the reasons why we advocate distributed version control.

  • +
+
+
+

Instructor note

+
    +
  • 15 min discussion/demonstration

  • +
+
+
+

Git is all about keeping track of changes

+

We will learn how to keep track of changes first in the web browser. +Below are screenshots of tracked changes with Git +(from this example repository):

+
+Screenshot of a git log on GitHub +
+

Web browser, GitHub view

+
+
+

Later also using the terminal or the editor +(the same example repository):

+
+Screenshot of a git log in terminal +
+

The same as above, but the terminal view

+
+
+
+
+

Why do we need to keep track of versions?

+

Problem: If you have to identify and find your code from 17 days +ago, can you?

+

Version control is an answer to the following questions (do you recognize some +of them?):

+
    +
  • “It broke … hopefully I have a working version somewhere?”

  • +
  • “Can you please send me the latest version?”

  • +
  • “Where is the latest version?”

  • +
  • “Which version are you using?”

  • +
  • “Which version have the authors used in the paper I am trying to reproduce?”

  • +
  • “Found a bug! Since when was it there?”

  • +
  • “I am sure it used to work. When did it change?”

  • +
  • “My laptop is gone. Is my thesis now gone?”

  • +
+
+
+

Features: roll-back, branching, merging, collaboration

+

Problem: Your code worked two days ago, but is giving an error now. +You don’t know what you changed.

+

Problem: You and your colleague want to work on the same code at the +same time.

+
    +
  • Roll-back: you can always go back to a previous version and compare

  • +
  • Branching and merging:

    +
      +
    • Work on different ideas at the same time

    • +
    • Different people can work on the same code/project without interfering

    • +
    • You can experiment with an idea and discard it if it turns out to be a bad idea

    • +
    +
  • +
+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+ +
+
+

Reproducibility

+

Problem: Someone asks you about your results from 5 years ago. Can +you get the same results now?

+
    +
  • How do you indicate which version of your code you have used in your paper?

  • +
  • When you find a bug, how do you know when precisely this bug was introduced +(Are published results affected? Do you need to inform collaborators or users of your code?).

  • +
+

With version control we can “annotate” code +(browse this example online):

+
+Example of a git-annotated code with code and history side-by-side +
+

Example of a git-annotated code with code and history side-by-side.

+
+
+
+
+

Talking about code

+

Problem: You want to show someone a few lines from one of your projects.

+

Which of these two is more practical?

+
    +
  • “Clone the code, go to the file ‘src/util.rs’, and search for ‘time_iso8601’”. +Oh! But make sure you use the version from August 2023.”

  • +
  • Or I can send you a permalink:

  • +
+
+Screen-shot of a code portion +
+

Permalink that points to a code portion.

+
+
+
+
+

What we typically like to snapshot

+
    +
  • Software (this is how it started but Git/GitHub can track a lot more)

  • +
  • Scripts

  • +
  • Documents (plain text files much better suitable than Word documents)

  • +
  • Manuscripts (Git is great for collaborating/sharing LaTeX or Quarto manuscripts)

  • +
  • Configuration files

  • +
  • Website sources

  • +
  • Data

  • +
+
+

Discussion

+

In this example somebody tried to keep track of versions without a version +control system tool like Git. Discuss the following directory listing. What +possible problems do you anticipate with this kind of “version control”:

+
myproject-2019.zip
+myproject-2020-February.zip
+myproject-2021-August.zip
+myproject-2023-09-19-working.zip
+myproject-2023-09-21.zip
+myproject-2023-09-21-test.zip
+myproject-2023-09-21-myversion.zip
+myproject-2023-09-21-newfeature.zip
+...
+
+
+ +
+
+
+

Difficulties of version control

+

Despite the benefits, let’s be honest, there are some difficulties:

+
    +
  • One more thing to learn (it’s probably worth it and will save you more time in the long run; basic career skill).

  • +
  • Difficult if your collaborators don’t want to use it (in the worst case, you can version control on your side and email them versions).

  • +
  • Advanced things can be difficult, but basics are often enough (ask others for help when needed).

  • +
+
+
+

Why Git and not another tool?

+
    +
  • Easy to set up: no server needed.

  • +
  • Very popular: chances are high you will need to contribute to somebody else’s code which is tracked with Git.

  • +
  • Distributed: good backup, no single point of failure, you can track and +clean-up changes offline, simplifies collaboration model for open-source +projects.

  • +
  • Important platforms such as GitHub, GitLab, and Bitbucket +build on top of Git.

  • +
+

However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +Subversion, +Mercurial, Pijul, or others.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/objects.inv b/branch/main/objects.inv new file mode 100644 index 00000000..47d7569a Binary files /dev/null and b/branch/main/objects.inv differ diff --git a/branch/main/recovering/index.html b/branch/main/recovering/index.html new file mode 100644 index 00000000..fa94eedd --- /dev/null +++ b/branch/main/recovering/index.html @@ -0,0 +1,450 @@ + + + + + + + Undoing and recovering — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Undoing and recovering

+
+

Objectives

+
    +
  • Learn to undo changes safely

  • +
  • See when undone changes are permanently deleted and when they can be retrieved

  • +
+
+
+

Instructor note

+
    +
  • 25 min teaching/type-along

  • +
  • 25 min exercise

  • +
+
+

One of the main points of version control is that you can go back in +time to recover. Unlike this xkcd comic implies: https://xkcd.com/1597/

+

In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn’t a “commit” permanent?

+
    +
  • You can modify old commit history.

  • +
  • But if you have shared that history already, modifying it can make +a huge mess.

  • +
+
+

It is almost always possible to recover

+

As long as you commit something once (or at least git add it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru… until that guru becomes you.

+
+
+

Nice resource to visually simulate Git operation

+

git-sim +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command.

+
+
+
+

Undoing your recent, uncommitted and unstaged changes (preserves history)

+
+

Note

+

In case git restore does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git restore.

+
+

You do some work, and want to undo your uncommitted and unstaged modifications. +You can always do that with:

+
    +
  • git restore . (the dot means “here and in all folders below”)

  • +
+

You can also undo things selectively:

+
    +
  • git restore -p (decide which portions of changes to undo) or git restore PATH (decide which path/file)

  • +
+

If you have staged changes, you have at least two options to undo the staging:

+
    +
  • git restore --staged . followed by git status and git restore .

  • +
  • git reset --hard HEAD throws away everything that is not in last +commit (HEAD - this literal word, this isn’t a placeholder)

  • +
+
+
+
+

Reverting commits (preserves history)

+

Imagine we made a few commits. +We realize that the latest commit e02efcd was a mistake and we wish to undo it:

+
$ git log --oneline
+
+e02efcd (HEAD -> main) not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

A safe way to undo the commit is to revert the commit with git revert:

+
$ git revert e02efcd
+
+
+

This creates a new commit that does the opposite of the reverted commit. +The old commit remains in the history:

+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

You can revert any commit, no matter how old it is. It doesn’t affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we’ll learn about later).

+
+

Exercise: Revert a commit

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+
+
+
+

Adding to the previous commit (modifies history)

+

Sometimes we commit but realize we forgot something. +We can amend to the last commit:

+
$ git commit --amend
+
+
+

This can also be used to modify the last commit message.

+

Note that this will change the commit hash. This command modifies the history. +This means that we avoid this command on commits that we have shared with others.

+
+

Exercise: Modify a previous commit

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+
+
+
+

Rewinding branches (modifies history)

+

You can reset branch history to move your branch back to some +point in the past.

+
    +
  • git reset --hard HASH will force a branch label to any other point. All +other changes are lost (but it is possible to recover if you force reset by mistake).

  • +
  • Be careful if you do this - it can mess stuff up. Use git graph a +lot before and after.

  • +
+
+

Exercise: Git reset

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+
+
+
+
+

Recovering from committing to the wrong branch

+

It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes.

+

Here we assume that we made a couple of commits but we realize they went to the +wrong branch.

+

Solution 1 using git cherry-pick:

+
    +
  1. Make sure that the correct branch exists and if not, create it. Make sure to +create it from the commit hash where you wish you had created it from: git branch BRANCHNAME HASH

  2. +
  3. Switch to the correct branch.

  4. +
  5. git cherry-pick HASH can be used to take a specific commit to the +current branch. Cherry-pick all commits that should have gone to the correct +branch, from oldest to most recent.

  6. +
  7. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  8. +
+

Solution 2 using git reset --hard (makes sense if the correct branch should +contain all commits of the accidentally modified branch):

+
    +
  1. Create the correct branch, pointing at the latest commit: git branch BRANCHNAME.

  2. +
  3. Check with git log or git graph that both branches point to the same, latest, commit.

  4. +
  5. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  6. +
+
+
+

Recovering from merging/pulling into the wrong branch

+

git merge, git rebase, and git pull modify the current branch, never +the other branch. But sometimes we run this command on the wrong branch.

+
    +
  1. Check with git log the commit hash that you would like to rewind the +wrongly modified branch to.

  2. +
  3. Rewind the branch that accidentally got wrong commits with git reset --hard HASH (see also above).

  4. +
+
+
+

Recovering from conflict after pulling changes

+

Pulling changes with +git pull can create a conflict since git pull always also includes a git merge (more about this +in the collaborative Git lesson).

+

The recovery is same as described in Conflict resolution. Either +resolve conflicts or abort the merge with git merge --abort.

+
+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/reference/index.html b/branch/main/reference/index.html new file mode 100644 index 00000000..e10a03f0 --- /dev/null +++ b/branch/main/reference/index.html @@ -0,0 +1,319 @@ + + + + + + + Quick reference — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Quick reference

+
+

Other cheatsheets

+ +
+
+

Glossary

+
+
alias

With aliases you can define your own shortcuts for Git commands.

+
+
version control system

A system that records changes to a file or set of files over time so that +you can recall specific versions later.

+
+
git

Implementation of a version control system. Currently the most popular one.

+
+
commit

As a verb, the process of recording more changes. +As a noun, the name of the record of changes. +A commit is identified by something such as 554c187.

+
+
working directory
workspace

the actual files you see and edit

+
+
staging area

Place files go after git add and before git commit

+
+
hash

Unique reference of any commit or state. Comes from hash +functions such as MD5 +or SHA1.

+
+
branch

One line of work. Different branches can exist at the same time +and split/merge. Committing on a branch updates that branch.

+
+
tag

Like a branch in that it points to a commit for reference. +It is designed to be permanent an not updated.

+
+
HEAD

Pointer to the most recent commit on the current branch.

+
+
remote

Roughly, another server that holds .git.

+
+
origin

Default name for a remote repository.

+
+
repository

One collection of files managed by Git. It contains entire history +of all files managed by git. GitHub has one repository as one +GitHub repository. VS Code has one repository as one directory you +can open. The command line has one repository as one directory.

+
+
clone

As a verb, the process of making a copy of a repository locally. +It brings in all history and all files. (As a noun, the copy that +was made when cloning).

+
+
GitHub repository

The files from the Git repository, but also other things from +GitHub such as access permissions, issues, and pull requests.

+
+
upstream

The original repository from which the code comes. If you +fork the repository, it is your upstream and it is easy to +send changes back to there.

+
+
fork

As a noun: a one person’s copy of a repository. +As a verb: making that copy. +As a verb on GitHub: Making a copy of a repository linked to the +original. It is easy to send changes to the original

+
+
issue

Within a web repository like GitHub, discussion of a topic, for +example a problem or improvement suggestion. These are a property +of the web platform and not of the Git program itself.

+
+
pull request

A GitHub concept: change proposal. A proposal to merge one branch +into another. Usually used to contribute code back to +upstream.

+
+
push

Moving changes from your local copy to another copy

+
+
pull

Getting changes from another copy to your own copy. git pull +does this fetch, and also tries to automatically merge.

+
+
master

Default name for main branch on Git. Depending on the configuration and service, +the default branch is sometimes main. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

+
+
main

Default name for main branch on GitLab and GitHub. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

+
+
merge
merging

Bringing changes from one branch into another, either as a noun or +verb.

+
+
VS Code

A text editor and development environment by Microsoft. It’s quite +popular, partly because it is powerful and easy to use. VS +Codium is the same but without Microsoft +tracking.

+
+
+
+
+

Commands we use

+

Setup:

+
    +
  • git config: edit configuration options

  • +
  • git init -b main: create new repository with main as the default branch

  • +
+

See our status:

+
    +
  • git status: see status of files - use often!

  • +
  • git log: see history of commits and their messages, newest first

  • +
  • git graph: see a detailed graph of commits. Create this command +with git config --global alias.graph "log --all --graph --decorate --oneline"

  • +
  • git diff: show difference between working directory and last commit

  • +
  • git diff --staged: show difference between staging area and last commit

  • +
  • git show COMMIT: inspect individual commits

  • +
+

General work:

+
    +
  • git add FILE:

    +
      +
    • Add a new file

    • +
    • Add a file to staging

    • +
    +
  • +
  • git commit: record a version, add it to current branch

  • +
  • git commit --amend: amend our last commit

  • +
  • git branch: show which branch we’re on

  • +
  • git branch NAME: create a new branch called “name”

  • +
  • git restore FILE: restore last committed/staged version of FILE, losing unstaged changes

  • +
  • git switch --create BRANCH-NAME: create a new branch and switch to it

  • +
  • git revert HASH: create a new commit which reverts commit HASH

  • +
  • git reset --soft HASH: remove all commits after HASH, but keep their modifications as staged changes

  • +
  • git reset --hard HASH: remove all commits after HASH, permanently throwing away their changes

  • +
  • git merge BRANCH-NAME: merge branch BRANCH-NAME into current branch

  • +
  • git grep PATTERN: search for patterns in tracked files

  • +
  • git annotate FILE: find out when a specific line got introduced and by whom

  • +
  • git bisect: find a commit which broke some functionality

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/resources/index.html b/branch/main/resources/index.html new file mode 100644 index 00000000..f4c8d5d7 --- /dev/null +++ b/branch/main/resources/index.html @@ -0,0 +1,190 @@ + + + + + + + Other resources — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/branch/main/search/index.html b/branch/main/search/index.html new file mode 100644 index 00000000..bfb1ef09 --- /dev/null +++ b/branch/main/search/index.html @@ -0,0 +1,191 @@ + + + + + + Search — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/branch/main/searchindex.js b/branch/main/searchindex.js new file mode 100644 index 00000000..f851ca39 --- /dev/null +++ b/branch/main/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["aliases", "archaeology", "basics", "branches", "browsing", "commits", "configuration", "conflicts", "customizing", "exercises", "guide", "index", "interrupted", "level", "local-workflow", "merging", "motivation", "recovering", "reference", "resources", "sharing", "staging-area", "under-the-hood", "what-to-avoid"], "filenames": ["aliases.md", "archaeology.md", "basics.md", "branches.md", "browsing.md", "commits.md", "configuration.md", "conflicts.md", "customizing.md", "exercises.md", "guide.md", "index.md", "interrupted.md", "level.md", "local-workflow.md", "merging.md", "motivation.md", "recovering.md", "reference.md", "resources.md", "sharing.md", "staging-area.md", "under-the-hood.md", "what-to-avoid.md"], "titles": ["Aliases and configuration", "Inspecting history", "Basics", "Branching and merging", "Copy and browse an existing project", "Committing changes", "Configuring Git command line and editor", "Conflict resolution", "Customizing Git", "List of exercises", "Instructor guide", "Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version", "Interrupted work", "Practical advice: how much Git is necessary?", "Cloning a Git repository and working locally", "Merging changes and contributing to the project", "Motivation", "Undoing and recovering", "Quick reference", "Other resources", "How to turn your project to a Git repo and share it", "Using the Git staging area", "Git under the hood", "What to avoid"], "terms": {"learn": [0, 2, 3, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22], "most": [0, 1, 4, 5, 6, 7, 10, 11, 12, 14, 15, 17, 18, 21, 23], "common": [0, 4, 5, 10, 17, 23], "ar": [0, 1, 2, 3, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 20, 21, 22, 23], "you": [0, 2, 6, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23], "get": [0, 2, 4, 5, 6, 7, 9, 10, 13, 14, 15, 16, 17, 18, 20, 21, 23], "tire": 0, "type": [0, 1, 3, 4, 7, 9, 10, 12, 14, 15, 17, 20, 21, 22], "so": [0, 1, 2, 3, 5, 9, 10, 12, 13, 14, 18, 20, 21, 22, 23], "much": [0, 4, 8, 11, 12, 15, 16], "In": [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20, 21, 22, 23], "can": [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23], "defin": [0, 1, 3, 4, 5, 6, 9, 14, 18, 21], "shortcut": [0, 3, 14, 18], "These": [0, 2, 4, 6, 10, 18, 23], "great": [0, 2, 13, 16, 21], "becaus": [0, 2, 5, 7, 11, 12, 15, 18, 23], "thei": [0, 2, 3, 4, 5, 9, 10, 13, 15, 17, 21, 22], "save": [0, 2, 6, 9, 12, 13, 16, 21, 22], "time": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 21, 22], "But": [0, 1, 2, 3, 4, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 20, 21, 23], "": [0, 1, 2, 3, 4, 5, 7, 9, 10, 13, 15, 16, 18, 20, 21], "easi": [0, 1, 2, 4, 5, 8, 9, 10, 16, 17, 18, 20], "forget": [0, 2, 3, 5, 9, 15, 17], "them": [0, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 15, 16, 17, 21], "confus": [0, 2, 3, 10], "inconsist": 0, "your": [0, 1, 4, 6, 7, 8, 12, 13, 14, 16, 18, 21, 22, 23], "colleagu": [0, 7, 12, 16], "There": [0, 2, 3, 5, 6, 7, 9, 10, 12, 13, 15, 20, 23], "i": [0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 18, 23], "plenti": 0, "other": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22], "make": [0, 1, 2, 3, 4, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 20, 23], "nicer": 0, "offer": [0, 1, 4, 5, 9, 10, 11, 14, 15, 20], "wai": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 17, 21, 23], "improv": [0, 2, 3, 8, 9, 13, 17, 18, 23], "usabl": 0, "ci": 0, "instead": [0, 1, 2, 4, 6, 7, 17, 20, 23], "commit": [0, 7, 10, 11, 12, 15, 18, 19, 20, 22, 23], "base": [0, 2, 9, 11, 13, 14, 15, 22], "simpl": [0, 4, 9, 10, 11, 13, 20], "string": [0, 1, 22], "replac": [0, 2, 5, 6, 9, 14, 20, 21], "either": [0, 2, 9, 12, 17, 18, 20], "specif": [0, 1, 2, 5, 9, 10, 15, 17, 18], "repositori": [0, 3, 5, 6, 7, 10, 11, 12, 13, 16, 17, 18, 21, 22, 23], "global": [0, 2, 3, 6, 7, 9, 14, 18], "help": [0, 2, 7, 9, 10, 13, 16, 20, 21, 23], "do": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 20, 21, 22, 23], "thing": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 18, 21, 23], "across": [0, 9, 15], "project": [0, 1, 2, 3, 5, 7, 8, 10, 14, 16, 19, 21, 23], "per": [0, 19], "also": [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23], "creat": [0, 1, 6, 13, 16, 17, 18, 20, 21, 22], "store": [0, 2, 4, 9, 14, 20, 21, 22], "gitconfig": [0, 6, 10], "A": [0, 2, 3, 4, 5, 7, 9, 10, 13, 15, 17, 18, 19, 20, 21, 22], "veri": [0, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 20, 21, 22], "which": [0, 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 15, 16, 17, 18, 20, 21, 22, 23], "we": [0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 17, 20, 21, 22, 23], "lot": [0, 2, 9, 12, 16, 17, 23], "our": [0, 2, 3, 4, 5, 6, 10, 11, 14, 15, 18, 20], "workshop": [0, 2, 5, 10, 15, 16], "config": [0, 2, 3, 6, 7, 9, 10, 14, 18, 22], "log": [0, 1, 3, 4, 5, 6, 9, 14, 15, 17, 18, 20, 21, 22], "all": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23], "decor": [0, 3, 4, 5, 6, 14, 18], "onelin": [0, 1, 2, 3, 4, 5, 6, 9, 14, 15, 17, 18], "cd": [0, 1, 2, 3, 4, 7, 9, 22], "your_git_repositori": 0, "It": [0, 1, 2, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 23], "possibl": [0, 1, 2, 8, 9, 13, 14, 15, 16], "call": [0, 1, 2, 3, 4, 5, 6, 7, 9, 14, 15, 18, 20], "exclam": 0, "mark": [0, 5, 7, 13], "charact": [0, 2, 3, 22], "thi": [0, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23], "here": [0, 1, 2, 3, 5, 6, 8, 9, 10, 15, 17, 20, 21], "local": [0, 1, 2, 3, 4, 6, 10, 11, 15, 17, 18, 20], "synchron": 0, "remot": [0, 3, 6, 7, 9, 10, 11, 18], "hi": [0, 6], "echo": 0, "hello": 0, "how": [0, 2, 3, 5, 6, 7, 8, 10, 12, 15, 16, 17, 21, 22], "mani": [0, 1, 2, 6, 9, 10, 13, 15, 20, 21, 23], "should": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 14, 15, 17, 20, 21, 23], "wait": [0, 23], "befor": [0, 1, 2, 3, 4, 5, 7, 9, 10, 12, 13, 14, 15, 17, 18, 21, 23], "believ": 0, "gener": [0, 2, 9, 10, 13, 18, 23], "two": [0, 2, 3, 4, 6, 7, 10, 12, 14, 15, 16, 17, 20, 22], "letter": [0, 3], "acronym": 0, "welcom": [0, 4, 10], "reus": [0, 9, 11, 20], "suggest": [0, 2, 18], "see": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 14, 15, 17, 18, 20, 21, 22, 23], "current": [0, 1, 3, 5, 7, 9, 11, 12, 14, 15, 17, 18, 20, 21], "ap": 0, "add": [0, 2, 3, 4, 6, 7, 9, 10, 12, 13, 14, 15, 17, 18, 20, 21, 23], "patch": [0, 9, 12, 21], "br": 0, "branch": [0, 1, 2, 4, 10, 11, 18, 19, 20, 23], "v": [0, 5, 7, 9, 14, 15, 18, 20, 21], "cip": 0, "cl": 0, "clone": [0, 1, 3, 4, 6, 7, 10, 11, 12, 16, 18], "recurs": [0, 7, 22], "di": 0, "diff": [0, 5, 7, 10, 12, 18, 21], "dic": 0, "stage": [0, 2, 3, 7, 10, 11, 12, 14, 17, 18], "color": 0, "word": [0, 3, 4, 8, 9, 15, 16, 17], "diw": 0, "pager": [0, 8], "stat": [0, 2, 9], "fe": 0, "fetch": [0, 9, 14, 18], "rem": 0, "st": 0, "statu": [0, 1, 2, 7, 9, 10, 12, 14, 15, 17, 18, 21, 22], "su": 0, "submodul": 0, "updat": [0, 7, 10, 18, 23], "init": [0, 2, 6, 9, 10, 18, 20], "what": [0, 3, 4, 5, 7, 9, 10, 11, 12, 15, 17, 20, 21, 22], "select": [0, 1, 4, 6, 9, 14, 15, 17, 21], "part": [0, 2, 3, 5, 6, 7, 9, 15, 20], "individu": [0, 2, 18, 21], "interact": [0, 11, 14, 18], "obviou": [0, 23], "check": [0, 1, 2, 6, 7, 9, 10, 12, 15, 17, 20, 21, 22, 23], "option": [0, 4, 6, 14, 15, 17, 18, 20, 21], "clariti": [0, 6], "an": [0, 1, 2, 5, 6, 7, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 23], "topic": [0, 18], "area": [0, 2, 10, 11, 12, 13, 18, 22], "last": [0, 1, 7, 9, 12, 14, 15, 17, 18, 21], "about": [0, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 17, 20, 21, 22], "small": [0, 2, 13, 20, 21, 23], "chang": [0, 3, 6, 10, 11, 12, 13, 14, 18, 20, 21, 22, 23], "diffstat": 0, "file": [0, 1, 3, 4, 5, 6, 7, 9, 12, 14, 15, 16, 17, 18, 20, 21, 22, 23], "content": [0, 2, 7, 9], "show": [0, 1, 3, 4, 5, 6, 7, 10, 12, 14, 15, 16, 17, 18], "whole": [0, 2, 4, 10, 11], "some": [0, 1, 2, 3, 4, 5, 7, 10, 13, 15, 16, 17, 18, 21, 23], "u": [0, 1, 2, 3, 4, 5, 7, 9, 12, 15, 17, 20, 21, 22], "l": [0, 9, 20, 22], "set": [0, 2, 3, 6, 9, 10, 15, 16, 18, 20], "p": [0, 12, 13, 17, 21, 22], "singlekei": 0, "true": [0, 15, 23], "won": [0, 7], "t": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 14, 15, 16, 17, 20, 21, 22, 23], "explain": [0, 2, 7, 9, 10, 11, 21, 23], "bore": 0, "have": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 23], "want": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 20, 21], "go": [0, 1, 2, 3, 4, 5, 7, 9, 10, 15, 16, 17, 18, 20, 21, 22], "deeper": 0, "try": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 15, 16, 17, 20], "figur": [0, 2, 7, 14], "out": [0, 2, 3, 4, 5, 7, 9, 10, 13, 14, 16, 18, 21], "might": [0, 3, 4, 6, 7, 9, 12, 13, 14, 15, 17, 20], "manual": [0, 3, 7, 9, 10, 22], "page": [0, 1, 2, 4, 5, 6, 9, 18, 20, 23], "cif": 0, "fixup": 0, "rb": 0, "rebas": [0, 10, 12, 17], "autosquash": 0, "rbi": 0, "autostash": 0, "rec": 0, "upstream": [0, 7, 9, 15, 18], "head": [0, 2, 3, 5, 7, 9, 14, 17, 18, 21, 22], "ignor": [0, 23], "o": 0, "exclud": 0, "standard": [0, 4, 10], "new": [0, 1, 2, 3, 4, 6, 7, 9, 10, 13, 14, 15, 17, 18, 20, 21, 22, 23], "newd": 0, "newdi": 0, "reca": 0, "n10": 0, "recd": 0, "besid": 0, "ones": [0, 15, 21], "core": [0, 2, 6, 20], "less": [0, 1, 3, 7, 9, 12], "r": [0, 16, 22], "excludesfil": 0, "gitignor": [0, 9, 20, 23], "merg": [0, 4, 5, 8, 10, 11, 12, 13, 18, 23], "conflictstyl": 0, "diff3": 0, "wordregex": 0, "za": 0, "z0": 0, "9_": 0, "space": [0, 1, 5], "mnemonicprefix": 0, "copi": [0, 2, 5, 10, 11, 12, 14, 18, 20], "past": [0, 4, 9, 14, 17, 20], "name": [0, 1, 2, 3, 4, 5, 9, 12, 14, 15, 18, 20, 21], "like": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 17, 18, 20, 21, 22], "github": [0, 2, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18], "com": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 17, 20], "myusernam": 0, "url": [0, 1, 4, 5, 6, 9, 14], "insteadof": 0, "gh": 0, "usernam": [0, 4, 5, 6, 14], "ghu": 0, "Then": [0, 1, 3, 5, 7, 9, 14, 15, 17, 20, 22], "recip": [0, 3, 7, 9, 10, 14, 15, 17, 21], "automat": [0, 1, 2, 5, 7, 9, 14, 18, 23], "translat": [0, 1, 6], "prefix": 0, "match": [0, 4], "If": [0, 1, 2, 4, 5, 6, 9, 11, 13, 14, 15, 16, 17, 18, 20], "frustrat": [0, 15], "rememb": [0, 2, 3, 4, 6, 7, 9, 13, 14, 15, 17], "Be": [1, 3, 17, 20], "abl": [1, 2, 3, 6, 7, 9, 10, 11, 14, 15, 20], "why": [1, 2, 3, 9, 13, 22, 23], "wa": [1, 2, 3, 7, 9, 10, 13, 16, 17, 18, 23], "introduc": [1, 4, 9, 10, 16, 18], "quickli": 1, "behavior": [1, 2], "30": [1, 3, 10], "teach": [1, 2, 3, 7, 9, 11, 12, 13, 17, 21, 22], "along": [1, 3, 4, 7, 10, 12, 17, 21, 22], "As": [1, 2, 3, 9, 17, 18], "usual": [1, 4, 6, 14, 18], "power": [1, 9, 18, 20], "rel": [1, 2], "mai": [1, 2, 3, 5, 6, 7, 10, 13, 17, 23], "haven": [1, 2, 9, 10, 14, 15, 17, 23], "tri": [1, 9, 16, 18, 20], "yet": [1, 2, 5, 9, 10, 15, 17, 20], "d": [1, 3, 15], "recommend": [1, 2, 4, 5, 6, 10, 11, 14, 15], "give": [1, 2, 3, 4, 6, 7, 9, 10, 12, 15, 16, 21], "The": [1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 22, 23], "web": [1, 2, 6, 9, 11, 14, 16, 18, 20], "interfac": [1, 3, 5, 6, 9, 14, 20], "allow": [1, 8, 9, 11, 15], "done": [1, 2, 3, 4, 5, 7, 9, 10, 14, 15, 17, 20, 21, 23], "everyth": [1, 2, 7, 11, 12, 17, 21, 22], "easier": [1, 3, 5, 13, 14, 15, 23], "open": [1, 2, 4, 5, 7, 9, 14, 15, 16, 18, 20, 22], "termin": [1, 3, 4, 5, 6, 9, 11, 14, 16, 17, 20], "run": [1, 2, 3, 4, 7, 9, 10, 16, 17, 20, 21, 23], "first": [1, 2, 3, 4, 5, 7, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 22, 23], "demonstr": [1, 3, 4, 5, 8, 9, 10, 11, 14, 16], "few": [1, 3, 4, 8, 9, 10, 12, 13, 15, 16, 17, 20, 22, 23], "real": [1, 4, 9, 12, 20], "life": 1, "exampl": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21], "http": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 14, 16, 17, 20, 21], "networkx": [1, 9], "mention": [1, 2, 3, 9], "amaz": 1, "site": [1, 20], "program": [1, 2, 7, 18], "historian": 1, "later": [1, 2, 4, 5, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23], "practic": [1, 2, 3, 7, 10, 11, 14, 15, 16, 19], "below": [1, 2, 3, 4, 5, 7, 9, 10, 12, 14, 15, 16, 17, 20], "readm": [1, 2, 3, 5, 9, 17, 20], "rst": 1, "visit": [1, 2, 9], "brows": [1, 2, 10, 11, 13, 15, 16], "githistori": 1, "xyz": 1, "blob": [1, 22], "main": [1, 2, 3, 4, 6, 7, 9, 12, 13, 14, 15, 17, 18, 20, 22], "left": [1, 2, 3, 4, 5, 7, 9, 12, 14], "right": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 15, 20, 21, 22], "kei": [1, 6, 10, 21], "too": [1, 2, 3, 4, 10, 13, 23], "With": [1, 2, 3, 5, 9, 11, 12, 14, 16, 18], "grep": [1, 4, 8, 9, 18], "contain": [1, 2, 3, 9, 13, 14, 15, 17, 18, 20, 22], "regular": [1, 3], "express": 1, "where": [1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 21, 23], "variabl": [1, 4], "error": [1, 9, 16, 20], "messag": [1, 3, 4, 5, 9, 10, 14, 17, 18, 22, 23], "print": [1, 3, 5, 9, 12, 21], "describ": [1, 4, 5, 15, 17, 23], "abov": [1, 2, 4, 5, 7, 9, 12, 14, 15, 16, 17, 20, 21], "fixm": 1, "while": [1, 3, 9, 12], "state": [1, 2, 3, 7, 8, 9, 10, 12, 17, 18, 21, 22], "through": [1, 2, 6, 10, 11, 21], "sometext": 1, "got": [1, 2, 5, 9, 17, 18, 21], "remov": [1, 2, 3, 7, 9, 15, 17, 18, 20, 21, 23], "same": [1, 2, 3, 5, 7, 9, 10, 12, 14, 15, 16, 17, 18, 20, 21], "q": [1, 2, 10, 21], "repo": [1, 4, 10, 11, 14, 17], "3anetworkx": 1, "2fnetworkx": 1, "from": [1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 16, 18, 20, 21, 22, 23], "window": [1, 2, 4, 6, 9], "enter": [1, 4, 5, 6, 9, 14], "magnifi": [1, 4], "glass": 1, "sidebar": [1, 4, 5, 14, 15], "equival": [1, 4], "seen": [1, 2, 9, 17], "one": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21], "alreadi": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 17, 20, 23], "know": [1, 2, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 21], "its": [1, 6, 10, 20, 22], "hash": [1, 2, 3, 5, 9, 12, 14, 17, 18, 22], "For": [1, 2, 3, 5, 6, 9, 10, 14, 15, 17, 20, 22, 23], "instanc": [1, 3, 4, 7, 9, 14], "759d589bdfa61aff99e0535938f14f67b01c83f7": 1, "don": [1, 2, 3, 4, 5, 6, 7, 9, 14, 15, 16, 17, 20, 23], "built": 1, "everi": [1, 2, 4, 9, 10, 21], "singl": [1, 3, 4, 5, 9, 16, 17], "order": [1, 2, 9, 12, 21, 22], "extens": [1, 3, 4, 5, 14, 23], "timelin": [1, 4, 9], "view": [1, 3, 4, 5, 7, 8, 9, 10, 14, 15, 16], "under": [1, 2, 4, 5, 9, 11, 14, 20], "click": [1, 2, 4, 5, 9, 14, 15, 20], "detail": [1, 2, 3, 13, 18, 20], "who": [1, 6, 7, 9, 10, 11], "modifi": [1, 2, 7, 12, 14, 15, 21, 22], "precis": [1, 10, 15, 16], "each": [1, 2, 5, 6, 9, 10, 14, 21, 22], "incredibli": 1, "reproduc": [1, 10], "convert_matrix": 1, "py": [1, 9, 20], "longer": [1, 6, 13, 23], "than": [1, 2, 3, 4, 7, 9, 13, 16, 17, 20, 23], "screen": [1, 4, 14], "default": [1, 2, 4, 5, 9, 15, 18, 20], "scroll": [1, 15], "output": [1, 2, 4, 9, 14], "cycl": 1, "result": [1, 3, 7, 9, 10, 14, 16], "n": [1, 7, 9, 21], "next": [1, 2, 3, 4, 5, 9, 14, 15, 20, 21], "down": [1, 9, 15, 17], "quit": [1, 2, 9, 18, 20], "blame": [1, 4, 9, 10], "screenshot": [1, 2, 3, 9, 15, 16, 20], "seem": [1, 4, 5, 14], "need": [1, 2, 3, 4, 5, 6, 7, 9, 10, 13, 14, 15, 17, 20, 21, 22], "method": [1, 5, 6, 14], "now": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22], "trivial": 1, "affect": [1, 2, 10, 16, 17], "wrap": 1, "long": [1, 2, 3, 6, 7, 12, 14, 16, 17, 19, 21], "shorter": [1, 14], "auto": [1, 7, 9], "format": [1, 5], "tool": [1, 4, 7, 10, 21], "black": 1, "editor": [1, 2, 4, 7, 9, 11, 15, 16, 18, 20, 21, 22], "trail": 1, "whitespac": 1, "point": [1, 3, 5, 9, 14, 16, 17, 18, 20, 23], "mechan": [1, 10, 22], "old": [1, 9, 17], "switch": [1, 2, 3, 7, 9, 10, 12, 15, 17, 18, 22], "branchnam": [1, 3, 9, 17], "start": [1, 2, 3, 4, 5, 6, 7, 9, 13, 14, 15, 16, 20, 21, 22, 23], "onli": [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 20, 21, 23], "comment": [1, 3, 15, 23], "older": [1, 3, 7, 9, 17, 20], "347e6292419b": 1, "347e6292419bd0e4bff077fe971f983932d7a0e9": 1, "navig": [1, 4, 9, 14], "back": [1, 2, 3, 4, 5, 9, 10, 12, 14, 17, 18, 20, 21, 22, 23], "after": [1, 2, 3, 4, 7, 9, 10, 12, 14, 15, 18, 20], "delet": [1, 7, 9, 17, 22], "On": [1, 2, 3, 7, 9, 13, 14, 15, 17, 22], "version": [1, 2, 3, 4, 5, 6, 7, 9, 10, 14, 15, 17, 18, 20, 21, 23], "23": [1, 9], "checkout": [1, 3, 7, 9, 17, 21], "b": [1, 2, 7, 9, 17, 18, 20, 21], "somehash": [1, 9], "347e629": 1, "onc": [1, 3, 5, 7, 9, 10, 13, 15, 17, 19, 20, 21, 22, 23], "sourc": [1, 4, 5, 9, 14, 15, 16, 20], "control": [1, 2, 3, 4, 5, 7, 9, 10, 14, 15, 17, 18, 20, 23], "menu": [1, 9], "identifi": [1, 2, 4, 5, 9, 14, 16, 18, 20], "sure": [1, 2, 3, 4, 9, 10, 13, 14, 15, 16, 17, 20, 21], "look": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 21, 22], "let": [1, 2, 3, 5, 7, 9, 13, 14, 16, 17, 20, 21, 22, 23], "valu": [1, 9], "futur": [1, 2, 4, 9, 10, 13], "depend": [1, 4, 9, 14, 17, 18], "ok": [1, 9, 16, 17, 23], "complet": [1, 9, 12, 14, 17, 20, 23], "fulli": [1, 9, 13], "step": [1, 2, 3, 4, 5, 6, 10, 13, 14, 15, 20], "insid": [1, 2, 4, 6, 9, 14, 22], "anoth": [1, 2, 3, 4, 5, 10, 11, 14, 15, 18, 20, 21, 22], "outsid": [1, 9], "avoid": [1, 3, 9, 11, 15, 17], "fatal": [1, 9], "ani": [1, 2, 3, 4, 5, 7, 9, 13, 15, 16, 17, 18, 20, 23], "parent": [1, 3, 9, 22], "directori": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 16, 18, 20, 21, 22, 23], "tell": [1, 2, 3, 7, 9], "problem": [1, 3, 4, 9, 10, 16, 18, 21, 23], "sinc": [1, 2, 3, 4, 7, 9, 10, 14, 15, 16, 17, 20, 21, 23], "noth": [1, 2, 3, 7, 9, 22], "directli": [1, 2, 4, 5, 9], "work": [1, 2, 5, 6, 7, 10, 13, 15, 16, 17, 18, 20, 21, 22, 23], "well": [1, 2, 3, 7, 9, 11, 21], "6": [1, 7, 9, 12, 20], "3": [1, 20, 21, 22], "tag": [1, 9, 13, 14, 18, 22], "releas": [1, 2, 5, 9, 13], "tree": [1, 2, 9, 10, 22], "logic": [1, 9, 21], "degree_correl": [1, 9], "ad": [1, 3, 4, 5, 7, 9, 14, 15, 23], "actual": [1, 4, 5, 7, 9, 14, 15, 18, 21], "bring": [1, 9, 15, 18], "provid": [1, 4, 9, 12, 13, 15, 22], "encourag": [1, 2, 3, 4, 5, 9, 15], "algorithm": [1, 3, 9], "threshold": [1, 2, 9], "rdi": [1, 9], "mayb": [1, 3, 9, 23], "number": [1, 7, 9, 11], "follow": [1, 2, 3, 4, 5, 6, 7, 9, 14, 16, 17, 20], "90544b4fa": [1, 9], "unless": [1, 2, 3, 6, 7, 9, 14, 20], "compact": [1, 9], "access": [1, 2, 4, 6, 9, 18, 20], "just": [1, 2, 3, 4, 6, 9, 11, 13, 14, 15, 20, 21], "1": [1, 22], "am": [1, 16], "strang": 1, "sometim": [1, 3, 6, 7, 13, 14, 15, 17, 18, 23], "realiz": [1, 3, 7, 10, 17], "500": [1, 9], "ago": [1, 16], "doe": [1, 2, 3, 5, 6, 7, 9, 12, 14, 17, 18, 22, 23], "could": [1, 2, 4, 5, 9, 12, 23], "probabl": [1, 2, 6, 9, 10, 12, 16, 20, 23], "arriv": [1, 2, 9], "similar": [1, 2, 4, 5, 9, 11, 17, 20], "good": [1, 2, 3, 4, 9, 10, 11, 12, 13, 16, 17, 19, 20, 22], "f0ea950": 1, "broken": [1, 10], "compil": [1, 2, 3, 21, 23], "test": [1, 6, 15, 16, 23], "decid": [1, 7, 9, 14, 15, 17, 21], "whether": [1, 7, 10, 14, 15], "And": [1, 2, 3, 7, 9, 10], "iter": 1, "until": [1, 3, 6, 9, 10, 17], "reset": [1, 7, 9, 10, 18, 21], "even": [1, 3, 5, 7, 8, 9, 10, 11, 14, 20, 23], "script": [1, 9, 16], "write": [1, 6, 9, 10, 12, 17, 20], "return": [1, 2, 6, 10, 12, 15], "zero": [1, 4], "non": 1, "success": [1, 2, 13, 19], "failur": [1, 16], "begin": [1, 9, 21], "coderefineri": [1, 3, 4, 5, 7, 9, 10, 11, 14, 15], "motiv": [1, 2, 10, 11, 13], "bug": [1, 3, 9, 10, 16], "difficult": [1, 2, 9, 15, 16, 23], "visual": [1, 3, 6, 7, 10, 11, 14], "offend": [1, 9], "often": [1, 2, 3, 4, 5, 7, 9, 10, 12, 13, 16, 18, 19, 21, 23], "more": [1, 3, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23], "half": [1, 2, 3, 5, 9, 17], "debug": [1, 3, 9, 12, 21], "background": [1, 9], "get_pi": [1, 9], "approxim": [1, 9], "pi": [1, 9], "term": [1, 2, 4, 9, 10, 19, 22], "nilakantha": [1, 9], "seri": [1, 9], "produc": [1, 9], "14": [1, 2, 9], "57": [1, 9], "python": [1, 2, 3, 9], "At": [1, 3, 4, 9], "within": [1, 2, 9, 15, 18], "correctli": [1, 9], "task": [1, 5, 9, 12], "comput": [1, 3, 4, 9, 14, 20], "spoiler": [1, 9], "alert": [1, 9], "found": [1, 3, 9, 10, 16], "bonu": [1, 9], "correct": [1, 2, 9, 17, 20], "hint": [1, 2, 4, 5, 9, 10, 15], "tail": [1, 9], "tild": [1, 9], "combin": [1, 7, 10, 13, 15, 23], "except": [1, 2], "grasp": 2, "structur": [2, 3, 6, 10, 14], "inspect": [2, 3, 4, 7, 11, 17, 18, 21, 22], "35": [2, 10], "min": [2, 3, 7, 10, 12, 13, 16, 17, 21, 22], "40": [2, 3, 22], "system": [2, 7, 10, 16, 18], "folder": [2, 4, 9, 17, 20, 22], "over": [2, 4, 5, 10, 13, 14, 15, 18, 21, 23], "entir": [2, 5, 7, 14, 18, 19], "assign": [2, 10], "kept": 2, "sub": [2, 5], "keep": [2, 3, 7, 10, 15, 18, 21], "move": [2, 3, 5, 7, 9, 10, 11, 14, 17, 18, 21], "somewher": [2, 6, 16], "els": [2, 3, 7, 12, 13, 15, 16, 23], "still": [2, 5, 6, 7, 9, 10, 12, 15, 20], "doesn": [2, 5, 9, 12, 17, 22], "anyth": [2, 6, 9, 10, 15], "ask": [2, 9, 12, 14, 15, 16, 17], "multipl": [2, 4, 5, 10, 13, 14, 21], "exist": [2, 5, 6, 7, 10, 14, 16, 17, 18, 20], "take": [2, 4, 7, 9, 17, 20, 21], "request": [2, 10, 13, 18, 23], "txt": [2, 3, 7, 9, 21], "anotherfil": 2, "focu": 2, "think": [2, 3, 7, 9, 10, 15], "outcom": 2, "edit": [2, 3, 5, 7, 9, 18], "again": [2, 3, 5, 7, 9, 10, 12, 13, 15, 17, 21], "sever": [2, 3, 5, 7, 9, 11, 12, 21, 22], "end": [2, 3, 4, 5, 9, 10, 13, 21, 23], "perform": 2, "focus": 2, "scene": 2, "press": 2, "shutter": 2, "instal": [2, 6, 7, 9, 11], "instruct": [2, 3, 5, 6, 7, 9, 11, 14, 17, 21], "email": [2, 16], "address": [2, 9, 20, 21], "yournam": [2, 6], "nano": [2, 6], "defaultbranch": [2, 6], "verifi": [2, 3, 6, 7, 9, 14, 20, 22], "list": [2, 3, 4, 6, 11, 12, 14, 16, 17, 22, 23], "learner": [2, 10, 11], "enough": [2, 4, 5, 7, 11, 13, 15, 16], "initi": [2, 9, 20], "delici": 2, "inspir": [2, 3, 5, 10, 13, 16], "smith": 2, "carpentri": 2, "mail": 2, "cook": 2, "everybodi": 2, "relat": [2, 7, 9, 21], "written": [2, 19], "e": [2, 3, 7, 9, 10, 17], "g": [2, 3, 7, 9, 10, 17], "languag": 2, "pleas": [2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 20, 23], "lesson": [2, 3, 9, 11, 13, 15, 17, 18, 20, 21], "realli": [2, 3, 9, 10, 12, 13, 20, 23], "stuck": [2, 9, 10], "One": [2, 9, 10, 15, 16, 17, 18, 21], "principl": 2, "mkdir": 2, "That": 2, "empti": [2, 5, 9, 13, 20], "No": [2, 7, 9], "sens": [2, 5, 17], "inform": [2, 3, 4, 8, 9, 10, 15, 16, 17, 22], "dure": [2, 7, 9, 10, 13, 15, 23], "descript": [2, 9, 15, 20, 21, 22], "plu": [2, 9, 20], "symbol": [2, 4, 9, 20], "top": [2, 3, 4, 5, 7, 9, 12, 15, 16, 20, 21], "choos": [2, 9, 11, 14, 15, 20], "short": [2, 5, 9, 14, 20, 21], "final": [2, 5, 7, 9, 14, 20], "overview": [2, 5, 15], "md": [2, 3, 4, 5, 9, 14], "ingredi": [2, 3, 5, 7, 9, 17, 21], "avocado": [2, 3, 7, 9], "chili": [2, 3, 7, 9], "lime": [2, 3, 7, 9], "tsp": [2, 3, 7, 9], "salt": [2, 3, 5, 7, 9], "second": [2, 7, 13], "chop": 2, "onion": [2, 3, 5, 7, 9, 17], "squeez": [2, 9], "mix": [2, 5, 9, 21], "alwai": [2, 6, 10, 13, 14, 15, 16, 22], "safe": [2, 6, 7, 9, 13, 15, 17], "idea": [2, 3, 4, 9, 10, 13, 16, 17, 21, 22, 23], "when": [2, 3, 5, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23], "untrack": 2, "includ": [2, 9, 14, 17, 23], "present": [2, 10, 21, 22], "camera": 2, "consciou": 2, "decis": 2, "rm": [2, 9, 17, 23], "cach": 2, "unstag": [2, 7, 9, 18, 21], "readi": [2, 3, 15, 21, 22, 23], "m": [2, 3, 5, 9, 14, 20], "root": [2, 14], "f146d25": [2, 3, 9, 17], "insert": [2, 7], "mode": [2, 9, 10], "100644": [2, 7, 9], "queri": 2, "muscl": 2, "memori": 2, "third": 2, "flag": [2, 3, 9], "mean": [2, 3, 4, 5, 6, 7, 9, 10, 15, 17, 20], "versatil": [2, 3], "worri": [2, 22], "mind": [2, 3, 9, 12, 20], "read": [2, 6, 14], "doubt": [2, 7], "search": [2, 6, 9, 10, 16, 18], "onlin": [2, 9, 13, 16, 20], "find": [2, 3, 4, 5, 10, 14, 15, 16, 17, 18, 20, 22], "relev": [2, 9, 13], "thread": [2, 9, 20], "network": [2, 5, 9, 14, 15, 16], "connect": [2, 6, 10], "specifi": [2, 10, 14], "adjust": [2, 5, 13, 15], "howev": [2, 3, 16], "up": [2, 3, 6, 7, 9, 10, 11, 13, 14, 15, 16, 17, 20, 22, 23], "three": [2, 3, 4, 5, 6, 9, 14, 15, 20, 21], "enjoi": [2, 3, 5, 9, 17], "index": [2, 4, 7, 9, 10, 12, 22], "4422a31": [2, 9], "ba8854f": [2, 9], "7811273": [2, 9], "2b11074": [2, 9], "separ": [2, 3, 5, 9, 11, 12, 21], "happen": [2, 3, 5, 7, 9, 10, 12, 17, 20, 22], "leav": [2, 7, 9, 10, 14, 16, 20], "associ": [2, 9], "made": [2, 3, 9, 17, 18, 21, 22], "chanc": [2, 7, 9, 10, 11, 16], "ve": [2, 6, 9, 14, 22], "convinc": [2, 9], "self": [2, 9], "were": [2, 3, 9, 10, 12, 15, 22], "justifi": [2, 9, 17], "close": [2, 7, 9, 20], "experi": [2, 3, 5, 9, 16, 17], "modif": [2, 5, 7, 9, 10, 12, 17, 18, 21], "pen": [2, 9], "By": [2, 4, 9, 10, 15], "preview": [2, 4, 9, 15], "goal": [2, 3, 9, 11, 22], "e7cf023efe382340e5284c278c6ae2c087dd3ff7": [2, 3], "author": [2, 3, 4, 6, 9, 13, 16, 20, 22], "radovan": [2, 5, 14], "bast": 2, "norepli": [2, 6], "date": [2, 7], "sun": 2, "sep": 2, "17": [2, 9, 16, 20], "19": [2, 16], "12": [2, 9, 10, 20], "47": 2, "2023": [2, 3, 11, 16], "0200": 2, "79161b6e67c62ad4688a58c1e54183334611a390": 2, "32": 2, "a3394e39535343c4dae3bb4f703741a31aa8b78a": 2, "18": 2, "369624674e63de48055a65bf63055bd59c985d22": 2, "46": 2, "58": 2, "f146d25b94569a15e94d7f0da6f15d7554f76c49": 2, "52": [2, 22], "arbitrari": [2, 9], "hash1": [2, 9], "hash2": [2, 9], "develop": [2, 3, 5, 6, 9, 10, 13, 15, 18], "uniqu": [2, 4, 5, 14, 18], "label": [2, 3, 9, 15, 17, 21], "code": [2, 3, 5, 7, 9, 10, 12, 13, 14, 15, 17, 18, 20, 21, 23], "integ": 2, "count": [2, 9, 20], "revers": 2, "chronolog": 2, "newest": [2, 18, 21], "7": [2, 9, 12, 20], "necessari": [2, 11], "nice": [2, 3, 4, 6, 9, 14, 21], "been": [2, 3, 6, 9, 10, 12, 14, 15, 23], "differ": [2, 3, 4, 5, 7, 9, 10, 15, 16, 18, 20, 21, 22, 23], "between": [2, 3, 5, 7, 9, 10, 12, 15, 18, 21], "side": [2, 4, 5, 8, 9, 16], "further": [2, 9], "difftool": [2, 9], "requir": [2, 3, 4, 5, 6, 7, 9, 14], "linux": [2, 9], "meld": [2, 9], "maco": [2, 9], "opendiff": [2, 9], "notic": [2, 3, 7, 9, 23], "deepen": [2, 9], "both": [2, 3, 4, 5, 7, 9, 10, 14, 17, 21], "manag": [2, 3, 6, 7, 9, 18], "troubl": [2, 9], "shoot": [2, 9], "better": [2, 4, 5, 12, 13, 16, 21, 23], "import": [2, 4, 5, 6, 10, 13, 15, 16, 21, 23], "increas": [2, 7, 13, 23], "alpha": [2, 13], "0": [2, 3, 4, 5, 9, 13, 20, 22], "enabl": [2, 10, 13], "123": [2, 13], "convent": [2, 3, 13], "summar": [2, 13], "paragraph": [2, 13], "free": [2, 13], "form": [2, 3, 5, 12, 13, 15, 16, 22], "someth": [2, 3, 5, 6, 7, 9, 10, 12, 13, 15, 17, 18, 23], "ha": [2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 17, 18, 23], "cross": [2, 13], "refer": [2, 9, 10, 13, 15, 20, 21, 22, 23], "issu": [2, 7, 9, 10, 13, 18, 21], "bad": [2, 3, 7, 10, 12, 13, 16, 21], "fix": [2, 3, 5, 7, 9, 12, 13, 17, 21], "oop": [2, 13], "whatthecommit": [2, 13], "english": [2, 13], "understood": [2, 13], "15": [2, 10, 12, 13, 14, 15, 16, 20, 22], "year": [2, 10, 13, 16], "someon": [2, 7, 13, 16, 23], "Or": [2, 3, 7, 13, 14, 15, 16, 23], "me": [2, 3, 5, 13, 16], "50": [2, 10, 13], "peopl": [2, 4, 5, 7, 9, 10, 13, 15, 16, 17, 20, 23], "decad": [2, 13], "my": [2, 5, 8, 9, 13, 14, 16, 20], "favourit": [2, 13], "style": [2, 12, 13], "choic": [2, 6, 13, 21], "scipi": [2, 13], "numpi": [2, 13], "panda": [2, 13], "julia": [2, 13], "ggplot2": [2, 13], "flask": [2, 13], "design": [2, 4, 5, 13, 15, 18], "consid": [2, 13], "easili": [2, 4, 5, 6, 7, 10, 12, 13, 21], "changelog": [2, 13], "review": [2, 6, 13, 15, 16, 23], "especi": [2, 13, 23], "perfect": [2, 12, 13, 19, 23], "enemi": [2, 13], "binari": 2, "reason": [2, 4, 12, 13, 16, 23], "platform": [2, 11, 16, 18, 23], "thu": [2, 9, 15, 23], "contribut": [2, 3, 4, 6, 10, 11, 14, 16, 18, 23], "meaning": [2, 5, 14, 23], "although": [2, 23], "touch": [2, 9, 12, 17, 23], "pyc": 2, "__pycache__": 2, "taken": 2, "offici": 2, "document": [2, 3, 5, 9, 13, 16, 17], "archiv": 2, "anywher": 2, "oa": 2, "html": [2, 10], "foo": 2, "maintain": 2, "hand": 2, "build": [2, 4, 16], "shell": [2, 6, 10], "glob": 2, "syntax": [2, 8], "determin": 2, "pattern": [2, 5, 18], "lower": 2, "level": [2, 8, 22], "via": [2, 5, 9, 14, 20], "websit": [2, 9, 16, 20], "gui": 2, "desktop": 2, "sourcetre": 2, "parti": 2, "checkpoint": [2, 21], "undo": [2, 11, 13, 23], "uncommit": 2, "mv": 2, "renam": [2, 9, 20], "ideal": [2, 10], "larg": [2, 20, 23], "annex": 2, "would": [2, 3, 4, 7, 9, 10, 11, 13, 15, 17, 21], "myfil": [2, 9], "recent": [2, 9, 12, 18], "stori": [2, 3], "afraid": [2, 7, 10], "20": [3, 7, 10, 13], "previou": [3, 5, 11, 15, 16, 22], "section": [3, 6, 7, 9, 10, 14, 20], "track": [3, 4, 5, 9, 14, 15, 17, 18, 20, 23], "guacamol": [3, 5, 9], "git": [3, 4, 5, 10, 12, 15, 18, 19, 23], "had": [3, 14, 17], "come": [3, 4, 12, 14, 15, 18, 23], "linear": [3, 4, 9], "depict": 3, "littl": [3, 7, 9, 15], "box": [3, 7, 21], "abbrevi": 3, "posit": 3, "record": [3, 4, 5, 10, 18, 21, 22], "tape": 3, "sai": [3, 4, 5, 9, 15], "those": [3, 7, 9, 15, 20], "liter": [3, 17, 21], "isn": [3, 14, 17, 21], "placehold": [3, 9, 17, 20], "talk": [3, 7, 15], "imag": [3, 5, 16, 22], "us": [3, 5, 10, 11, 12, 14, 15, 16, 17, 20, 22, 23], "gopher": [3, 5, 16], "softwar": [3, 16], "least": [3, 9, 12, 17, 21], "expect": [3, 5, 7, 9, 14], "featur": [3, 7, 12, 13, 19, 21, 23], "concurr": 3, "unfinish": [3, 13, 20, 23], "line": [3, 5, 7, 10, 11, 12, 13, 15, 16, 18, 20, 21], "strength": 3, "permit": 3, "research": [3, 11], "isol": 3, "composit": 3, "master": [3, 5, 6, 9, 18, 20], "special": 3, "direct": [3, 10, 15, 22], "acycl": [3, 22], "graph": [3, 5, 6, 7, 9, 12, 16, 17, 18, 22], "arrow": [3, 9, 15, 20], "group": [3, 21, 23], "narr": 3, "strategi": [3, 10, 12], "sequenc": [3, 21], "extract": 3, "matrix": 3, "invers": 3, "without": [3, 4, 6, 7, 9, 10, 12, 14, 15, 16, 18, 20], "command": [3, 5, 7, 10, 11, 15, 17, 20], "alias": [3, 6, 11, 14, 18], "given": 3, "rest": 3, "ensur": 3, "collabor": [3, 4, 7, 9, 10, 11, 13, 15, 17, 20, 23], "histori": [3, 7, 11, 14, 16, 18, 20, 23], "e7cf023": [3, 9, 17], "79161b6": [3, 9, 17], "a3394e3": [3, 9, 17], "3696246": [3, 9, 17], "coupl": [3, 9, 14, 17, 22], "character": 3, "checksum": [3, 22], "pointer": [3, 18, 22], "afterward": 3, "togeth": [3, 4, 5, 7, 9, 15, 21, 23], "particip": [3, 10, 22], "episod": [3, 4, 5, 14, 15], "prefer": [3, 4, 6, 16], "browser": [3, 4, 5, 14, 16], "cilantro": [3, 4, 5, 7, 9], "text": [3, 7, 10, 15, 16, 18, 22], "case": [3, 4, 5, 7, 9, 10, 12, 14, 15, 16, 17, 20, 21], "2019": [3, 7, 16, 17], "clear": [3, 7, 10, 21], "tbsp": [3, 7], "reduc": [3, 5, 7, 9], "amount": [3, 5, 7, 9], "bit": [3, 7, 9, 12, 22], "bcb8b78": [3, 9], "f6ec7b7": [3, 9], "ahead": 3, "safer": [3, 9], "explicitli": [3, 9], "shown": [3, 4, 9, 15], "bf28166": [3, 9], "graphic": [3, 9, 10], "represent": [3, 9, 10], "situat": [3, 9, 17, 21], "b4af65b": [3, 9, 17], "comparison": [3, 9], "turn": [3, 10, 11, 14, 16], "appli": [3, 7, 9, 11], "skip": [3, 6, 7, 21], "origin": [3, 5, 6, 7, 9, 14, 18, 20], "helper": [3, 6, 7, 9], "un": [3, 7, 15], "wish": [3, 12, 17], "81fcc0c": 3, "intern": [3, 19], "attempt": 3, "incorpor": 3, "To": [3, 4, 7, 9, 10, 14, 20], "happi": [3, 7], "4e03d4b": [3, 7], "observ": [3, 7, 9, 14], "cat": [3, 7, 22], "overlap": 3, "user": [3, 4, 5, 6, 9, 13, 14, 15, 16, 20, 22, 23], "settl": 3, "conflict": [3, 8, 10, 11, 12, 23], "sticki": [3, 5, 15], "disappear": 3, "reintegr": 3, "insist": 3, "lost": [3, 17], "hard": [3, 4, 9, 10, 13, 15, 17, 18, 22], "advanc": [3, 4, 9, 12, 13, 15, 16], "absolut": 3, "postpon": [3, 7, 23], "month": [3, 7, 21, 23], "resolv": [3, 12, 17], "examin": [3, 9], "discuss": [3, 4, 9, 10, 11, 14, 15, 17, 18, 20], "ancestor": [3, 7, 9], "did": [3, 5, 7, 9, 14, 16, 21], "diverg": [3, 5, 9], "altern": [3, 4, 9, 14, 21], "replai": [3, 9], "explicit": [3, 9], "public": [3, 4, 9, 10, 15, 20], "alter": [3, 9], "contrast": 3, "ever": [3, 10, 21], "commemor": 3, "plaqu": 3, "particular": [3, 5, 10], "mileston": [3, 13], "semant": [3, 7], "v1": [3, 5], "64441c1934def7d91ff0b66af0795749d5f1954a": 3, "basic": [3, 5, 10, 11, 12, 15, 16, 23], "annot": [3, 4, 9, 10, 16, 18], "lightweight": [3, 22], "cryptograph": 3, "sign": [3, 5, 14], "gpg": 3, "timestamp": 3, "attach": [3, 5], "nobel": 3, "banquet": 3, "pro": [3, 19, 22], "book": [3, 4, 5, 9, 10, 14, 15, 19, 22], "chapter": 3, "subject": 3, "paus": 3, "moment": [3, 22], "recapitul": 3, "unmerg": [3, 7], "combo": [3, 9], "frequent": 3, "wild": [3, 23], "throw": [3, 17, 18], "awai": [3, 12, 17, 18, 22], "gone": [3, 9, 15, 16, 17], "off": [3, 9, 12], "job": [3, 9], "divis": 3, "unit": [3, 13], "understand": [4, 5, 7, 10, 15, 22], "piec": 4, "own": [4, 5, 6, 9, 11, 14, 15, 16, 17, 18, 20], "scratch": 4, "abstract": 4, "ll": [4, 5, 17], "cool": 4, "stuff": [4, 17, 21], "cours": [4, 10, 22], "big": [4, 23], "pictur": 4, "bunch": 4, "path": [4, 5, 7, 9, 12, 14, 15, 17, 20, 23], "dai": [4, 5, 13, 15, 16], "comfort": [4, 10, 11], "jupyt": 4, "rstudio": 4, "collect": [4, 18], "organ": [4, 21], "becom": [4, 10, 15, 17], "visibl": [4, 5], "stream": [4, 10], "button": [4, 5, 9, 14, 15, 20], "toward": [4, 9, 15], "shortli": 4, "redirect": [4, 9, 20], "your_user_nam": 4, "awar": [4, 5, 8, 14], "tab": [4, 5, 9, 14], "ye": [4, 7, 9, 12], "trust": 4, "somewhat": 4, "applic": 4, "bash": [4, 8, 10], "ssh": [4, 9, 14, 20], "setup": [4, 5, 14, 15, 18, 20], "team": [4, 14], "session": 4, "account": [4, 6, 9, 11, 20], "explor": [4, 22], "prepar": [4, 9, 10, 21], "question": [4, 9, 10, 16, 23], "insight": [4, 5, 9, 14], "filter": [4, 9], "licens": [4, 5, 9, 20, 22], "goe": [4, 5, 14, 15], "answer": [4, 5, 14, 15, 16], "aren": [4, 5, 15], "554c187": [4, 5, 18], "bottom": [4, 5, 9, 14, 15, 21], "saw": [4, 5], "hover": 4, "dot": [4, 5, 14, 15, 17], "person": [4, 7, 10, 13, 15, 18], "correspond": [4, 21], "alia": [4, 10, 14, 18], "configur": [4, 7, 9, 10, 11, 16, 18, 20], "filenam": [4, 5, 12], "accord": 4, "five": [4, 21], "2024": [4, 11], "03": [4, 21], "07": [4, 21], "occurr": 4, "function": [4, 5, 7, 10, 18], "class": 4, "context": [4, 8, 12, 13], "minut": 4, "keyword": 4, "continu": [4, 7, 9, 12, 15], "usag": 4, "c": [4, 21], "insensit": 4, "unfortun": 4, "histor": 4, "meant": [4, 7, 9, 15], "anyon": [4, 9, 17], "slightli": [4, 7, 9], "creativ": 4, "domain": 4, "condit": [4, 9, 17], "commun": [4, 7], "propos": [4, 15, 18], "owner": 4, "accept": [4, 13], "support": 5, "snapshot": [5, 14], "certain": [5, 7, 12, 14, 23], "note": [5, 6, 9, 23], "locat": [5, 9, 14, 21, 22], "templat": [5, 10], "markdown": 5, "matter": [5, 17], "verb": [5, 18], "upper": [5, 14], "nut": 5, "appear": [5, 7, 14], "brief": [5, 14], "pencil": 5, "icon": [5, 9, 20], "repeat": [5, 7, 9, 14, 21], "summari": 5, "shouldn": [5, 9, 15], "selector": [5, 14, 15], "normal": [5, 14], "prompt": [5, 6, 14], "didn": 5, "b4de93b": 5, "spring": 5, "poke": [5, 14, 22], "dc5d6f0": 5, "chocol": 5, "b4035e3": 5, "alex": [5, 14], "fruit": [5, 14], "salad": [5, 14], "89d5ef9": 5, "3bd2468": 5, "8bcb766": 5, "todo": 5, "b950c5c": 5, "capit": 5, "d18035e": 5, "7051cca": 5, "ae19e81": 5, "categori": 5, "a6fe629": 5, "30b89c4": 5, "fd12dc1": 5, "lasagna": [5, 14], "7753d43": 5, "vegetarian": 5, "aa0473": 5, "1e5a24a": 5, "5aa6687": 5, "oh": [5, 8, 16], "forgot": [5, 15, 17, 21], "cc84e4f": 5, "9500901": 5, "classic": [5, 6], "pumpkin": 5, "pie": 5, "yum": 5, "34ce939": 5, "draft": [5, 15], "pasta": 5, "far": [5, 10], "28e5f26": 5, "mushroom": 5, "soup": 5, "a550963": 5, "f2d6d58": 5, "1fde064": 5, "4c1873e": 5, "2992443": 5, "cc0": 5, "084a1ea": 5, "almost": [5, 7, 9, 10, 12], "switcher": 5, "version1": 5, "version2": 5, "around": [5, 9, 15], "addit": [5, 7, 9, 12, 20, 23], "metadata": 5, "purpos": [5, 15], "interchang": 5, "manuscript": [5, 16], "pre": [5, 7], "interfer": 5, "stick": [5, 11, 21], "cost": 5, "signific": 5, "disk": 5, "integr": 6, "environ": [6, 18], "home": [6, 21], "carri": 6, "your_github_usernam": 6, "nobodi": [6, 9, 16, 17], "theori": 6, "data": [6, 7, 9, 12, 15, 16, 20, 22], "registr": 6, "ident": 6, "place": [6, 12, 18, 21], "secur": 6, "protocol": 6, "credenti": 6, "extra": [6, 9, 12], "mac": 6, "successfulli": 6, "yourself": [6, 9, 14, 20, 23], "guid": [6, 11, 14, 19], "process": [6, 9, 18], "suffici": 7, "imagin": [7, 17], "somebodi": [7, 15, 16], "smooth": 7, "fast": 7, "forward": 7, "portion": [7, 15, 16, 17], "silent": 7, "overwrit": [7, 9, 20], "scari": 7, "luckili": 7, "rare": [7, 21], "meet": 7, "simpli": 7, "kind": [7, 16], "measur": 7, "declar": 7, "minor": 7, "revis": 7, "spell": 7, "rewrit": 7, "solv": [7, 9, 10, 21], "demo": 7, "decreas": 7, "dislik": [7, 9], "e83294b": 7, "6cacd50": 7, "4": [7, 20, 21, 22], "6484462": 7, "3caa632": 7, "fail": [7, 9], "marker": [7, 9, 15], "cc": [7, 22], "0000000": 7, "10": [7, 10, 12, 14, 15, 20, 21, 22], "care": [7, 17], "exactli": [7, 9, 10], "emac": 7, "plugin": 7, "fill": 7, "banch": [7, 9], "5": [7, 12, 16, 21, 22], "link": [7, 9, 18, 20, 22], "assum": [7, 9, 14, 15, 17], "anticip": [7, 9, 16, 21], "inde": [7, 9], "disagre": [7, 9], "stop": [7, 9, 23], "middl": [7, 9, 12, 21], "backup": [7, 9, 10, 14, 16, 20], "temporari": [7, 9, 12], "clean": [7, 9, 16, 22], "f": [7, 9], "keepbackup": [7, 9], "fals": [7, 9], "xour": 7, "xtheir": 7, "plan": [7, 13, 14], "put": [7, 9, 12, 21], "unrel": [7, 9, 12, 13, 21, 23], "live": [7, 15, 21], "layout": [7, 23], "caus": 7, "modular": 7, "risk": [7, 23], "technic": 7, "share": [7, 10, 14, 16, 17], "earli": [7, 10, 13, 23], "circumst": 7, "everyon": [7, 10, 15], "selfish": 7, "push": [7, 9, 10, 14, 15, 17, 18, 20], "best": [7, 19], "pull": [7, 10, 13, 14, 18, 20, 23], "handl": 7, "compar": [7, 10, 13, 15, 16, 21], "servic": [7, 11, 18, 20], "googl": 7, "drive": 7, "optim": [7, 10], "displai": 8, "contextu": 8, "jimeh": 8, "ohmyz": 8, "sh": 8, "zsh": 8, "fish": 8, "magicmonti": 8, "delta": [8, 9, 20], "highlight": 8, "mainli": 9, "instructor": [9, 11], "event": 9, "cover": [9, 15], "subset": 9, "interest": [9, 15], "sound": [9, 12, 16], "discov": [9, 16], "receiv": 9, "fork": [9, 14, 15, 18], "titl": [9, 15], "target": [9, 14, 15], "central": [9, 15], "mostli": [9, 15], "complex": [9, 15, 21], "workflow": [9, 11, 19], "toolbox": 9, "broke": [9, 16, 18], "myproject": [9, 16, 20], "repres": [9, 20], "gitlab": [9, 10, 11, 16, 18], "upload": [9, 20], "publish": [9, 10, 16, 19], "never": [9, 10, 12, 17, 20, 22, 23], "chose": [9, 20], "login": [9, 20], "oauth": [9, 20], "consist": [9, 18, 20], "rw": [9, 20, 22], "19k": [9, 20], "mar": [9, 20], "36": [9, 20], "21": [9, 16, 20, 22], "myscript": [9, 20], "28": [9, 20], "none": [9, 20], "green": [9, 15, 20], "red": [9, 20], "execut": [9, 20], "possibli": [9, 15, 17, 20], "enumer": [9, 20], "object": 9, "100": [9, 20], "compress": [9, 20], "08": [9, 10, 20], "kib": [9, 20], "mib": [9, 20], "total": [9, 20], "pack": [9, 20, 21], "reload": [9, 20], "troubleshoot": [9, 20], "explan": [9, 20], "ran": [9, 20], "recoveri": [9, 17, 20], "prevent": [9, 10, 20, 23], "accident": [9, 17, 20, 23], "forc": [9, 17, 20], "danger": [9, 13, 20], "brand": [9, 20], "fine": [9, 20], "abort": [9, 12, 17, 21], "unmodifi": [9, 21], "keystrok": [9, 21], "re": [9, 10, 18, 21], "benefici": [9, 21], "feel": [9, 10, 11, 14, 21], "regret": [9, 21], "newli": [9, 17], "incomplet": [9, 17], "typo": [9, 17], "unsatisfactori": [9, 17], "amend": [9, 17, 18], "d3fc63a": [9, 17], "e02efcd": [9, 17], "forev": [9, 17], "alright": [9, 17], "extraordinari": [9, 17], "sensit": [9, 17], "secret": [9, 17], "pop": [9, 12], "twice": [9, 12], "opposit": [9, 12, 17, 21], "deci": [9, 12], "ref": [9, 12, 22], "exercis": [10, 11, 22], "preserv": 10, "mirror": 10, "trigger": 10, "ce": 10, "09": [10, 16], "00": 10, "soft": [10, 18, 21], "icebreak": 10, "25": [10, 15, 17, 22], "break": [10, 13], "11": 10, "60": 10, "13": 10, "resolut": [10, 11, 15, 17], "feedback": [10, 15], "tomorrow": 10, "advic": [10, 11], "alon": [10, 21], "industri": 10, "high": [10, 11, 16, 23], "encount": 10, "disast": 10, "mistak": [10, 17], "roll": 10, "parallel": 10, "toe": 10, "exact": 10, "major": 10, "extent": 10, "lack": 10, "mental": 10, "model": [10, 16, 19, 22], "oper": 10, "newcom": 10, "valuabl": 10, "craft": [10, 21], "incorrect": 10, "emphas": 10, "effici": [10, 19], "avail": [10, 21], "bisect": [10, 18], "anybodi": 10, "rather": [10, 13, 21], "involv": 10, "wonder": 10, "whom": [10, 18], "behav": 10, "incorrectli": 10, "earlier": 10, "screencast": 10, "modul": [10, 11], "forgotten": 10, "expand": 10, "stash": [10, 13], "info": [10, 22], "anytim": 10, "etc": [10, 22], "cheat": 10, "sheet": 10, "www": 10, "ndpsoftwar": 10, "dir": 10, "diagram": 10, "student": 10, "sampl": 10, "infrequ": 10, "constantli": 10, "imposs": 10, "lose": [10, 12, 13, 18, 22], "highli": 10, "bashrc": 10, "februari": [11, 16], "march": 11, "rewrot": 11, "ground": [11, 21], "introductori": 11, "concept": [11, 18], "obsess": 11, "materi": 11, "bitbucket": [11, 16, 20], "transfer": 11, "implicitli": 11, "endors": 11, "compani": 11, "chosen": 11, "popular": [11, 16, 18, 20], "host": 11, "recov": [11, 13], "interrupt": 11, "hood": 11, "quick": [11, 23], "custom": 11, "resourc": 11, "pdf": 11, "panick": 12, "fresh": 12, "beauti": 12, "world": 12, "chaotic": [12, 23], "jackson": 12, "pollock": 12, "spree": 12, "27": 12, "everywher": [12, 23], "ruin": 12, "easiest": 12, "temporarili": 12, "drop": 12, "whichev": 12, "stack": [12, 17], "batch": 12, "resum": 12, "overlook": 12, "week": [12, 23], "2": [13, 18, 20, 22], "faster": 13, "converg": 13, "typic": 13, "untest": 13, "unsur": [13, 14], "protect": 13, "otherwis": 13, "split": [13, 18, 21, 23], "smaller": 13, "size": [13, 23], "huge": [13, 17, 23], "imperfect": 13, "simplifi": [13, 16], "repair": 13, "fit": 13, "grow": [13, 23], "beginn": 13, "input": 13, "introduct": [14, 15, 20], "download": 14, "full": 14, "activ": [14, 23], "conceptu": 14, "familiar": [14, 22], "yesterdai": 14, "authent": 14, "argument": 14, "anymor": [14, 15], "vari": 14, "somehow": [15, 21], "effect": 15, "equal": 15, "donat": 15, "send": [15, 16, 18], "permiss": [15, 18], "Not": [15, 23], "human": 15, "confid": 15, "watch": 15, "Being": 15, "basi": 15, "themselv": 15, "advoc": 16, "distribut": [16, 20], "recogn": 16, "hopefulli": [16, 22], "latest": [16, 17], "paper": 16, "laptop": 16, "thesi": 16, "interf": 16, "discard": [16, 21], "indic": 16, "src": 16, "util": 16, "time_iso8601": 16, "august": 16, "permalink": 16, "plain": 16, "suitabl": 16, "latex": 16, "quarto": 16, "zip": 16, "2020": [16, 21], "2021": 16, "myvers": 16, "newfeatur": 16, "despit": 16, "benefit": 16, "honest": 16, "worth": 16, "career": 16, "skill": 16, "worst": 16, "server": [16, 18, 20], "offlin": 16, "subvers": 16, "mercuri": 16, "pijul": 16, "undon": 17, "perman": [17, 18], "retriev": [17, 22], "unlik": 17, "xkcd": [17, 19], "comic": 17, "impli": [17, 21], "1597": 17, "mess": 17, "overflow": 17, "guru": 17, "sim": 17, "resouc": 17, "restor": [17, 18, 21], "remain": 17, "went": 17, "cherri": 17, "pick": [17, 21], "oldest": 17, "wrongli": 17, "recal": 18, "implement": [18, 21, 22], "noun": 18, "workspac": 18, "md5": 18, "sha1": 18, "roughli": 18, "hold": 18, "properti": 18, "itself": 18, "microsoft": 18, "partli": 18, "codium": 18, "revert": 18, "scott": 19, "chacon": 19, "ben": 19, "straub": 19, "peepcod": 19, "mid": 19, "finish": 20, "findabl": 20, "commerci": 20, "univers": 20, "privat": 20, "notabug": 20, "truli": 20, "condid": 20, "citabl": 20, "persist": 20, "pid": 20, "doi": 20, "publicli": 20, "zenodo": 20, "demystifi": 21, "came": [21, 23], "stand": 21, "hardli": 21, "advantag": 21, "disadvantag": 21, "b135ec8": 21, "6f0d49f": 21, "fee1807": 21, "6fe2f23": 21, "ab990f4": 21, "miscellan": 21, "bf39f9d": 21, "45831a5": 21, "bddb280": 21, "72d78e7": 21, "72e0211": 21, "61dd3a3": 21, "bugfix": 21, "49dc419": 21, "wip": 21, "progress": 21, "1949dc4": 21, "04": 21, "a361dd3": 21, "06": 21, "1172e02": 21, "e772d78": 21, "02": 21, "spread": 21, "simplest": 21, "y": 21, "blank": 21, "sort": 21, "shot": 21, "analogi": 21, "shop": 21, "receipt": 21, "wouldn": 21, "item": 21, "bathroom": 21, "kitchen": 21, "room": 21, "seal": 21, "dev": 21, "sublimegeek": 21, "im": 21, "1anh": 21, "bui": 21, "pai": 21, "ineffici": 21, "annoi": 21, "basket": 21, "conveyor": 21, "belt": 21, "importantli": 21, "flexibl": 21, "extrem": 22, "drwxr": 22, "xr": 22, "x": 22, "aug": 22, "51": 22, "499": 22, "commit_editmsg": 22, "92": 22, "73": 22, "hook": 22, "137": 22, "fact": 22, "previous": 22, "wrote": 22, "referenc": 22, "sha": 22, "hexadecim": 22, "BY": 22, "ca": 22, "digest": 22, "raw": 22, "lift": 22, "aha": 22, "underli": 22, "41": 22, "54": 22, "045e3db14740c60684d745e5fb891ae71e335611": 22, "replic": 22, "cp": 22, "gotcha": 23, "ugli": 23, "ish": 23, "harder": 23, "wors": 23, "meantim": 23, "largest": 23, "counterpoint": 23, "phase": 23, "ambiti": 23, "card": 23, "engin": 23, "safeguard": 23, "restrict": 23, "loop": 23, "significantli": 23, "subsequ": 23, "detect": 23, "autom": 23, "season": 23, "miss": 23}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"alias": 0, "configur": [0, 2, 6, 14], "object": [0, 1, 2, 3, 4, 5, 7, 12, 14, 15, 16, 17, 20, 21, 22], "exampl": 0, "alia": [0, 3, 6], "git": [0, 1, 2, 6, 7, 8, 9, 11, 13, 14, 16, 17, 20, 21, 22], "graph": [0, 4, 10, 14], "us": [0, 1, 2, 4, 6, 7, 8, 9, 13, 18, 21], "extern": 0, "command": [0, 1, 2, 4, 6, 9, 14, 18, 21], "food": 0, "thought": 0, "when": [0, 1, 4, 7, 9], "list": [0, 9], "instructor": [0, 1, 2, 3, 4, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22], "advanc": [0, 2], "keypoint": [0, 2, 3, 7, 12, 13, 21], "inspect": [1, 9, 10], "histori": [1, 2, 4, 9, 10, 17, 21], "note": [1, 2, 3, 4, 7, 8, 12, 13, 14, 15, 16, 17, 20, 21, 22], "line": [1, 2, 4, 6, 9, 14], "github": [1, 3, 4, 6, 14, 20], "v": [1, 4, 6], "code": [1, 4, 6, 16], "our": [1, 7, 9, 17], "toolbox": 1, "warm": 1, "up": 1, "browser": [1, 2, 9], "search": [1, 4], "text": [1, 6], "pattern": 1, "repositori": [1, 2, 4, 9, 14, 15, 20], "individu": 1, "commit": [1, 2, 3, 4, 5, 6, 9, 13, 14, 17, 21], "annot": 1, "metadata": [1, 6], "discuss": [1, 2, 5, 7, 13, 16, 21, 22, 23], "past": 1, "exercis": [1, 2, 3, 4, 5, 7, 9, 12, 14, 15, 17, 20, 21], "explor": [1, 9], "basic": [1, 2, 4, 9, 22], "archaeologi": [1, 9], "20": [1, 5, 9, 15], "min": [1, 4, 5, 9, 14, 15, 20], "solut": [1, 2, 3, 4, 5, 7, 9, 12, 14, 15, 16, 17, 21], "find": [1, 9, 11], "out": [1, 15], "someth": 1, "broke": 1, "chang": [1, 2, 4, 5, 7, 9, 15, 16, 17], "bisect": [1, 9], "how": [1, 4, 9, 11, 13, 14, 20], "would": 1, "you": [1, 3, 4, 5, 7, 12], "solv": 1, "thi": [1, 9, 10, 17], "option": [1, 2, 3, 7, 9, 11, 12], "2": [1, 2, 3, 4, 5, 7, 9, 10, 12, 14, 15, 17, 21], "bad": [1, 9], "summari": [1, 2, 3, 4, 14, 15], "what": [2, 13, 14, 16, 23], "i": [2, 3, 13, 14, 16, 17, 20, 21, 22], "record": [2, 9], "snapshot": [2, 16], "question": 2, "more": [2, 4, 8], "particip": 2, "type": 2, "along": 2, "track": [2, 11, 16], "guacamol": [2, 4], "recip": [2, 4, 5], "creat": [2, 3, 4, 5, 7, 9, 10, 12, 14, 15], "ad": [2, 17], "file": 2, "1": [2, 3, 4, 5, 7, 9, 10, 12, 14, 15, 17, 21], "log": [2, 10], "compar": [2, 4, 5, 9, 14], "show": [2, 9], "3": [2, 3, 4, 5, 7, 9, 14, 15, 17], "visual": [2, 9, 17], "diff": [2, 8, 9], "tool": [2, 9, 16], "4": [2, 3, 4, 5, 9, 14, 15, 17], "write": [2, 13], "messag": [2, 6, 13], "ignor": 2, "path": 2, "gitignor": 2, "graphic": 2, "user": 2, "interfac": 2, "5": [2, 3, 4, 5, 9, 14, 15], "test": [2, 3, 9, 17], "your": [2, 3, 5, 9, 10, 11, 15, 17, 20], "understand": [2, 3, 9, 17], "branch": [3, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 22], "merg": [3, 7, 9, 14, 15, 16, 17], "motiv": [3, 9, 16], "an": [3, 4, 9, 11, 21], "import": 3, "work": [3, 4, 9, 11, 12, 14], "It": [3, 17], "possibl": [3, 17], "directli": 3, "If": [3, 7], "got": [3, 7], "stuck": [3, 7], "abov": 3, "join": [3, 7], "later": [3, 7], "delet": [3, 15], "safe": 3, "perform": [3, 9, 21], "fast": [3, 9], "forward": [3, 9], "rebas": [3, 7, 9], "instead": [3, 9], "tag": [3, 5], "typic": [3, 16], "workflow": 3, "copi": [4, 9], "brows": [4, 5, 9, 14], "exist": [4, 9, 11], "project": [4, 9, 11, 13, 15, 20], "fork": [4, 5], "25": [4, 9, 14, 20], "walk": [4, 5, 14, 15], "through": [4, 5, 14, 15], "network": 4, "wa": 4, "last": 4, "modifi": [4, 5, 9, 11, 17], "mani": 4, "did": 4, "receiv": 4, "which": 4, "includ": 4, "ingredi": 4, "salt": 4, "instantan": 4, "6": [4, 5, 14, 15], "who": 4, "each": [4, 13], "7": [4, 5, 14, 15], "can": 4, "yourself": 4, "ar": [4, 5, 7, 14], "allow": 4, "share": [4, 9, 11, 20], "modif": 4, "8": [4, 5, 14], "issu": 4, "pull": [4, 9, 15, 17], "request": [4, 9, 15], "upstream": 4, "background": [5, 15], "practic": [5, 9, 13], "make": [5, 9, 21], "sure": 5, "add": 5, "new": 5, "switch": [5, 14], "main": 5, "just": 5, "made": 5, "two": [5, 9, 21], "arbitrari": 5, "renam": 5, "9": 5, "editor": [6, 14], "name": 6, "email": 6, "address": [6, 22], "default": 6, "authent": 6, "ssh": 6, "http": 6, "conflict": [7, 9, 15, 17], "resolut": [7, 9], "why": [7, 10, 11, 16], "thei": 7, "good": 7, "The": [7, 21], "human": 7, "side": 7, "prepar": 7, "previous": 7, "step": [7, 9, 21], "resolv": [7, 9, 15], "anoth": [7, 9, 16], "mergetool": [7, 9], "theirs": 7, "strategi": 7, "abort": 7, "avoid": [7, 23], "custom": 8, "shell": 8, "prompt": 8, "output": 8, "contribut": [9, 15], "clone": [9, 14], "local": [9, 14], "turn": [9, 20], "repo": [9, 20], "stage": [9, 13, 21], "area": [9, 21], "interact": [9, 21], "undo": [9, 17], "recov": [9, 17], "revert": [9, 17], "previou": [9, 17], "destroi": [9, 17], "experiment": [9, 17], "episod": [9, 11, 17], "interrupt": [9, 12], "stash": [9, 12], "some": [9, 12], "uncommit": [9, 12, 17], "guid": 10, "privaci": 10, "schedul": 10, "dai": 10, "we": [10, 11, 14, 16, 18], "teach": 10, "lesson": 10, "intend": 10, "learn": 10, "outcom": 10, "live": 10, "better": 10, "than": 10, "read": 10, "websit": 10, "materi": 10, "separ": 10, "window": 10, "cheatsheet": [10, 18], "board": 10, "draw": 10, "repeat": 10, "follow": 10, "point": 10, "start": [10, 11], "from": [10, 14, 17], "ident": 10, "environ": 10, "introduct": 11, "version": [11, 16], "control": [11, 16], "want": [11, 12], "go": 11, "back": [11, 16], "time": 11, "prerequisit": 11, "get": [11, 12], "studi": 11, "balanc": 11, "older": 11, "refer": [11, 18], "about": [11, 13, 16], "frequent": 12, "situat": 12, "store": 12, "variou": 12, "junk": 12, "don": 12, "t": 12, "need": [12, 16], "rid": 12, "advic": 13, "much": 13, "necessari": 13, "level": 13, "complex": 13, "larg": 13, "should": 13, "remot": [14, 20], "them": 14, "navig": 15, "begin": 15, "process": 15, "fill": 15, "verifi": 15, "origin": 15, "demonstr": [15, 22], "all": 16, "keep": 16, "do": 16, "featur": 16, "roll": 16, "collabor": 16, "reproduc": 16, "talk": 16, "like": 16, "difficulti": 16, "almost": 17, "alwai": 17, "nice": 17, "resourc": [17, 19], "simul": 17, "oper": 17, "recent": 17, "unstag": 17, "preserv": 17, "rewind": 17, "reset": 17, "wrong": 17, "after": 17, "quick": 18, "other": [18, 19], "glossari": 18, "put": 20, "softwar": 20, "gitlab": 20, "publish": 20, "tell": 21, "stori": 21, "under": 22, "hood": 22, "down": 22, "rabbit": 22, "hole": 22, "content": 22, "storag": 22, "system": 22, "experi": 22}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Aliases and configuration": [[0, "aliases-and-configuration"]], "Objectives": [[0, "objectives-0"], [1, "objectives-0"], [2, "objectives-0"], [3, "objectives-0"], [4, "objectives-0"], [5, "objectives-0"], [7, "objectives-0"], [12, "objectives-0"], [14, "objectives-0"], [15, "objectives-0"], [16, "objectives-0"], [17, "objectives-0"], [20, "objectives-0"], [21, "objectives-0"], [22, "objectives-0"]], "Aliases": [[0, "id1"]], "Example alias: git graph": [[0, "example-alias-git-graph"]], "Using external commands": [[0, "using-external-commands"]], "Food for thought: When to alias?": [[0, "discussion-0"]], "List of aliases the instructors use": [[0, "list-of-aliases-the-instructors-use"]], "Advanced aliases": [[0, "advanced-aliases"]], "Advanced Git configuration": [[0, "advanced-git-configuration"]], "Keypoints": [[0, "keypoints-0"], [2, "keypoints-0"], [3, "keypoints-0"], [7, "keypoints-0"], [12, "keypoints-0"], [13, "keypoints-0"], [21, "keypoints-0"]], "Inspecting history": [[1, "inspecting-history"], [9, "inspecting-history"], [10, "inspecting-history"]], "Instructor note": [[1, "instructor-note-0"], [1, "instructor-note-1"], [2, "instructor-note-0"], [2, "instructor-note-1"], [2, "instructor-note-2"], [3, "instructor-note-0"], [3, "instructor-note-1"], [3, "instructor-note-2"], [4, "instructor-note-0"], [7, "instructor-note-0"], [7, "instructor-note-1"], [8, "instructor-note-0"], [12, "instructor-note-0"], [13, "instructor-note-0"], [14, "instructor-note-0"], [15, "instructor-note-0"], [16, "instructor-note-0"], [17, "instructor-note-0"], [20, "instructor-note-0"], [21, "instructor-note-0"], [21, "instructor-note-1"], [22, "instructor-note-0"]], "Command line, GitHub, and VS Code": [[1, "command-line-github-and-vs-code"]], "Our toolbox for history inspection": [[1, "our-toolbox-for-history-inspection"]], "Warm-up: \u201cGit History\u201d browser": [[1, "warm-up-git-history-browser"]], "Searching text patterns in the repository": [[1, "searching-text-patterns-in-the-repository"]], "Inspecting individual commits": [[1, "inspecting-individual-commits"]], "Line-by-line code annotation with metadata": [[1, "line-by-line-code-annotation-with-metadata"]], "Discussion": [[1, "discussion-0"], [2, "discussion-1"], [5, "discussion"], [7, "discussion-1"], [13, "discussion-0"], [16, "discussion-0"], [21, "discussion-0"], [21, "discussion-1"], [21, "discussion-2"], [22, "discussion-0"], [23, "discussion-0"]], "Inspecting code in the past": [[1, "inspecting-code-in-the-past"]], "Exercise": [[1, "exercise"], [4, "exercise"], [5, "exercise"], [9, "exercise-1"], [14, "exercise"], [15, "exercise"], [15, "exercise-1"], [20, "exercise"]], "Exercise: Explore basic archaeology commands (20 min)": [[1, "exercise-0"], [9, "exercise-0"]], "Solution": [[1, "solution-0"], [2, "solution-0"], [3, "solution-0"], [3, "solution-1"], [3, "solution-2"], [7, "solution-0"], [7, "solution-1"], [9, "solution-0"], [9, "solution-0"], [9, "solution-0"], [9, "solution-0"], [9, "solution-1"], [9, "solution-2"], [9, "solution-0"], [9, "solution-1"], [9, "solution-0"], [9, "solution-0"], [9, "solution-1"], [9, "solution-0"], [12, "solution-0"], [16, "solution-0"], [17, "solution-0"], [17, "solution-1"], [21, "solution-0"]], "Finding out when something broke/changed with git bisect": [[1, "finding-out-when-something-broke-changed-with-git-bisect"]], "How would you solve this?": [[1, "discussion-1"]], "Optional exercise: Git bisect": [[1, "optional-exercise-git-bisect"]], "(optional) History-2: Use git bisect to find the bad commit": [[1, "exercise-1"], [9, "exercise-1"]], "Summary": [[1, "summary"], [2, "summary"], [3, "summary"], [4, "summary"], [14, "summary"], [15, "summary"]], "Basics": [[2, "basics"], [9, "basics"]], "What is Git, and what is a Git repository?": [[2, "what-is-git-and-what-is-a-git-repository"]], "Recording a snapshot with Git": [[2, "recording-a-snapshot-with-git"]], "Question for the more advanced participants": [[2, "discussion-0"]], "Configuring Git command line": [[2, "configuring-git-command-line"]], "Type-along: Tracking a guacamole recipe with Git": [[2, "type-along-tracking-a-guacamole-recipe-with-git"]], "Creating a repository": [[2, "creating-a-repository"]], "Adding files and committing changes": [[2, "adding-files-and-committing-changes"]], "Exercise: Record changes": [[2, "exercise-record-changes"]], "Basic-1: Record changes": [[2, "exercise-0"], [9, "exercise-0"]], "Git history and log": [[2, "git-history-and-log"]], "Optional exercises: Comparing changes": [[2, "optional-exercises-comparing-changes"]], "(optional) Basic-2: Comparing and showing commits": [[2, "exercise-1"], [9, "exercise-1"]], "(optional) Basic-3: Visual diff tools": [[2, "exercise-2"], [9, "exercise-2"]], "(optional) Basic-4: Browser and command line": [[2, "exercise-3"], [9, "exercise-3"]], "Writing useful commit messages": [[2, "writing-useful-commit-messages"], [13, "writing-useful-commit-messages"]], "Ignoring files and paths with .gitignore": [[2, "ignoring-files-and-paths-with-gitignore"]], "Graphical user interfaces": [[2, "graphical-user-interfaces"]], "Basic-5: Test your understanding": [[2, "exercise-4"], [9, "exercise-4"]], "Branching and merging": [[3, "branching-and-merging"], [9, "branching-and-merging"]], "Motivation for branches": [[3, "motivation-for-branches"]], "An important alias": [[3, null]], "Creating and working with branches": [[3, "creating-and-working-with-branches"]], "It is possible to create and merge branches directly on GitHub": [[3, null]], "Exercise: Create and commit to branches": [[3, "exercise-create-and-commit-to-branches"]], "Branch-1: Create and commit to branches": [[3, "exercise-0"], [9, "exercise-0"]], "Exercise: Merging branches": [[3, "exercise-merging-branches"]], "Branch-2: Merge branches": [[3, "exercise-1"], [9, "exercise-1"]], "If you got stuck in the above exercises or joined later": [[3, null]], "Deleting branches safely": [[3, "deleting-branches-safely"]], "Optional exercises with branches": [[3, "optional-exercises-with-branches"]], "(optional) Branch-3: Perform a fast-forward merge": [[3, "exercise-2"], [9, "exercise-2"]], "(optional) Branch-4: Rebase a branch (instead of merge)": [[3, "exercise-3"], [9, "exercise-3"]], "Tags": [[3, "tags"]], "Typical workflows": [[3, "typical-workflows"]], "Branch-5: Test your understanding": [[3, "exercise-4"], [9, "exercise-4"]], "Copy and browse an existing project": [[4, "copy-and-browse-an-existing-project"], [9, "copy-and-browse-an-existing-project"]], "GitHub, VS Code, Command line, and more": [[4, "github-vs-code-command-line-and-more"]], "Creating a copy of the repository by \u201cforking\u201d": [[4, "creating-a-copy-of-the-repository-by-forking"]], "Exercise: Browsing an existing project (25 min)": [[4, "exercise-0"], [9, "exercise-0"]], "Solution and walk-through": [[4, "solution-and-walk-through"], [5, "solution-and-walk-through"], [14, "solution-and-walk-through"], [15, "solution-and-walk-through"]], "(1) Basic browsing": [[4, "basic-browsing"]], "(2) Compare commit history with network graph": [[4, "compare-commit-history-with-network-graph"]], "(3) When was a recipe last modified?": [[4, "when-was-a-recipe-last-modified"]], "(4) How many changes did the Guacamole recipe receive?": [[4, "how-many-changes-did-the-guacamole-recipe-receive"]], "(5) Which recipes include the ingredient \u201csalt\u201d": [[4, "which-recipes-include-the-ingredient-salt"]], "Searching in a forked repository will not work instantaneously!": [[4, null]], "(6) Who modified each line last and when?": [[4, "who-modified-each-line-last-and-when"]], "(7) Can you use these recipes yourself? Are you allowed to share modifications?": [[4, "can-you-use-these-recipes-yourself-are-you-allowed-to-share-modifications"]], "(8) Browse issues and pull requests in the upstream repository": [[4, "browse-issues-and-pull-requests-in-the-upstream-repository"]], "Committing changes": [[5, "committing-changes"], [9, "committing-changes"]], "Background": [[5, "background"], [15, "background"]], "Exercise: Practice creating commits and branches (20 min)": [[5, "exercise-0"], [9, "exercise-0"]], "(1) Make sure you are on your fork": [[5, "make-sure-you-are-on-your-fork"]], "(2) Create a branch and add a recipe to the branch": [[5, "create-a-branch-and-add-a-recipe-to-the-branch"]], "(3) Modify the recipe with a new commit": [[5, "modify-the-recipe-with-a-new-commit"]], "(4) Switch to the main branch and modify a recipe there": [[5, "switch-to-the-main-branch-and-modify-a-recipe-there"]], "(5) Browse the commits you just made": [[5, "browse-the-commits-you-just-made"]], "(6) Compare the branches": [[5, "compare-the-branches"]], "(7) Compare two arbitrary commits": [[5, "compare-two-arbitrary-commits"]], "(8) Renaming a branch": [[5, "renaming-a-branch"]], "(9) Creating a tag": [[5, "creating-a-tag"]], "Configuring Git command line and editor": [[6, "configuring-git-command-line-and-editor"]], "Name and email address for Git commit metadata": [[6, "name-and-email-address-for-git-commit-metadata"]], "Default branch name": [[6, "default-branch-name"]], "Useful alias for the command line": [[6, "useful-alias-for-the-command-line"]], "Default text editor for commit messages": [[6, "default-text-editor-for-commit-messages"]], "Authenticating to GitHub: SSH or HTTPS or VS Code?": [[6, "authenticating-to-github-ssh-or-https-or-vs-code"]], "Conflict resolution": [[7, "conflict-resolution"], [7, "id2"], [9, "conflict-resolution"]], "Conflicts in Git and why they are good": [[7, "conflicts-in-git-and-why-they-are-good"]], "The human side of conflicts": [[7, "discussion-0"]], "Preparing a conflict": [[7, "preparing-a-conflict"]], "If you got stuck previously or joined later": [[7, null]], "Merging conflicting changes": [[7, "merging-conflicting-changes"]], "Steps to resolve a conflict": [[7, null]], "Exercise: Create and resolve a conflict": [[7, "exercise-create-and-resolve-a-conflict"]], "Conflict-1: Create another conflict and resolve": [[7, "exercise-0"], [9, "exercise-0"]], "Optional exercises with conflict resolution": [[7, "optional-exercises-with-conflict-resolution"]], "(optional) Conflict-2: Resolve a conflict when rebasing a branch": [[7, "exercise-1"], [9, "exercise-1"]], "(optional) Conflict-3: Resolve a conflict using mergetool": [[7, "exercise-2"], [9, "exercise-2"]], "Using \u201cours\u201d or \u201ctheirs\u201d strategy": [[7, "using-ours-or-theirs-strategy"]], "Aborting a conflicting merge": [[7, "aborting-a-conflicting-merge"]], "Avoiding conflicts": [[7, "avoiding-conflicts"]], "Customizing Git": [[8, "customizing-git"]], "Shell prompt": [[8, "shell-prompt"]], "More useful \u201cdiff\u201d output": [[8, "more-useful-diff-output"]], "List of exercises": [[9, "list-of-exercises"]], "Motivation": [[9, "motivation"], [16, "motivation"]], "Merging changes and contributing to the project": [[9, "merging-changes-and-contributing-to-the-project"], [15, "merging-changes-and-contributing-to-the-project"]], "Exercise: Merging branches with pull requests (20 min)": [[9, "exercise-0"], [15, "exercise-0"]], "Cloning a Git repository and working locally": [[9, "cloning-a-git-repository-and-working-locally"], [14, "cloning-a-git-repository-and-working-locally"]], "Exercise: Cloning a Git repository and working locally (25 min)": [[9, "exercise-0"], [14, "exercise-0"]], "How to turn your project to a Git repo and share it": [[9, "how-to-turn-your-project-to-a-git-repo-and-share-it"], [20, "how-to-turn-your-project-to-a-git-repo-and-share-it"]], "Exercise: Turn your project to a Git repo and share it (25 min)": [[9, "exercise-0"], [20, "exercise-0"]], "Using the Git staging area": [[9, "using-the-git-staging-area"], [21, "using-the-git-staging-area"]], "Staging-1: Perform an interactive commit": [[9, "exercise-0"], [21, "exercise-0"]], "Staging-2: Use the staging area to make a commit in two steps": [[9, "exercise-1"], [21, "exercise-1"]], "Undoing and recovering": [[9, "undoing-and-recovering"], [17, "undoing-and-recovering"]], "Undoing-1: Revert a commit": [[9, "exercise-0"], [17, "exercise-0"]], "Undoing-2: Modify a previous commit": [[9, "exercise-1"], [17, "exercise-1"]], "Undoing-3: Destroy our experimentation in this episode": [[9, "exercise-2"], [17, "exercise-2"]], "Undoing-4: Test your understanding": [[9, "exercise-3"], [17, "exercise-3"]], "Interrupted work": [[9, "interrupted-work"], [12, "interrupted-work"]], "Interrupted-1: Stash some uncommitted work": [[9, "exercise-0"], [12, "exercise-0"]], "Instructor guide": [[10, "instructor-guide"]], "Privacy": [[10, "privacy"]], "Schedule Day 1": [[10, "schedule-day-1"]], "Schedule Day 2": [[10, "schedule-day-2"]], "Why we teach this lesson": [[10, "why-we-teach-this-lesson"]], "Intended learning outcomes": [[10, "intended-learning-outcomes"]], "Live better than reading the website material": [[10, "live-better-than-reading-the-website-material"]], "Log your history in a separate window": [[10, "log-your-history-in-a-separate-window"]], "Create a cheatsheet on the board": [[10, "create-a-cheatsheet-on-the-board"]], "Draw a graph on the board": [[10, "draw-a-graph-on-the-board"]], "Repeat the following points": [[10, "repeat-the-following-points"]], "Start from identical environment": [[10, "start-from-identical-environment"]], "Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version": [[11, "introduction-to-version-control-with-git-why-we-want-to-track-versions-and-how-to-go-back-in-time-to-a-working-version"]], "Prerequisites": [[11, "prerequisites-0"]], "Getting started": [[11, null]], "Modifying an existing project": [[11, null]], "Studying an existing project": [[11, null]], "Sharing your work": [[11, null]], "Finding the balance": [[11, null]], "Older episodes": [[11, null]], "Optional episodes": [[11, null]], "Reference": [[11, null]], "About": [[11, null]], "Frequent situation: interrupted work": [[12, "frequent-situation-interrupted-work"]], "Option 1: Stashing": [[12, "option-1-stashing"]], "Exercise: Stashing": [[12, "exercise-stashing"]], "Option 2: Create branches": [[12, "option-2-create-branches"]], "Storing various junk you don\u2019t need but don\u2019t want to get rid of": [[12, "storing-various-junk-you-don-t-need-but-don-t-want-to-get-rid-of"]], "Practical advice: how much Git is necessary?": [[13, "practical-advice-how-much-git-is-necessary"]], "What level of branching complexity is necessary for each project?": [[13, "what-level-of-branching-complexity-is-necessary-for-each-project"]], "How about staging and committing?": [[13, "how-about-staging-and-committing"]], "How large should a commit be?": [[13, "how-large-should-a-commit-be"]], "What is in a Git repository and what are we cloning?": [[14, "what-is-in-a-git-repository-and-what-are-we-cloning"]], "(1) Configure Git command line and editor": [[14, "configure-git-command-line-and-editor"]], "(2) Cloning a repository": [[14, "cloning-a-repository"]], "(3) Creating branches locally": [[14, "creating-branches-locally"]], "(4) Creating commits locally": [[14, "creating-commits-locally"]], "(5) Switching branches and creating commits": [[14, "switching-branches-and-creating-commits"]], "(6) Merging branches locally": [[14, "merging-branches-locally"]], "(7) How to compare the graph locally and on GitHub": [[14, "how-to-compare-the-graph-locally-and-on-github"]], "(8) Browsing remote branches and creating local branches from them": [[14, "browsing-remote-branches-and-creating-local-branches-from-them"]], "(1) Navigate to your branch": [[15, "navigate-to-your-branch"]], "(2) Begin the pull request process": [[15, "begin-the-pull-request-process"]], "(3) Fill out and verify the pull request": [[15, "fill-out-and-verify-the-pull-request"]], "(4) Create the pull request": [[15, "create-the-pull-request"]], "(5) Merge the pull request": [[15, "merge-the-pull-request"]], "(6) Delete merged branches": [[15, "delete-merged-branches"]], "(7) Contribute to the original repository with a pull request": [[15, "contribute-to-the-original-repository-with-a-pull-request"]], "Resolving a conflict (demonstration)": [[15, "resolving-a-conflict-demonstration"]], "Git is all about keeping track of changes": [[16, "git-is-all-about-keeping-track-of-changes"]], "Why do we need to keep track of versions?": [[16, "why-do-we-need-to-keep-track-of-versions"]], "Features: roll-back, branching, merging, collaboration": [[16, "features-roll-back-branching-merging-collaboration"]], "Reproducibility": [[16, "reproducibility"]], "Talking about code": [[16, "talking-about-code"]], "What we typically like to snapshot": [[16, "what-we-typically-like-to-snapshot"]], "Difficulties of version control": [[16, "difficulties-of-version-control"]], "Why Git and not another tool?": [[16, "why-git-and-not-another-tool"]], "It is almost always possible to recover": [[17, null]], "Nice resource to visually simulate Git operation": [[17, null]], "Undoing your recent, uncommitted and unstaged changes (preserves history)": [[17, "undoing-your-recent-uncommitted-and-unstaged-changes-preserves-history"]], "Reverting commits (preserves history)": [[17, "reverting-commits-preserves-history"]], "Exercise: Revert a commit": [[17, "exercise-revert-a-commit"]], "Adding to the previous commit (modifies history)": [[17, "adding-to-the-previous-commit-modifies-history"]], "Exercise: Modify a previous commit": [[17, "exercise-modify-a-previous-commit"]], "Rewinding branches (modifies history)": [[17, "rewinding-branches-modifies-history"]], "Exercise: Git reset": [[17, "exercise-git-reset"]], "Recovering from committing to the wrong branch": [[17, "recovering-from-committing-to-the-wrong-branch"]], "Recovering from merging/pulling into the wrong branch": [[17, "recovering-from-merging-pulling-into-the-wrong-branch"]], "Recovering from conflict after pulling changes": [[17, "recovering-from-conflict-after-pulling-changes"]], "Quick reference": [[18, "quick-reference"]], "Other cheatsheets": [[18, "other-cheatsheets"]], "Glossary": [[18, "glossary"]], "Commands we use": [[18, "commands-we-use"]], "Other resources": [[19, "other-resources"]], "Remote repositories": [[20, "remote-repositories"]], "Is putting software on GitHub/GitLab/\u2026 publishing?": [[20, "is-putting-software-on-github-gitlab-publishing"]], "Commit history is telling a story": [[21, "commit-history-is-telling-a-story"]], "Interactive commits": [[21, "interactive-commits"]], "Exercise: Interactive commits": [[21, "exercise-interactive-commits"]], "The staging area": [[21, "the-staging-area"]], "Staging area commands": [[21, "staging-area-commands"]], "Exercise: Using the staging area": [[21, "exercise-using-the-staging-area"]], "Git under the hood": [[22, "git-under-the-hood"]], "Down the rabbit hole": [[22, "down-the-rabbit-hole"]], "Git is basically a content-addressed storage system": [[22, "git-is-basically-a-content-addressed-storage-system"]], "Demonstration: experimenting with branches": [[22, "demonstration-experimenting-with-branches"]], "What to avoid": [[23, "what-to-avoid"]]}, "indexentries": {"github repository": [[18, "term-GitHub-repository"]], "head": [[18, "term-HEAD"]], "vs code": [[18, "term-VS-Code"]], "alias": [[18, "term-alias"]], "branch": [[18, "term-branch"]], "clone": [[18, "term-clone"]], "commit": [[18, "term-commit"]], "fork": [[18, "term-fork"]], "git": [[18, "term-git"]], "hash": [[18, "term-hash"]], "issue": [[18, "term-issue"]], "main": [[18, "term-main"]], "master": [[18, "term-master"]], "merge": [[18, "term-merge"]], "merging": [[18, "term-merging"]], "origin": [[18, "term-origin"]], "pull": [[18, "term-pull"]], "pull request": [[18, "term-pull-request"]], "push": [[18, "term-push"]], "remote": [[18, "term-remote"]], "repository": [[18, "term-repository"]], "staging area": [[18, "term-staging-area"]], "tag": [[18, "term-tag"]], "upstream": [[18, "term-upstream"]], "version control system": [[18, "term-version-control-system"]], "working directory": [[18, "term-working-directory"]], "workspace": [[18, "term-workspace"]]}}) \ No newline at end of file diff --git a/branch/main/sharing/index.html b/branch/main/sharing/index.html new file mode 100644 index 00000000..9ad1c053 --- /dev/null +++ b/branch/main/sharing/index.html @@ -0,0 +1,435 @@ + + + + + + + How to turn your project to a Git repo and share it — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

How to turn your project to a Git repo and share it

+
+

Objectives

+
    +
  • Turn our own coding project (small or large, finished or unfinished) into a +Git repository.

  • +
  • Be able to share a repository on the web to have a backup or so that others +can reuse and collaborate or even just find it.

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

Exercise

+
+

Exercise: Turn your project to a Git repo and share it (25 min)

+
    +
  1. Create a new directory called myproject with one or few files in it. +This represents our own project. It is not yet a Git repository. You can try +that with your own project or use a simple placeholder example.

  2. +
  3. Turn this new directory into a Git repository.

  4. +
  5. Share this repository on GitHub (or GitLab, since it really works the same).

  6. +
+

We offer three different paths of how to do this exercise.

+
    +
  • Via GitHub web interface: easy and can be a good starting point if you are completely +new to Git.

  • +
  • VS Code is quite easy, since VS Code can offer to create the +GitHub repositories for you.

  • +
  • Command line: you need to create the +repository on GitHub and link it yourself.

  • +
+
+

Create an repository on GitHub

+

First log into GitHub, then follow the screenshots and descriptions below.

+
+Screenshot on GitHub before a new repository form is opened +
+

Click on the “plus” symbol on top right, then on “New repository”.

+
+
+

Then:

+
+Screenshot on GitHub just before a new repository is created +
+

Choose a repository name, add a short description, and in this case make sure to check “Add a +README file”. Finally “Create repository”.

+
+
+

Upload your files

+

Now that the repository is created, you can upload your files:

+
+Screenshot on GitHub just before uploading files +
+

Click on the “+” symbol and then on “Upload files”.

+
+
+
+
+
+
+

Remote repositories

+

In this exercise we have pushed our local repository to a remote repository. +We will learn how to work with remote repositories in detail in the +collaborative distributed version +control lesson. To store +your git data on another server, you use remotes. A remote is a repository +on its own, with its own branches. We can push changes to the remote and +pull from the remote.

+

You might use remotes to:

+
    +
  • Back up your own work or make your work findable.

  • +
  • To collaborate with other people.

  • +
+

There are different types of remotes:

+
    +
  • If you have a server you can SSH to, you can use that as a remote.

  • +
  • GitHub is a popular, closed-source commercial site.

  • +
  • GitLab is a popular, open-core +commercial site. Many universities have their own private GitLab servers +set up.

  • +
  • Bitbucket is yet another popular commercial site.

  • +
  • Another option is NotABug.

  • +
  • There are more …

  • +
+
+
+

Is putting software on GitHub/GitLab/… publishing?

+

It is a good first step but to make your code truly findable and +accessible, condider making your code citable and persistent: Get a +persistent identifier (PID) such as DOI in addition to sharing the code +publicly, by using services like Zenodo or similar +services.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/singlehtml/.buildinfo b/branch/main/singlehtml/.buildinfo new file mode 100644 index 00000000..d48d887f --- /dev/null +++ b/branch/main/singlehtml/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: e21ba9a26a1fa041e43d0d2e9e34e5b6 +tags: 33eac41acc08762151beb8f3b7b86c8f diff --git a/branch/main/singlehtml/.nojekyll b/branch/main/singlehtml/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/main/singlehtml/_images/add-file.png b/branch/main/singlehtml/_images/add-file.png new file mode 100644 index 00000000..9683b2db Binary files /dev/null and b/branch/main/singlehtml/_images/add-file.png differ diff --git a/branch/main/singlehtml/_images/annotate.png b/branch/main/singlehtml/_images/annotate.png new file mode 100644 index 00000000..8021920a Binary files /dev/null and b/branch/main/singlehtml/_images/annotate.png differ diff --git a/branch/main/singlehtml/_images/annotate1.png b/branch/main/singlehtml/_images/annotate1.png new file mode 100644 index 00000000..93416b2a Binary files /dev/null and b/branch/main/singlehtml/_images/annotate1.png differ diff --git a/branch/main/singlehtml/_images/bare-repository.png b/branch/main/singlehtml/_images/bare-repository.png new file mode 100644 index 00000000..45286f93 Binary files /dev/null and b/branch/main/singlehtml/_images/bare-repository.png differ diff --git a/branch/main/singlehtml/_images/browse-files.png b/branch/main/singlehtml/_images/browse-files.png new file mode 100644 index 00000000..5fcc3528 Binary files /dev/null and b/branch/main/singlehtml/_images/browse-files.png differ diff --git a/branch/main/singlehtml/_images/cheat-sheet.jpg b/branch/main/singlehtml/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/branch/main/singlehtml/_images/cheat-sheet.jpg differ diff --git a/branch/main/singlehtml/_images/code-portion.png b/branch/main/singlehtml/_images/code-portion.png new file mode 100644 index 00000000..39356bd5 Binary files /dev/null and b/branch/main/singlehtml/_images/code-portion.png differ diff --git a/branch/main/singlehtml/_images/commit-and-tree.png b/branch/main/singlehtml/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/branch/main/singlehtml/_images/commit-and-tree.png differ diff --git a/branch/main/singlehtml/_images/commit-changes.png b/branch/main/singlehtml/_images/commit-changes.png new file mode 100644 index 00000000..4c0546c6 Binary files /dev/null and b/branch/main/singlehtml/_images/commit-changes.png differ diff --git a/branch/main/singlehtml/_images/commits-and-parents.png b/branch/main/singlehtml/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/branch/main/singlehtml/_images/commits-and-parents.png differ diff --git a/branch/main/singlehtml/_images/commits.png b/branch/main/singlehtml/_images/commits.png new file mode 100644 index 00000000..b154c666 Binary files /dev/null and b/branch/main/singlehtml/_images/commits.png differ diff --git a/branch/main/singlehtml/_images/create-repository-with-readme.png b/branch/main/singlehtml/_images/create-repository-with-readme.png new file mode 100644 index 00000000..24118344 Binary files /dev/null and b/branch/main/singlehtml/_images/create-repository-with-readme.png differ diff --git a/branch/main/singlehtml/_images/create-repository.png b/branch/main/singlehtml/_images/create-repository.png new file mode 100644 index 00000000..80fb99c2 Binary files /dev/null and b/branch/main/singlehtml/_images/create-repository.png differ diff --git a/branch/main/singlehtml/_images/edit-file.png b/branch/main/singlehtml/_images/edit-file.png new file mode 100644 index 00000000..f7527bd0 Binary files /dev/null and b/branch/main/singlehtml/_images/edit-file.png differ diff --git a/branch/main/singlehtml/_images/file-history.png b/branch/main/singlehtml/_images/file-history.png new file mode 100644 index 00000000..5e42fbe9 Binary files /dev/null and b/branch/main/singlehtml/_images/file-history.png differ diff --git a/branch/main/singlehtml/_images/fork.png b/branch/main/singlehtml/_images/fork.png new file mode 100644 index 00000000..0c992d3d Binary files /dev/null and b/branch/main/singlehtml/_images/fork.png differ diff --git a/branch/main/singlehtml/_images/forking.png b/branch/main/singlehtml/_images/forking.png new file mode 100644 index 00000000..73c4d71a Binary files /dev/null and b/branch/main/singlehtml/_images/forking.png differ diff --git a/branch/main/singlehtml/_images/git-annotate.png b/branch/main/singlehtml/_images/git-annotate.png new file mode 100644 index 00000000..60c6f7c2 Binary files /dev/null and b/branch/main/singlehtml/_images/git-annotate.png differ diff --git a/branch/main/singlehtml/_images/git-branch-1.svg b/branch/main/singlehtml/_images/git-branch-1.svg new file mode 100644 index 00000000..4b735e40 --- /dev/null +++ b/branch/main/singlehtml/_images/git-branch-1.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + m2 + + + m3 + + + m1 + + + + + main + + + + + HEAD + + + diff --git a/branch/main/singlehtml/_images/git-branch-2.svg b/branch/main/singlehtml/_images/git-branch-2.svg new file mode 100644 index 00000000..dde628b6 --- /dev/null +++ b/branch/main/singlehtml/_images/git-branch-2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l1 + + + e2 + + + e1 + + + m5 + + + m4 + + + m2 + + + m3 + + + m1 + + + + + less-salt + + + + + HEAD + + + + + experiment + + + + + main + + + diff --git a/branch/main/singlehtml/_images/git-branch-3.svg b/branch/main/singlehtml/_images/git-branch-3.svg new file mode 100644 index 00000000..19231579 --- /dev/null +++ b/branch/main/singlehtml/_images/git-branch-3.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + e2 + + + m3 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + + + less-salt + + + + + experiment + + + diff --git a/branch/main/singlehtml/_images/git-collaborative.svg b/branch/main/singlehtml/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/branch/main/singlehtml/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/branch/main/singlehtml/_images/git-deleted-branches.svg b/branch/main/singlehtml/_images/git-deleted-branches.svg new file mode 100644 index 00000000..d54c0032 --- /dev/null +++ b/branch/main/singlehtml/_images/git-deleted-branches.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + m5 + + + l1 + + + m4 + + + + + main + + + + + HEAD + + + diff --git a/branch/main/singlehtml/_images/git-log-github.png b/branch/main/singlehtml/_images/git-log-github.png new file mode 100644 index 00000000..db44d29b Binary files /dev/null and b/branch/main/singlehtml/_images/git-log-github.png differ diff --git a/branch/main/singlehtml/_images/git-log-terminal.png b/branch/main/singlehtml/_images/git-log-terminal.png new file mode 100644 index 00000000..56493e6e Binary files /dev/null and b/branch/main/singlehtml/_images/git-log-terminal.png differ diff --git a/branch/main/singlehtml/_images/git-merge-1.svg b/branch/main/singlehtml/_images/git-merge-1.svg new file mode 100644 index 00000000..005301ab --- /dev/null +++ b/branch/main/singlehtml/_images/git-merge-1.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m1 + + + m2 + + + m5 + + + m6 + + + e1 + + + m3 + + + l1 + + + m7 + + + m4 + + + + + experiment + + + + + less-salt + + + + + main + + + + + HEAD + + + diff --git a/branch/main/singlehtml/_images/git-merge-2.svg b/branch/main/singlehtml/_images/git-merge-2.svg new file mode 100644 index 00000000..cb268ee7 --- /dev/null +++ b/branch/main/singlehtml/_images/git-merge-2.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m7 + + + m8 + + + m6 + + + m1 + + + m2 + + + e1 + + + m3 + + + l1 + + + m5 + + + m4 + + + + + experiment + + + + + main + + + + + HEAD + + + + + less-salt + + + diff --git a/branch/main/singlehtml/_images/git-pre-ff.svg b/branch/main/singlehtml/_images/git-pre-ff.svg new file mode 100644 index 00000000..e4d8bc5b --- /dev/null +++ b/branch/main/singlehtml/_images/git-pre-ff.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e1 + + + e2 + + + m7 + + + m8 + + + n3 + + + n1 + + + m5 + + + l1 + + + m6 + + + m4 + + + n2 + + + m2 + + + m3 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + main + + + diff --git a/branch/main/singlehtml/_images/git_stage_commit.svg b/branch/main/singlehtml/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/branch/main/singlehtml/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/main/singlehtml/_images/github-branches-overview.png b/branch/main/singlehtml/_images/github-branches-overview.png new file mode 100644 index 00000000..89e0058d Binary files /dev/null and b/branch/main/singlehtml/_images/github-branches-overview.png differ diff --git a/branch/main/singlehtml/_images/github-branches.png b/branch/main/singlehtml/_images/github-branches.png new file mode 100644 index 00000000..3a6a8ff9 Binary files /dev/null and b/branch/main/singlehtml/_images/github-branches.png differ diff --git a/branch/main/singlehtml/_images/github-comparing-changes.png b/branch/main/singlehtml/_images/github-comparing-changes.png new file mode 100644 index 00000000..735b990b Binary files /dev/null and b/branch/main/singlehtml/_images/github-comparing-changes.png differ diff --git a/branch/main/singlehtml/_images/github-contribute.png b/branch/main/singlehtml/_images/github-contribute.png new file mode 100644 index 00000000..a149e9f3 Binary files /dev/null and b/branch/main/singlehtml/_images/github-contribute.png differ diff --git a/branch/main/singlehtml/_images/github-create-branch.png b/branch/main/singlehtml/_images/github-create-branch.png new file mode 100644 index 00000000..e7958ff2 Binary files /dev/null and b/branch/main/singlehtml/_images/github-create-branch.png differ diff --git a/branch/main/singlehtml/_images/github-create-tag.png b/branch/main/singlehtml/_images/github-create-tag.png new file mode 100644 index 00000000..f08f5878 Binary files /dev/null and b/branch/main/singlehtml/_images/github-create-tag.png differ diff --git a/branch/main/singlehtml/_images/github-merged.png b/branch/main/singlehtml/_images/github-merged.png new file mode 100644 index 00000000..eea47d93 Binary files /dev/null and b/branch/main/singlehtml/_images/github-merged.png differ diff --git a/branch/main/singlehtml/_images/github-navigate-to-branch.png b/branch/main/singlehtml/_images/github-navigate-to-branch.png new file mode 100644 index 00000000..42b0f753 Binary files /dev/null and b/branch/main/singlehtml/_images/github-navigate-to-branch.png differ diff --git a/branch/main/singlehtml/_images/gophers.png b/branch/main/singlehtml/_images/gophers.png new file mode 100644 index 00000000..741406ba Binary files /dev/null and b/branch/main/singlehtml/_images/gophers.png differ diff --git a/branch/main/singlehtml/_images/history.png b/branch/main/singlehtml/_images/history.png new file mode 100644 index 00000000..6384e302 Binary files /dev/null and b/branch/main/singlehtml/_images/history.png differ diff --git a/branch/main/singlehtml/_images/history1.png b/branch/main/singlehtml/_images/history1.png new file mode 100644 index 00000000..06662c31 Binary files /dev/null and b/branch/main/singlehtml/_images/history1.png differ diff --git a/branch/main/singlehtml/_images/license.png b/branch/main/singlehtml/_images/license.png new file mode 100644 index 00000000..f4cadf0d Binary files /dev/null and b/branch/main/singlehtml/_images/license.png differ diff --git a/branch/main/singlehtml/_images/meld.png b/branch/main/singlehtml/_images/meld.png new file mode 100644 index 00000000..774f9cd1 Binary files /dev/null and b/branch/main/singlehtml/_images/meld.png differ diff --git a/branch/main/singlehtml/_images/mergetool.png b/branch/main/singlehtml/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/branch/main/singlehtml/_images/mergetool.png differ diff --git a/branch/main/singlehtml/_images/network.png b/branch/main/singlehtml/_images/network.png new file mode 100644 index 00000000..e0fcb2fb Binary files /dev/null and b/branch/main/singlehtml/_images/network.png differ diff --git a/branch/main/singlehtml/_images/new-repo-form.png b/branch/main/singlehtml/_images/new-repo-form.png new file mode 100644 index 00000000..b808ee0b Binary files /dev/null and b/branch/main/singlehtml/_images/new-repo-form.png differ diff --git a/branch/main/singlehtml/_images/new-repo-plus.png b/branch/main/singlehtml/_images/new-repo-plus.png new file mode 100644 index 00000000..e58ba5d8 Binary files /dev/null and b/branch/main/singlehtml/_images/new-repo-plus.png differ diff --git a/branch/main/singlehtml/_images/new-repository.png b/branch/main/singlehtml/_images/new-repository.png new file mode 100644 index 00000000..aff76772 Binary files /dev/null and b/branch/main/singlehtml/_images/new-repository.png differ diff --git a/branch/main/singlehtml/_images/pen-symbol.png b/branch/main/singlehtml/_images/pen-symbol.png new file mode 100644 index 00000000..044902a3 Binary files /dev/null and b/branch/main/singlehtml/_images/pen-symbol.png differ diff --git a/branch/main/singlehtml/_images/preview.png b/branch/main/singlehtml/_images/preview.png new file mode 100644 index 00000000..8a602b66 Binary files /dev/null and b/branch/main/singlehtml/_images/preview.png differ diff --git a/branch/main/singlehtml/_images/search.png b/branch/main/singlehtml/_images/search.png new file mode 100644 index 00000000..4462f71e Binary files /dev/null and b/branch/main/singlehtml/_images/search.png differ diff --git a/branch/main/singlehtml/_images/search1.png b/branch/main/singlehtml/_images/search1.png new file mode 100644 index 00000000..89c0e25a Binary files /dev/null and b/branch/main/singlehtml/_images/search1.png differ diff --git a/branch/main/singlehtml/_images/show.png b/branch/main/singlehtml/_images/show.png new file mode 100644 index 00000000..12d7915c Binary files /dev/null and b/branch/main/singlehtml/_images/show.png differ diff --git a/branch/main/singlehtml/_images/staging-basics.svg b/branch/main/singlehtml/_images/staging-basics.svg new file mode 100644 index 00000000..13df8bf5 --- /dev/null +++ b/branch/main/singlehtml/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + restore + add + commit + restore + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/branch/main/singlehtml/_images/stranger.jpg b/branch/main/singlehtml/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/branch/main/singlehtml/_images/stranger.jpg differ diff --git a/branch/main/singlehtml/_images/upload-files.png b/branch/main/singlehtml/_images/upload-files.png new file mode 100644 index 00000000..fd3ef8cc Binary files /dev/null and b/branch/main/singlehtml/_images/upload-files.png differ diff --git a/branch/main/singlehtml/_images/vscode-add-and-commit.png b/branch/main/singlehtml/_images/vscode-add-and-commit.png new file mode 100644 index 00000000..d9a09c46 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-add-and-commit.png differ diff --git a/branch/main/singlehtml/_images/vscode-authorize.png b/branch/main/singlehtml/_images/vscode-authorize.png new file mode 100644 index 00000000..4d45dc2d Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-authorize.png differ diff --git a/branch/main/singlehtml/_images/vscode-change-branch.png b/branch/main/singlehtml/_images/vscode-change-branch.png new file mode 100644 index 00000000..c1a5f00a Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-change-branch.png differ diff --git a/branch/main/singlehtml/_images/vscode-create-branch.png b/branch/main/singlehtml/_images/vscode-create-branch.png new file mode 100644 index 00000000..71b275a9 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-create-branch.png differ diff --git a/branch/main/singlehtml/_images/vscode-merging.png b/branch/main/singlehtml/_images/vscode-merging.png new file mode 100644 index 00000000..7e5880e7 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-merging.png differ diff --git a/branch/main/singlehtml/_images/vscode-open-terminal.png b/branch/main/singlehtml/_images/vscode-open-terminal.png new file mode 100644 index 00000000..1be92267 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-open-terminal.png differ diff --git a/branch/main/singlehtml/_images/vscode-publish-to-github1.png b/branch/main/singlehtml/_images/vscode-publish-to-github1.png new file mode 100644 index 00000000..883e756c Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-publish-to-github1.png differ diff --git a/branch/main/singlehtml/_images/vscode-publish-to-github2.png b/branch/main/singlehtml/_images/vscode-publish-to-github2.png new file mode 100644 index 00000000..d0055db4 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-publish-to-github2.png differ diff --git a/branch/main/singlehtml/_images/vscode-publish-to-github3.png b/branch/main/singlehtml/_images/vscode-publish-to-github3.png new file mode 100644 index 00000000..0f68d0ee Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-publish-to-github3.png differ diff --git a/branch/main/singlehtml/_images/vscode-start.png b/branch/main/singlehtml/_images/vscode-start.png new file mode 100644 index 00000000..e7830807 Binary files /dev/null and b/branch/main/singlehtml/_images/vscode-start.png differ diff --git a/branch/main/singlehtml/_static/_sphinx_javascript_frameworks_compat.js b/branch/main/singlehtml/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/branch/main/singlehtml/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/branch/main/singlehtml/_static/basic.css b/branch/main/singlehtml/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/branch/main/singlehtml/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/branch/main/singlehtml/_static/check-solid.svg b/branch/main/singlehtml/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/branch/main/singlehtml/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/main/singlehtml/_static/clipboard.min.js b/branch/main/singlehtml/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/branch/main/singlehtml/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/branch/main/singlehtml/_static/copybutton.css b/branch/main/singlehtml/_static/copybutton.css new file mode 100644 index 00000000..40eafe5f --- /dev/null +++ b/branch/main/singlehtml/_static/copybutton.css @@ -0,0 +1,93 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/branch/main/singlehtml/_static/copybutton.js b/branch/main/singlehtml/_static/copybutton.js new file mode 100644 index 00000000..f3ecd034 --- /dev/null +++ b/branch/main/singlehtml/_static/copybutton.js @@ -0,0 +1,241 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos, .gp'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/branch/main/singlehtml/_static/copybutton_funcs.js b/branch/main/singlehtml/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/branch/main/singlehtml/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/branch/main/singlehtml/_static/css/badge_only.css b/branch/main/singlehtml/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/branch/main/singlehtml/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.eot b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.svg b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.ttf b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff b/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff2 b/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-bold.woff b/branch/main/singlehtml/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-bold.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-bold.woff2 b/branch/main/singlehtml/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-bold.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff b/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff2 b/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-normal.woff b/branch/main/singlehtml/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-normal.woff differ diff --git a/branch/main/singlehtml/_static/css/fonts/lato-normal.woff2 b/branch/main/singlehtml/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/branch/main/singlehtml/_static/css/fonts/lato-normal.woff2 differ diff --git a/branch/main/singlehtml/_static/css/theme.css b/branch/main/singlehtml/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/branch/main/singlehtml/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/branch/main/singlehtml/_static/doctools.js b/branch/main/singlehtml/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/branch/main/singlehtml/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/branch/main/singlehtml/_static/documentation_options.js b/branch/main/singlehtml/_static/documentation_options.js new file mode 100644 index 00000000..89003c67 --- /dev/null +++ b/branch/main/singlehtml/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'singlehtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/branch/main/singlehtml/_static/file.png b/branch/main/singlehtml/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/branch/main/singlehtml/_static/file.png differ diff --git a/branch/main/singlehtml/_static/jquery.js b/branch/main/singlehtml/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/branch/main/singlehtml/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/main/singlehtml/_static/js/html5shiv.min.js b/branch/main/singlehtml/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/branch/main/singlehtml/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/branch/main/singlehtml/_static/js/theme.js b/branch/main/singlehtml/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/branch/main/singlehtml/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/branch/main/singlehtml/_static/minipres.js b/branch/main/singlehtml/_static/minipres.js new file mode 100644 index 00000000..ad11c871 --- /dev/null +++ b/branch/main/singlehtml/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/branch/main/singlehtml/_static/minus.png b/branch/main/singlehtml/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/branch/main/singlehtml/_static/minus.png differ diff --git a/branch/main/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/branch/main/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 00000000..33566310 --- /dev/null +++ b/branch/main/singlehtml/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/branch/main/singlehtml/_static/plus.png b/branch/main/singlehtml/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/branch/main/singlehtml/_static/plus.png differ diff --git a/branch/main/singlehtml/_static/pygments.css b/branch/main/singlehtml/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/branch/main/singlehtml/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/branch/main/singlehtml/_static/searchtools.js b/branch/main/singlehtml/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/branch/main/singlehtml/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/branch/main/singlehtml/_static/sphinx_highlight.js b/branch/main/singlehtml/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/branch/main/singlehtml/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/branch/main/singlehtml/_static/sphinx_lesson.css b/branch/main/singlehtml/_static/sphinx_lesson.css new file mode 100644 index 00000000..14b20c64 --- /dev/null +++ b/branch/main/singlehtml/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/branch/main/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css b/branch/main/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css new file mode 100644 index 00000000..e68feb82 --- /dev/null +++ b/branch/main/singlehtml/_static/sphinx_rtd_theme_ext_color_contrast.css @@ -0,0 +1,47 @@ +/* The following are for web accessibility of sphinx_rtd_theme: they + * solve some of the most frequent contrast issues. Remove when this + * solved: + * https://github.com/readthedocs/sphinx_rtd_theme/issues/971 + */ +/* background: #fcfcfc, note boxes #E7F2FA */ +a { color: #2573A7; } /* original #2980B9, #1F5C84; */ +body { color: #242424; } /* original #404040, #383838 */ +.wy-side-nav-search>a, .wy-side-nav-search .wy-dropdown>a { + color: #ffffff; +} /* original #fcfcfc */ +footer { color: #737373; } /* original gray=#808080*/ +footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { + color: #737373; +} /* original gray=#808080*/ +.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { + color: #AB2314; +} +/* Sidebar background */ +.wy-side-nav-search { background-color: #277CB4;} + +/* Same, but for pygments */ +.highlight .ch { color: #3E7A89; } /* #! line */ +.highlight .c1 { color: #3E7A89; } /* also comments */ +.highlight .nv { color: #AD3ECC; } /* variable */ +.highlight .gp { color: #B45608; } /* prompt character, $*/ +.highlight .si { color: #3975B1; } /* ${} variable text */ +.highlight .nc { color: #0C78A7; } + +/* Sphinx admonitions */ +/* warning */ +.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { + background: #B15E16; } +/* important */ +.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { + background: #12826C; } +/* seealso, note, etc */ +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { + background: #277CB4; } +/* error, danger */ +.rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { + background: #e31704; +} + +/* Generic admonition titles */ +.wy-alert-title, .rst-content .admonition-title { + background: #277CB4; } diff --git a/branch/main/singlehtml/_static/tabs.css b/branch/main/singlehtml/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/branch/main/singlehtml/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/branch/main/singlehtml/_static/tabs.js b/branch/main/singlehtml/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/branch/main/singlehtml/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/branch/main/singlehtml/_static/term_role_formatting.css b/branch/main/singlehtml/_static/term_role_formatting.css new file mode 100644 index 00000000..0b66095c --- /dev/null +++ b/branch/main/singlehtml/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/branch/main/singlehtml/_static/togglebutton.css b/branch/main/singlehtml/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/branch/main/singlehtml/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/branch/main/singlehtml/_static/togglebutton.js b/branch/main/singlehtml/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/branch/main/singlehtml/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/branch/main/singlehtml/index.html b/branch/main/singlehtml/index.html new file mode 100644 index 00000000..65e9282a --- /dev/null +++ b/branch/main/singlehtml/index.html @@ -0,0 +1,5700 @@ + + + + + + + Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • + Edit on GitHub +
  • +
+
+
+
+
+ +
+

Introduction to version control with Git - Why we want to track versions and how to go back in time to a working version

+
+

Warning

+

In February and March 2024 we rewrote this lesson from the ground up. +If you are looking for the previous version, you can browse the +2023 version of this lesson.

+
+

This is the introductory lesson to version control using +Git.

+

We start with an existing repository on the web to visually explain the basic +concepts of version control. We later move to a local +repository. Our goal there is not only to be able to apply changes to an +existing repository but to also be able to turn own projects into Git +repositories and to share them with others.

+

In the separate collaborative Git +lesson, we teach more use +of remote repositories and good collaborative workflows. We try to stick to +simple workflows, just enough for researchers who are not obsessed with Git to +be able to work well.

+

The goals of the module as a whole are that the learner will feel comfortable +about committing changes, branching, and merging.

+
+

Prerequisites

+

We offer several options to go through the material: on the web, in an editor, +or in the terminal. +Please see the installation instructions.

+

We recommend to have a GitHub account. +Why GitHub? +Also GitLab and Bitbucket would +allow similar workflows and basically everything that we will discuss is +transferable. With this material and these exercises we do not implicitly +endorse the company GitHub. We have chosen to demonstrate +a number of concepts using examples with GitHub because +it is currently the most popular web platform for hosting Git repositories and +the chance is high that you will interact with +GitHub-based repositories even if you choose to host your +Git repository on another service.

+
+
+
+

Motivation

+
+

Objectives

+
    +
  • Make sure nobody leaves the workshop without starting to use some form of version control.

  • +
  • Discuss the reasons why we advocate distributed version control.

  • +
+
+
+

Instructor note

+
    +
  • 15 min discussion/demonstration

  • +
+
+
+

Git is all about keeping track of changes

+

We will learn how to keep track of changes first in the web browser. +Below are screenshots of tracked changes with Git +(from this example repository):

+
+Screenshot of a git log on GitHub +
+

Web browser, GitHub view

+
+
+

Later also using the terminal or the editor +(the same example repository):

+
+Screenshot of a git log in terminal +
+

The same as above, but the terminal view

+
+
+
+
+

Why do we need to keep track of versions?

+

Problem: If you have to identify and find your code from 17 days +ago, can you?

+

Version control is an answer to the following questions (do you recognize some +of them?):

+
    +
  • “It broke … hopefully I have a working version somewhere?”

  • +
  • “Can you please send me the latest version?”

  • +
  • “Where is the latest version?”

  • +
  • “Which version are you using?”

  • +
  • “Which version have the authors used in the paper I am trying to reproduce?”

  • +
  • “Found a bug! Since when was it there?”

  • +
  • “I am sure it used to work. When did it change?”

  • +
  • “My laptop is gone. Is my thesis now gone?”

  • +
+
+
+

Features: roll-back, branching, merging, collaboration

+

Problem: Your code worked two days ago, but is giving an error now. +You don’t know what you changed.

+

Problem: You and your colleague want to work on the same code at the +same time.

+
    +
  • Roll-back: you can always go back to a previous version and compare

  • +
  • Branching and merging:

    +
      +
    • Work on different ideas at the same time

    • +
    • Different people can work on the same code/project without interfering

    • +
    • You can experiment with an idea and discard it if it turns out to be a bad idea

    • +
    +
  • +
+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+ +
+
+

Reproducibility

+

Problem: Someone asks you about your results from 5 years ago. Can +you get the same results now?

+
    +
  • How do you indicate which version of your code you have used in your paper?

  • +
  • When you find a bug, how do you know when precisely this bug was introduced +(Are published results affected? Do you need to inform collaborators or users of your code?).

  • +
+

With version control we can “annotate” code +(browse this example online):

+
+Example of a git-annotated code with code and history side-by-side +
+

Example of a git-annotated code with code and history side-by-side.

+
+
+
+
+

Talking about code

+

Problem: You want to show someone a few lines from one of your projects.

+

Which of these two is more practical?

+
    +
  • “Clone the code, go to the file ‘src/util.rs’, and search for ‘time_iso8601’”. +Oh! But make sure you use the version from August 2023.”

  • +
  • Or I can send you a permalink:

  • +
+
+Screen-shot of a code portion +
+

Permalink that points to a code portion.

+
+
+
+
+

What we typically like to snapshot

+
    +
  • Software (this is how it started but Git/GitHub can track a lot more)

  • +
  • Scripts

  • +
  • Documents (plain text files much better suitable than Word documents)

  • +
  • Manuscripts (Git is great for collaborating/sharing LaTeX or Quarto manuscripts)

  • +
  • Configuration files

  • +
  • Website sources

  • +
  • Data

  • +
+
+

Discussion

+

In this example somebody tried to keep track of versions without a version +control system tool like Git. Discuss the following directory listing. What +possible problems do you anticipate with this kind of “version control”:

+
myproject-2019.zip
+myproject-2020-February.zip
+myproject-2021-August.zip
+myproject-2023-09-19-working.zip
+myproject-2023-09-21.zip
+myproject-2023-09-21-test.zip
+myproject-2023-09-21-myversion.zip
+myproject-2023-09-21-newfeature.zip
+...
+
+
+ +
+
+
+

Difficulties of version control

+

Despite the benefits, let’s be honest, there are some difficulties:

+
    +
  • One more thing to learn (it’s probably worth it and will save you more time in the long run; basic career skill).

  • +
  • Difficult if your collaborators don’t want to use it (in the worst case, you can version control on your side and email them versions).

  • +
  • Advanced things can be difficult, but basics are often enough (ask others for help when needed).

  • +
+
+
+

Why Git and not another tool?

+
    +
  • Easy to set up: no server needed.

  • +
  • Very popular: chances are high you will need to contribute to somebody else’s code which is tracked with Git.

  • +
  • Distributed: good backup, no single point of failure, you can track and +clean-up changes offline, simplifies collaboration model for open-source +projects.

  • +
  • Important platforms such as GitHub, GitLab, and Bitbucket +build on top of Git.

  • +
+

However, any version control is better than no version control and it is OK to +prefer a different tool than Git such as +Subversion, +Mercurial, Pijul, or others.

+
+
+
+

Configuring Git command line and editor

+

We have a longer version of this in the installation +instructions. +But for clarity, we will review the most important parts here.

+

You don’t need to set these if you work only through the GitHub web interface. +If you use VS Code or other editors or integrated development environments, +the editor might prompt you to set these up.

+

These configuration settings are saved in a file called .gitconfig in your +home directory. If this file exists, editors like VS Code will use this +configuration.

+

If you want to see your configuration settings, you can use the +command (--show-origin means it shows the file where each setting +is defined):

+
$ git config --list --show-origin
+
+
+
+

Name and email address for Git commit metadata

+

Git commits carry metadata about the author and two things you will always need +to define somewhere are:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+
+
+

For the email address we recommend to use the one you use for your GitHub account. +If you prefer to not use it, you can instead use +YOUR_GITHUB_USERNAME@users.noreply.github.com as the email address (replace YOUR_GITHUB_USERNAME). +This means that nobody can write to this email address, but GitHub will still +be able to connect your contributions with your GitHub account.

+

Note that these can, in theory, be anything: this is just data, not a +registration or identity requirement.

+
+
+

Default branch name

+

The default branch name in Git has been master for a long time, but it is +changing to main in many places. We recommend to set it to main for new +repositories that you create locally:

+
$ git config --global init.defaultbranch main
+
+
+
+
+

Useful alias for the command line

+

We recommend to define an alias in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+

We have an own section about aliases: Aliases and configuration.

+
+
+

Default text editor for commit messages

+

Git sometimes needs to start a text editor for you to enter messages (unless you create +commits from inside an editor or on the web). +This may have already been set to something (like VS Code), but if not +nano is usually a safe choice:

+
$ git config --global core.editor nano
+
+
+

The installation instructions text editor page gives ways +to set other editors, or do a web search for “git set editor to +[editor name]”.

+
+
+

Authenticating to GitHub: SSH or HTTPS or VS Code?

+

How does GitHub know who you are? There are three options:

+
    +
  • SSH is the classic method, using Secure Shell +Protocol remote connection +keys.

  • +
  • HTTPS works with the Git Credential Manager, which is an +extra add-on that works easily in Windows and Mac.

  • +
  • VS Code editor can authenticate with GitHub using its own +authentication method.

  • +
+

Read how to install them from the installation +instructions.

+

Test which one you should use:

+
+

Try this command:

+
$ ssh -T git@github.com
+
+
+

If it returns Hi USERNAME! You've successfully authenticated, ..., +then SSH is configured and the following steps will work with the SSH +cloning.

+

See our installation +instructions to +set up SSH access.

+

From now on, if you know that SSH works, you should always select +SSH as the clone URL from GitHub, or translate the URL to start with +the right thing yourself: git@github.com: (with the :).

+
+
+
+
+
+
+

Copy and browse an existing project

+

In this episode, we will look at an existing repository to +understand how all the pieces work together. Along the way, we will make a copy +(a fork) of the repository for us, which will be used for our +own changes in the next episode.

+
    +
  • We used to start by directly going and creating a repository from scratch. This +was abstract and hard to understand.

  • +
  • Instead, we’ll show you all the cool stuff in a Git repository +first, and then start adding files.

  • +
  • We use an example recipe book we created just for this course.

  • +
  • By the end of the course, you’ll know how to contribute your own +recipes to it.

  • +
+
+

Objectives

+
    +
  • See a real Git repository and understand what is inside of it.

  • +
  • Understand how version control allows advanced inspection of a +repository.

  • +
  • See how Git allows multiple people to collaborate easily.

  • +
  • See the big picture instead of remembering a bunch of commands.

  • +
+
+
+

GitHub, VS Code, Command line, and more

+

We offer three different paths of how to do this exercise:

+
    +
  • GitHub (this is the one we will demonstrate on day 1)

  • +
  • VS Code (if you prefer to follow along using an editor; we will +do this on day 2)

  • +
  • Command line (for people comfortable with the command line; you +will see more of this on day 2)

  • +
+

In the future we’ll add more paths, for example Jupyter and RStudio +(contributions welcome!).

+
+
+

Creating a copy of the repository by “forking”

+

A repository is a collection of files in one directory tracked +by git. A GitHub repository is GitHub’s copy, which adds +things like access control. Each GitHub repository is owned by a user +or organization, who controls what is in it.

+

First, we need to make our own copy of the exercise repository. This will +become important later, when we make our own changes.

+
    +
  1. Go to the repository view on GitHub:

    + +
  2. +
  3. First, on GitHub, click the button that says “Fork”. It is towards +the top-right of the screen:

    +
    +Screenshot on GitHub before clicking on "Fork" +
    +
  4. +
  5. You should shortly be redirected to your copy of the repository +YOUR_USER_NAME/recipe-book.

  6. +
+

At all times you should be aware of if you looking at your repository +or the CodeRefinery upstream repository.

+
    +
  • Your repository: https://github.com/USERNAME/recipe-book

  • +
  • CodeRefinery upstream repository: https://github.com/coderefinery/recipe-book

  • +
+
+

You only need to open your own view, as described above. The browser +URL should look like https://github.com/USER/recipe-book, where +USER is your GitHub username.

+
+
+
+

Exercise

+

Work on this by yourself or in your team.

+
+

Instructor note

+

Before starting the exercise session:

+
    +
  • Make sure you have shown how to fork the repository to own account +(above).

  • +
+
+
+

Exercise: Browsing an existing project (25 min)

+

Browse the recipe-book project (introduced above) and explore commits and branches. Take notes +and prepare questions. The hints are for the GitHub path in the +browser.

+
    +
  1. Browse the commit history: Are commit messages understandable? +(Hint: “Commit history”, the timeline symbol, above the file list)

  2. +
  3. Compare the commit history with the network graph (“Insights” -> “Network”). Can you find the branches?

  4. +
  5. How can you find out when a recipe was last modified?

  6. +
  7. How many changes did the Guacamole recipe receive (you find it under “sides”)? +Try to click on some of the commits to see what changed. +(Hint: “History” in the view of a single file)

  8. +
  9. Which recipes include the ingredient “salt”? +(Hint: the GitHub search. From the repository view, it should offer +the filter “repo:USER/recipe-book” by default. What if you +add a search term?)

  10. +
  11. In the Guacamole recipe, find out who modified each line last and when +(click on file, then click “Blame” button). Find out who added the cilantro +and in which commit. +(Hint: “Blame” view in the file view)

  12. +
  13. Can you use these recipes yourself? Are you allowed to share +modifications? +(Hint: look for a license file)

  14. +
  15. Browse issues and pull requests in the upstream repository (the +repository you forked from). Any idea what these might be good for? +(Hint: tabs in the repository view)

  16. +
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by +design.

+
+
+

Solution and walk-through

+
+

(1) Basic browsing

+

The most basic thing to look at is the history of commits.

+
    +
  • This is visible from a button in the repository view. We see every +change, when, and who has committed.

  • +
  • Every change has a unique identifier, such as 554c187. This can +be used to identify both this change, and the whole project’s +version as of that change.

  • +
  • Clicking on a change in the view shows more.

  • +
+
+

Click on the timeline symbol in the repository view:

+
+Screenshot on GitHub of where to find the commit history +
+
+
+
+

(2) Compare commit history with network graph

+

The commit history we saw above looks linear: one commit after +another. But if we look at the network view, we see some branches and +merges. We’ll see how to do these later. This is another one of the +basic Git views.

+
+

In a new browser tab, open the “Insights” tab, and click on “Network”. +You can hover over the commit dots to see the person who committed and +how they correspond with the commits in the other view:

+
+Screenshot on GitHub of the network graph +
+
+
+
+

(3) When was a recipe last modified?

+

We see the history for the whole repository, but we can also see it +for a single file.

+
+

Navigate to the file view: Main page → sides directory → +guacamole.md. Click the “History” button near the top right:

+
+Screenshot on GitHub showing the history of a single file +
+
+
+
+

(4) How many changes did the Guacamole recipe receive?

+

According to the view above, it seems to have five changes (as of +2024-03-07). This could change later on.

+
+
+

(5) Which recipes include the ingredient “salt”

+

Version control makes it very easy to find all occurrences of a single +word. This is useful for things like finding where functions or +variables are defined or used.

+
+

We go to the main recipe book view. We click the Search magnifying +class at the very top, type “salt”, and click enter. We see every +instance, including the context.

+
+

Searching in a forked repository will not work instantaneously!

+

It usually takes a few minutes before one can search for keywords in a forked repository +since it first needs to build the search index the very first time we search. +Start it, continue with other steps, then come back to this.

+
+
+Screenshot on GitHub performing a search +
+
+
+
+

(6) Who modified each line last and when?

+

This is called the “annotate” or “blame” view. The name “blame” +is very unfortunate, but it is the standard term for historical reasons +for this functionality and it is not meant to blame anyone.

+
+

From a recipe view, change preview to “Blame” towards the top-left. +To get the actual commit, click on the commit message.

+
+Screenshot on GitHub showing the "Blame" view +
+
+
+
+

(7) Can you use these recipes yourself? Are you allowed to share modifications?

+
    +
  • Look at the file LICENSE.

  • +
  • It says it is “Creative Commons Zero 1.0”, which is equivalent to +public domain. You can use them without conditions.

  • +
  • Note the GitHub view of the file LICENSE gives a nice summary of what it +means. Try it out:

    +
    +Screenshot on GitHub summarizing license terms +
    +
  • +
+
+
+

(8) Browse issues and pull requests in the upstream repository

+

This can only be done through the GitHub view. Go to the main +repository coderefinery/recipe-book, (not your fork): +https://github.com/coderefinery/recipe-book. Issues +and Pull requests are different for each GitHub +copy.

+
    +
  • Click on the “Issues” tab. These are notes that people have added, +which allow discussion about the project. Often they are used to communicate +problems or ideas.

  • +
  • Click on the “Pull requests” tab. This allows anyone to propose +changes, but only the repository owners can accept.

  • +
+
+
+
+

Summary

+
    +
  • Git allowed us to understand this simple project much better than we +could, if it was just a few files on our own computer.

  • +
  • It was also very easy to share the project with the course.

  • +
  • By forking the repository, we created our own copy. This is +important for the next episode, where we will make changes to +our copy.

  • +
+
+
+
+

Committing changes

+

The first and most basic task to do in Git is record changes using +commits. In this part, we will record changes in two +ways: on a new branch (which supports multiple lines of work at once), and directly +on the “main” branch (which happens to be the default branch here).

+
+

Objectives

+
    +
  • Record new changes to our own copy of the project.

  • +
  • Understand adding changes in two separate branches.

  • +
  • See how to compare different versions.

  • +
+
+
+

Background

+
    +
  • In the previous episode we have browsed an existing repository and saw commits +and branches.

  • +
  • Each commit is a snapshot of the entire project at a certain +point in time and has a unique identifier (hash) .

  • +
  • A branch is a line of development, and the main branch or master branch +are often the default branch in Git.

  • +
  • A branch in Git is like a sticky note that is attached to a commit. When we add +new commits to a branch, the sticky note moves to the new commit.

  • +
  • Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don’t move when new +commits are added.

  • +
+
+Branching explained with a gopher +
+

What if two people, at the same time, make two different changes? Git +can merge them together easily. Image created using https://gopherize.me/ +(inspiration).

+
+
+
+
+

Exercise

+

We offer three different paths of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the GitHub +path only and recommend you do that. (You can get experience with +the other paths on day 2)

+
+

Exercise: Practice creating commits and branches (20 min)

+
    +
  1. Make sure that you now work on your fork of the recipe-book +repository (USER/recipe-book, not coderefinery/recipe-book)

  2. +
  3. First create a new branch and then add a recipe to the branch and commit the change.

  4. +
  5. In a new commit, modify the recipe you just added.

  6. +
  7. Switch to the main branch and modify a recipe there.

  8. +
  9. Browse the network and locate the commits that you just created (“Insights” -> “Network”).

  10. +
  11. Compare the branch that you created with the main branch. Can you find an easy way to see the differences?

  12. +
  13. Can you find a way to compare versions between two arbitrary commits in the repository?

  14. +
  15. Try to rename the branch that you created and then browse the network again.

  16. +
  17. Try to create a tag for one of the commits that you created (on GitHub, +create a “release”).

  18. +
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by +design.

+
+
+

Solution and walk-through

+
+

(1) Make sure you are on your fork

+
+Screenshot on GitHub where we verify that we are on our fork. +
+

You want to see your username in the URL and you want to see the “forked from +…” part.

+
+
+
+
+

(2) Create a branch and add a recipe to the branch

+

A recipe template is below. This format is called “Markdown”, but it +doesn’t matter right now. You don’t have to use this particular template.

+
# Recipe name
+
+## Ingredients
+
+- Ingredient 1
+- Ingredient 2
+
+
+## Instructions
+
+- Step 1
+- Step 2
+
+
+

There is a main branch that is default. We want to create a +different branch for our new commit, because we will merge it later. +Commit is the verb to describe recording more changes, and also the +name of the thing you make. A commit is identified by something such as +554c187.

+
+
    +
  1. Where it says “main” at the top left, click, enter a new branch +name new-recipe, click on the offer to create the new branch +(“Create branch new-recipe from main”).

    +
    +Screenshot on GitHub where we create a new branch. +
    +
  2. +
  3. Change to some sub-directory, for example sides

  4. +
  5. Make sure you are still on the new-recipe branch (it should say +it at the top), and click “Add file” → “Create new file” from the +upper right.

  6. +
  7. Enter a filename where it says “Name your file…”, with a .md at +the end. Example: mixed-nuts.md.

  8. +
  9. Enter the recipe. You can use the template above.

  10. +
  11. Click “Commit changes”

  12. +
  13. Enter a commit message. Then click “Commit +changes”.

  14. +
+

You should appear back at the file browser view, and see your new +recipe there.

+
+
+
+

(3) Modify the recipe with a new commit

+
+

This is similar to before, but we click on the existing file to +modify.

+
    +
  1. Click on your new recipe, for example mixed-nuts.md.

  2. +
  3. Click the edit button, the pencil icon at top-right.

  4. +
  5. Follow the “Commit changes” instructions as in the previous step.

  6. +
+
+
+
+

(4) Switch to the main branch and modify a recipe there

+
+
    +
  1. Go back to the main repository page (your user’s page).

  2. +
  3. In the branch switch view (top left above the file view), switch to +main.

  4. +
  5. Modify another recipe that already exists, following the pattern +from above. Don’t modify the one you just created (but it shouldn’t +even be visible on the main branch).

  6. +
+
+
+
+

(5) Browse the commits you just made

+

Let’s look at what we did. Now, the main and new-recipe branches +have diverged: both have some modifications. Try to find the commits +you created.

+
+

Insights tab → Network view (just like we have done before).

+
+
+
+

(6) Compare the branches

+

Comparing changes is an important thing we need to do. When using the +GitHub view only, this may not be so common, but we’ll show it so that +it makes sense later on.

+
+

Next to the branch name switcher, click on “Branches” to get an overview.

+

Another way to compare branches or commits on GitHub is to adjust the following URL: +https://github.com/USER/recipe-book/compare/VERSION1..VERSION2

+

Replace USER with your username and VERSION1 and VERSION2 with a commit hash or branch name. +Please try it out.

+
+
+
+

(7) Compare two arbitrary commits

+

This is similar to above, but not only between branches.

+
+

Like above, one can compare commits on GitHub by adjusting the following URL: +https://github.com/USER/recipe-book/compare/VERSION1..VERSION2

+

Replace USER with your username and VERSION1 and VERSION2 with a commit hash or branch name. +Please try it out.

+
+
+
+

(8) Renaming a branch

+
+

Branch button → View all branches → three dots at right side → Rename branch.

+
+
+
+

(9) Creating a tag

+

Tags are a way to mark a specific commit as important, for example a release +version. They are also like a sticky note, but they don’t move when new +commits are added.

+
+

Click on the branch switcher, and then on “Tags”, then on “View all tags”, then +“Create a new release”:

+
+Screenshot on GitHub where we create a new tag. +
+

What GitHub calls releases are actually tags in Git with additional metadata. +For the purpose of this exercise we can use them interchangeably.

+
+
+
+
+

Discussion

+

In this part, we saw how we can make changes to our files. +With branches, we can +track several lines of work at once, and can compare +their differences.

+
    +
  • You could commit directly to main if there is only one single line +of work and it’s only you.

  • +
  • You could commit to branches if there are multiple lines of work at +once, and you don’t want them to interfere with each other.

  • +
  • Tags are useful to mark a specific commit as important, for example a +release version.

  • +
  • In Git, commits form a so-called “graph”. Branches are tags in Git function +like sticky notes that stick to specific commits. What this means for us is +that it does not cost any significant disk space to create new branches.

  • +
+
+
+
+

Merging changes and contributing to the project

+

Git allows us to have different development lines where we can try things out. +It also allows different people to work on the same project at the same. This +means that we have to somehow combine the changes later. In this part we will +practice this: merging.

+
+

Objectives

+
    +
  • Understand that on GitHub merging is done through a pull request. Think of it as a change proposal.

  • +
  • Create and merge a pull request within your own repository.

  • +
  • Understand (and optionally) do the same across repositories, to contribute to +the upstream public repository.

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

Background

+
    +
  • In the last episode, we added a new recipe on a branch. This allows +us to test it before it becomes “live”.

  • +
  • Now, we want to bring that change into the “main” branch.

  • +
  • We will find it’s not that hard! But you do have to keep track of the +steps and make sure that you work very precisely.

  • +
+
+
+

Exercise

+

In this exercise, we will show how we can propose changes and merge +changes within our own repository. Optionally, you can propose a recipe to +the upstream recipe book - which shows the true purpose of this. But +this is only a preview and we will practice collaboration much more in the +collaborative Git lesson.

+

We offer three different paths of how to do this exercise. For +the CodeRefinery workshop day 1, we use and demonstrate the GitHub +path only and recommend you do that. The exercise text below has +some GitHub-specific notes, but most is possibly with any path.

+
+

First, we make something called a pull request, which allows +review and commenting before the actual merge.

+
+

Exercise: Merging branches with pull requests (20 min)

+

We assume that in the previous exercise you have created a new branch +with a recipe. In our previous example, it is called new-recipe. +If not, create it first and add a recipe to your new branch, see +Committing changes.

+

We provide basic hints. You should refer to the solution as needed.

+
    +
  1. Navigate to your branch from the previous episode +(Hint: the same branch view we used last time).

  2. +
  3. Begin the pull request process. +(Hint: There is a “Contribute” button in the branch view).

  4. +
  5. Add or modify the pull request title and description, and verify the other data. +In the pull request verify the target repository and the target +branch. Make sure that you are merging within your own repository. +GitHub: By default, it will offer to make the change to the +upstream repository, coderefinery. You should change this, you +shouldn’t contribute your test recipe upstream yet. Where it says +base repository, select your own user’s repository.

  6. +
  7. Create the pull request by clicking “Create pull request”. Browse +the network view to see if anything has changed yet.

  8. +
  9. Merge the pull request, or if you are not on GitHub you can merge +the branch locally. Browse the network again. What has changed?

  10. +
  11. Find out which branches are merged and thus safe to delete. Then remove them +and verify that the commits are still there, only the branch labels are +gone. (Hint: you can delete branches that have been merged into main).

  12. +
  13. Optional: Try to create a new branch with a new change, then open a pull +request but towards the central repository. We will later merge few of +those. +(Hint: this is mostly the same as above, for the GitHub path. But, +you set the base repository as CodeRefinery. You might need to +compare across forks.)

  14. +
+
+
+

The solution below goes over most of the answers, and you are +encouraged to use it when the hints aren’t enough - this is by design.

+
+
+

Solution and walk-through

+ +
+

(2) Begin the pull request process

+

In GitHub, the pull request is the way we propose to merge two +branches together. We start the process of making one.

+
+
+Screenshot on GitHub where we get to the pull request process. +
+
+
+
+

(3) Fill out and verify the pull request

+

Check that the pull request is directed to the right repository and branch +and that it contains the changes that you meant to merge.

+
+

Things to check:

+
    +
  • Base repository: this should be your own

  • +
  • Title: make it descriptive

  • +
  • Description: make it informative

  • +
  • Scroll down to see commits: are these the ones you want to merge?

  • +
  • Scroll down to see the changes: are these the ones you want to merge?

    +
    +Screenshot on GitHub where we verify the changes we want to merge. +
    +

    This screenshot only shows the top part. If you scroll down, you +can see the commits and the changes. We recommend to do this before +clicking on “Create pull request”.

    +
    +
    +
  • +
+
+
+
+

(4) Create the pull request

+

We actually create the pull request. Don’t forget to navigate to the Network +view after opening the pull request. Note that the changes proposed in the +pull request are not yet merged.

+
+

Click on the green button “Create pull request”.

+

If you click on the little arrow next to “Create pull request”, you can also +see the option to “Create draft pull request”. This will be interesting later +when collaborating with others. It allows you to open a pull request that is +not ready to be merged yet, but you want to show it to others and get feedback.

+
+
+
+

(5) Merge the pull request

+

Now, we do the actual merging. We see some effects now.

+
+

Review it again (commits and changes), and then click “Merge pull request”.

+

After merging, verify the network view. Also navigate then to your “main” +branch and check that your new recipe is there.

+
+
+
+

(6) Delete merged branches

+

Before deleting branches, first check whether they are merged.

+

If you delete an un-merged branch, it will be difficult to find the commits +that were on that branch. If you delete a merged branch, the commits are now +also part of the branch where we have merged to.

+
+

One way to delete the branch is to click on the “Delete branch” button after the pull +request is merged:

+
+Screenshot on GitHub suggesting us to delete a branch after it has been merged. +
+

But what if we forgot? Then navigate to the branch view:

+
+Screenshot on GitHub where we navigate to the branches view. +
+

In the overview we can see that it has been merged and we can delete it:

+
+Screenshot on GitHub where we see an overview of branches and can delete them. +
+
+
+
+

(7) Contribute to the original repository with a pull request

+

Remember, this is an advanced step. If you do this, you are donating +a recipe to everyone.

+
+

Now that you know how to create branches and opening a pull request, try to +open a new pull request with a new change but this time the base repository +should be the upstream one.

+

In other words, you now send a pull request across repositories: from your fork +to the original repository.

+

Another thing that is different now is that you might not have permissions to +merge the pull request. We can then together review and browse the pull +request.

+
+
+
+
+

Resolving a conflict (demonstration)

+

A conflict is when Git asks humans to decide during a merge which of two +changes to keep if the same portion of a file has been changed in two different +ways on two different branches.

+

We will practice conflict resolution in the collaborative Git +lesson.

+

Here we will only demonstrate how to create a conflict and how to resolve it, +all on GitHub. Once we understand how this works, we will be more confident to +resolve conflicts also in the command line.

+

How to create a conflict (please try this in your own time and just watch now):

+
    +
  • Create a new branch from main and on it make a change to a file.

  • +
  • On main, make a different change to the same part of the same file.

  • +
  • Now try to merge the new branch to main. You will get a conflict.

  • +
+

How to resolve conflicts:

+
    +
  • On GitHub, you can resolve conflicts by clicking on the “Resolve conflicts” +button. This will open a text editor where you can choose which changes to +keep. +Make sure to remove the conflict markers. +After resolving the conflict, you can commit the changes and merge the +pull request.

  • +
  • Sometimes a conflict is between your change and somebody else’s change. In +that case, you might have to discuss with the other person which changes to +keep.

  • +
+

How to avoid conflicts:

+ +
+
+

Summary

+
    +
  • We learned how to merge two branches together.

  • +
  • When is this useful? This is not only useful to combine development lines in +your own work. Being able to merge branches also forms a basis for collaboration.

  • +
  • Branches which are merged to other branches are safe to delete, since we only +delete the “sticky note” next to a commit, not the commits themselves.

  • +
+
+
+
+

Cloning a Git repository and working locally

+

If you’ve been following the main path, you have just had interacted +with repositories on GitHub. This might not be what you usually +do, so now we move to working on your own computer.

+
+

Objectives

+
    +
  • We are able to clone a repository from the web and modify it locally.

  • +
  • We can do the same things we did before (commit, branch, merge), but locally.

  • +
  • We get a feeling for remote repositories (more later).

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

What is in a Git repository and what are we cloning?

+

Git repository:

+
    +
  • Contains all the files and directories of a project.

  • +
  • Contains the complete history of all changes (commits) to these files and directories.

  • +
  • Each commit is a snapshot of the entire project at a certain point in time and has a unique identifier (“hash”).

  • +
  • Sometimes it contains multiple branches and tags.

  • +
  • All the commits and history of a local repository are stored in a directory +called .git which is located at the root of the repository.

  • +
+

Cloning:

+
    +
  • Copying (downloading) the entire repository with all commits, branches, and tags to your computer.

  • +
  • It is a full backup of the repository, including all history.

  • +
  • You can then work on your local clone of the repository.

  • +
  • Changes on local clone will not automatically appear in the repository where +we cloned from. We have to actively “push” them there (we will practice this +in a later episode: How to turn your project to a Git repo and share it).

  • +
+
+
+

Exercise

+

Work on this by yourself or in your teams. Conceptually this episode should +seem familiar, from the browser-based exercises we did yesterday.

+

We offer the Command Line and VS Code paths for this exercise. +GitHub isn’t an option in this episode, since that is what we already +demonstrated in Committing changes and Merging changes and contributing to the project and since the point of this +episode is to work locally.

+

It is also possible to use the command line (terminal) from inside VS Code.

+
+

Exercise: Cloning a Git repository and working locally (25 min)

+
    +
  1. Configure Git command line and editor if you haven’t done that already.

  2. +
  3. Decide which repository you want to clone: your fork or the original repository? Both will work for this exercise. +Then, clone the recipe book.

  4. +
  5. Create a new branch.

  6. +
  7. Make a commit on your new branch.

  8. +
  9. Switch back to the main branch and create one or two commits there.

  10. +
  11. Merge the new branch into main.

  12. +
  13. Compare the graph locally and on GitHub and observe that the changes only exist locally on your computer.

  14. +
  15. Where are the remote branches? Practice how you can see all remote branches +also locally and how you can fetch them and make local changes to them.

  16. +
+
+

The solution below goes over most of the answer and should be used as +your guide (you can’t figure it out just from the exercise instructions).

+
+
+

Solution and walk-through

+
+

(1) Configure Git command line and editor

+

We have an own section for this: Configuring Git command line and editor.

+
+
+

(2) Cloning a repository

+

Now you need to decide which repository you want to clone. All of these options will work for this exercise +since we don’t plan to push changes back (for step 8 it might be easier to use the original repository):

+ +

The examples below assume you are cloning the original repository. If you are cloning your fork, you should +replace coderefinery with your GitHub username.

+
+

If you are unsure whether you are using SSH or HTTPS, please read Authenticating to GitHub: SSH or HTTPS or VS Code?.

+
+
$ git clone git@github.com:coderefinery/recipe-book.git
+
+
+
+

This creates a directory called “recipe-book” unless it already exists. You can also specify the target directory +on your computer (in this case “my-recipe-book”):

+
+
$ git clone git@github.com:coderefinery/recipe-book.git my-recipe-book
+
+
+
+
+
+
+

(3) Creating branches locally

+
+

Create a new branch called another-recipe from main and switch to it:

+
$ git switch --create another-recipe main
+
+
+

If you leave out the last argument, it will create a branch from the current +branch:

+
$ git switch --create another-recipe
+
+
+
+
+
+

(4) Creating commits locally

+
+

Create a new file. After we have created it, we can stage and commit +the change:

+
$ git add new-file.md
+$ git commit -m "Short summary of the change"
+
+
+

Make sure to replace “new-file.md” with the actual name of the file you created +and to replace “Short summary of the change” with a meaningful commit message.

+
+
+
+

(5) Switching branches and creating commits

+
+

First switch to the main branch:

+
$ git switch main
+
+
+

Then modify a file. Finally git add and then commit the change:

+
$ git commit -m "Short summary of the change"
+
+
+
+
+
+

(6) Merging branches locally

+
+

On the command line, when we merge, we always modify our current branch.

+

If you are not sure anymore what your current branch is, type:

+
$ git branch
+
+
+

Another way to find out where we are in Git:

+
$ git status
+
+
+

In this case we merge the another-recipe branch into our current branch:

+
$ git merge another-recipe
+
+
+
+
+
+

(7) How to compare the graph locally and on GitHub

+
+
$ git log --graph --oneline --decorate --all
+
+
+

We recommend to define an alias in Git, to be able to nicely visualize +branch structure in the terminal without having to remember a long Git command:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+

Then you can just type git graph from there on. We have an own section about +aliases: Aliases and configuration.

+

Compare this with the graph on GitHub: Insights tab → Network view (just like +we have done before).

+

The result is that we should not be able to see the new branch and the new +commits on GitHub.

+
+
+
+

(8) Browsing remote branches and creating local branches from them

+
+

With git branch you can list all local branches:

+
$ git branch
+
+  another-recipe
+* main
+
+
+

But where are the remote branches? We expect to see a couple of +them.

+

We can see them by asking for all branches (your output might vary depending on +where you cloned from):

+
$ git branch --all
+
+  another-recipe
+* main
+  remotes/origin/HEAD -> origin/main
+  remotes/origin/alex/fruit-salad
+  remotes/origin/main
+  remotes/origin/radovan/lasagna
+  remotes/origin/radovan/poke
+
+
+

You can create a local branch from a remote branch which will “track” the remote branch. +For instance, to create a local branch alex/fruit-salad from the remote branch origin/alex/fruit-salad +and switch to it, you can do:

+
$ git switch --create alex/fruit-salad origin/alex/fruit-salad
+
+
+

This shortcut will do the same thing:

+
$ git switch --track origin/alex/fruit-salad
+
+
+

Or even shorter:

+
$ git switch alex/fruit-salad
+
+
+

If you want to create a branch and not switch to it, you can use git branch.

+
$ git branch alex/fruit-salad
+
+
+
+
+
+
+

Summary

+
    +
  • When we clone a repository, we get a full backup of the repository, including +all history: all commits, branches, and tags.

  • +
  • Yesterday we learned about branches and commits, and now we created and used them locally.

  • +
  • Creating local branches and commits does not automatically modify the remote +repository. To “push” our local changes to the remote repository, we have to actively +“push” them there. We will practice this in a later episode: +How to turn your project to a Git repo and share it

  • +
  • Remote branches and local branches are not the same thing. If we want to +create local commits, we always need to create a local branch first. But the local branch can +“track” the remote branch and we can push and pull changes to and from the +remote branch.

  • +
+
+
+
+
+
+

Inspecting history

+
+

Objectives

+
    +
  • Be able find a line of code, find out why it was introduced and when.

  • +
  • Be able to quickly find the commit that changed a behavior.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Command line, GitHub, and VS Code

+

As usual, we offer ways to do this with the command line, VS Code, and +GitHub.

+
    +
  • Command line is most powerful and relatively easy with this. +You may also use it along with other things. If you haven’t tried +it yet, we’d recommend you to give it a try.

  • +
  • The GitHub web interface allows many things to be done, but not +everything.

  • +
  • VS Code allows some of these, but for some it’s easier to open +the VS Code terminal and run git there.

  • +
+
+
+

Our toolbox for history inspection

+
+

Instructor note

+

First the instructor demonstrates few commands on a real life example +repository https://github.com/networkx/networkx (mentioned in the amazing site The +Programming Historian). +Later we will practice these in an archaeology exercise (below).

+
+
+

Warm-up: “Git History” browser

+

As a warm-up we can try the “Git History” browser +on the README.rst file of the networkx repository:

+ +
+
+

Searching text patterns in the repository

+

With git grep you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or +some error message printed.

+
+

The Git command is as described above:

+
$ git grep TEXT
+$ git grep "some text with spaces"
+
+
+

In the networkx repository you can try:

+
$ git clone https://github.com/networkx/networkx
+$ cd networkx
+$ git grep -i fixme
+
+
+

While git grep searches the current state of the repository, +it is also possible to search through all changes with git log -S sometext +which can be useful to find where something got removed.

+
+
+
+

Inspecting individual commits

+
+

We have seen this one before already. Using git show we can inspect an individual commit if +we know its hash:

+
$ git show HASH
+
+
+

For instance:

+
$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7
+
+
+
+
+
+

Line-by-line code annotation with metadata

+

With git annotate you can see line by line who and when the line was +modified last. It also prints the precise hash of the last change which +modified each line. Incredibly useful for reproducibility.

+
+
$ git annotate FILE
+
+
+

Example:

+
$ git annotate networkx/convert_matrix.py
+
+
+

If you annotate in a terminal and the file is longer than the screen, Git by default uses the program less to +scroll the output. +Use /sometext <ENTER> to find “sometext” and you can cycle through the results with n (next) and N (last). +You can also use page up/down to scroll. You can quit with q.

+
+
+

Discussion

+

Discuss how these relatively trivial changes affect the annotation:

+
    +
  • Wrapping long lines of text/code into shorter lines

  • +
  • Auto-formatting tools such as black

  • +
  • Editors that automatically remove trailing whitespace

  • +
+
+
+
+

Inspecting code in the past

+
+

We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code:

+
$ git switch --create BRANCHNAME HASH
+
+
+

Example (lines starting with “#” are only comments):

+
$ # create branch called "older-code" from hash 347e6292419b
+$ git switch --create older-code 347e6292419bd0e4bff077fe971f983932d7a0e9
+
+$ # now you can navigate and inspect the code as it was back then
+$ # ...
+
+$ # after we are done we can switch back to "main"
+$ git switch main
+
+$ # if we like we can delete the "older-code" branch
+$ git branch -d older-code
+
+
+

On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

+
$ git checkout -b BRANCHNAME SOMEHASH
+
+
+
+
+
+
+

Exercise

+

This is described with the command line method, but by looking above +you can translate to the other options.

+
+

Exercise: Explore basic archaeology commands (20 min)

+

Let us explore the value of these commands in an exercise. Future +exercises do not depend on this, so it is OK if you do not complete +it fully.

+

Exercise steps:

+
    +
  • Make sure you are not inside another Git repository when running this +exercise. If you are, first step “outside” of it. +We want to avoid creating a Git repository inside another Git repository.

    +
    +

    You can check if you are inside a Git repository with:

    +
    $ git status
    +
    +fatal: not a git repository (or any of the parent directories): .git
    +
    +
    +

    You want to see the above message which tells us that this is not a Git repository.

    +
    +
  • +
  • Clone this repository: +https://github.com/networkx/networkx.git.

    +
    +
    $ git clone https://github.com/networkx/networkx.git
    +
    +
    +
    +
  • +
  • Then let us all make sure we are working on a well-defined version of the repository.

    +
    +

    Step into the new directory and create an exercise branch from the +networkx-2.6.3 tag/release:

    +
    $ cd networkx
    +$ git switch --create exercise networkx-2.6.3
    +
    +
    +

    On old Git versions which do not know the switch command (before 2.23), you +need to use this instead:

    +
    $ git checkout -b exercise networkx-2.6.3
    +
    +
    +
    +
  • +
+

Then using the above toolbox try to:

+
    +
  1. Find the code line which contains "Logic error in degree_correlation".

  2. +
  3. Find out when this line was last modified or added. Find the actual commit which modified that line.

  4. +
  5. Inspect that commit with git show.

  6. +
  7. Create a branch pointing to the past when that commit was created to be +able to browse and use the code as it was back then.

  8. +
  9. How would you bring the code to the version of the code right before that line was last modified?

  10. +
+ +
+
+
+
+

Finding out when something broke/changed with git bisect

+

This only works with the command line.

+
+

“But I am sure it used to work! Strange.”

+
+

Sometimes you realize that something broke. +You know that it used to work. +You do not know when it broke.

+
+

How would you solve this?

+

Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now.

+
    +
  • How would you find the commit which changed it?

  • +
  • Why could it be useful to know the commit that changed it?

  • +
+
+

We will probably arrive at a solution which is similar to git bisect:

+
    +
  • First find out a commit in past when it worked.

    +
    $ git bisect start
    +$ git bisect good f0ea950  # this is a commit that worked
    +$ git bisect bad main      # last commit is broken
    +
    +
    +
  • +
  • Now compile and/or run and/or test and decide whether “good” or “bad”.

  • +
  • This is how you can tell Git that this was a working commit:

    +
    $ git bisect good
    +
    +
    +
  • +
  • And this is how you can tell Git that this was not a working commit:

    +
    $ git bisect bad
    +
    +
    +
  • +
  • Then bisect/iterate your way until you find the commit that broke it.

  • +
  • If you want to go back to start, type git bisect reset.

  • +
  • This can even be automatized with git bisect run SCRIPT. +For this you write a script that returns zero/non-zero (success/failure).

  • +
+
+
+

Optional exercise: Git bisect

+

This only works with the command line.

+
+

(optional) History-2: Use git bisect to find the bad commit

+

In this exercise, we use git bisect on an example repository. It +is OK if you do not complete this exercise fully.

+

Begin by cloning https://github.com/coderefinery/git-bisect-exercise.

+

Motivation

+

The motivation for this exercise is to be able to do archaeology with Git on a +source code where the bug is difficult to see visually. Finding the offending +commit is often more than half the debugging.

+

Background

+

The script get_pi.py approximates pi using terms of the Nilakantha series. It +should produce 3.14 but it does not. The script broke at some point and +produces 3.57 using the last commit:

+
$ python get_pi.py
+
+3.57
+
+
+

At some point within the 500 first commits, an error was introduced. The only +thing we know is that the first commit worked correctly.

+

Your task

+
    +
  • Clone this repository and use git bisect to find the commit which +broke the computation +(solution - spoiler alert!).

  • +
  • Once you have found the offending commit, also practice navigating to the last good commit.

  • +
  • Bonus exercise: +Write a script that checks for a correct result and use git bisect run to +find the offending commit automatically +(solution - spoiler alert!).

  • +
+

Hints

+

Finding the first commit:

+
$ git log --oneline | tail -n 1
+
+
+

How to navigate to the parent of a commit with hash SOMEHASH:

+
$ git switch --create BRANCHNAME SOMEHASH~1
+
+
+

Instead of a tilde you can also use this:

+
$ git switch --create BRANCHNAME SOMEHASH^
+
+
+
+
+
+

Summary

+
    +
  • git log/grep/annotate/show/bisect is a powerful combination when doing archaeology in a project on the command line.

  • +
  • git switch --create NAME HASH is the recommended mechanism to inspect old code on the command line.

  • +
  • Most of these commands can be used in the GitHub web interface (except git bisect).

  • +
+
+
+
+
+
+

How to turn your project to a Git repo and share it

+
+

Objectives

+
    +
  • Turn our own coding project (small or large, finished or unfinished) into a +Git repository.

  • +
  • Be able to share a repository on the web to have a backup or so that others +can reuse and collaborate or even just find it.

  • +
+
+
+

Instructor note

+
    +
  • 10 min introduction and setup

  • +
  • 25 min exercise

  • +
  • 15 min discussion

  • +
+
+
+

Exercise

+
+

Exercise: Turn your project to a Git repo and share it (25 min)

+
    +
  1. Create a new directory called myproject with one or few files in it. +This represents our own project. It is not yet a Git repository. You can try +that with your own project or use a simple placeholder example.

  2. +
  3. Turn this new directory into a Git repository.

  4. +
  5. Share this repository on GitHub (or GitLab, since it really works the same).

  6. +
+

We offer three different paths of how to do this exercise.

+
    +
  • Via GitHub web interface: easy and can be a good starting point if you are completely +new to Git.

  • +
  • VS Code is quite easy, since VS Code can offer to create the +GitHub repositories for you.

  • +
  • Command line: you need to create the +repository on GitHub and link it yourself.

  • +
+
+

Create an repository on GitHub

+

First log into GitHub, then follow the screenshots and descriptions below.

+
+Screenshot on GitHub before a new repository form is opened +
+

Click on the “plus” symbol on top right, then on “New repository”.

+
+
+

Then:

+
+Screenshot on GitHub just before a new repository is created +
+

Choose a repository name, add a short description, and in this case make sure to check “Add a +README file”. Finally “Create repository”.

+
+
+

Upload your files

+

Now that the repository is created, you can upload your files:

+
+Screenshot on GitHub just before uploading files +
+

Click on the “+” symbol and then on “Upload files”.

+
+
+
+
+
+
+

Remote repositories

+

In this exercise we have pushed our local repository to a remote repository. +We will learn how to work with remote repositories in detail in the +collaborative distributed version +control lesson. To store +your git data on another server, you use remotes. A remote is a repository +on its own, with its own branches. We can push changes to the remote and +pull from the remote.

+

You might use remotes to:

+
    +
  • Back up your own work or make your work findable.

  • +
  • To collaborate with other people.

  • +
+

There are different types of remotes:

+
    +
  • If you have a server you can SSH to, you can use that as a remote.

  • +
  • GitHub is a popular, closed-source commercial site.

  • +
  • GitLab is a popular, open-core +commercial site. Many universities have their own private GitLab servers +set up.

  • +
  • Bitbucket is yet another popular commercial site.

  • +
  • Another option is NotABug.

  • +
  • There are more …

  • +
+
+
+

Is putting software on GitHub/GitLab/… publishing?

+

It is a good first step but to make your code truly findable and +accessible, condider making your code citable and persistent: Get a +persistent identifier (PID) such as DOI in addition to sharing the code +publicly, by using services like Zenodo or similar +services.

+
+
+
+
+
+

Practical advice: how much Git is necessary?

+
+

Instructor note

+
    +
  • 20 min teaching/discussion

  • +
+
+
+

Writing useful commit messages

+

Useful commit messages summarize the change and provide context.

+

If you need a commit message that is longer than one line, +then the convention is: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+

Good example:

+
increase alpha to 2.0 for faster convergence
+
+the motivation for this change is
+to enable ...
+...
+(more context)
+...
+this is based on a discussion in #123
+
+
+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

What level of branching complexity is necessary for each project?

+

Simple personal projects:

+
    +
  • Typically start with just the main branch.

  • +
  • Use branches for unfinished/untested ideas.

  • +
  • Use branches when you are not sure about a change.

  • +
  • Use tags to mark important milestones.

  • +
  • If you are unsure what to do with unfinished and not working code, commit it +to a branch.

  • +
+

Projects with few persons: you accept things breaking sometimes

+
    +
  • It might be reasonable to commit to the main branch and feature branches.

  • +
+

Projects with few persons: changes are reviewed by others

+
    +
  • You create new feature branches for changes.

  • +
  • Changes are reviewed before they are merged to the main branch +(more about that in the collaborative Git lesson).

  • +
  • Consider to write-protect the main branch so that it can only be changed +with pull requests or merge requests.

  • +
+
+
+

How about staging and committing?

+
    +
  • Commit early and often: rather create too many commits than too few. +You can always combine commits later.

  • +
  • Once you commit, it is very, very hard to really lose your code.

  • +
  • Always fully commit (or stash) before you do dangerous things, so that you know you are safe. +Otherwise it can be hard to recover.

  • +
  • Later you can start using the staging area (where you first stage and then commit in a second step).

  • +
  • Later start using git add -p and/or git commit -p.

  • +
+
+
+

How large should a commit be?

+
    +
  • Better too small than too large (easier to combine than to split).

  • +
  • Often I make a commit at the end of the day (this is a unit I would not like to lose).

  • +
  • Smaller sized commits may be easier to review for others than huge commits.

  • +
  • Imperfect commits are better than no commits.

  • +
  • A commit should not contain unrelated changes to simplify review and possible +repair/adjustments/undo later (but again: imperfect commits are better than no commits).

  • +
+
+
+

Keypoints

+
    +
  • There is no one size fits all - start simple and grow your project.

  • +
+
+
+

Discussion

+

How do you [plan to] use Git?

+
    +
  • Advanced users or beginners, please provide your input in the online collaborative document.

  • +
+
+
+
+
+

What to avoid

+

The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas.

+

Postponing commits because the changes are “unfinished”/”ugly”: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all.

+

Not updating your branch before starting new work: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later. +So update your branch before adding new commits.

+

Commit unrelated changes together: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects.

+

Too ambitious branch which risks to never get completed: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere.

+

Committing generated files: Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files where +you can list which files and paths should be ignored by Git. You can also use +wild-cards to ignore files with a certain extension or files in a certain +directory.

+

Over-engineering the branch layout and safeguards in small projects: This +may prevent people from contributing (maybe even including yourself?). Add more +restrictions and safeguards only as the project and the group of collaborators +grows.

+

Commit messages that explain what has been changed but do not explain why it has been +changed: This is as useful as code comments which describe the “obvious” such +as “this is a loop” instead of explaining why something is done this way. +But don’t let perfect commit messages stop you from the most important point, committing often (first point).

+

Commit huge files: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent git rm does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request.

+
+

Discussion

+

Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements.

+
+
+
+
+
+

Basics

+
+

Objectives

+
    +
  • Learn to create Git repositories and make commits.

  • +
  • Get a grasp of the structure of a repository.

  • +
  • Learn how to inspect the project history.

  • +
  • Learn how to write useful commit log messages.

  • +
+
+
+

Instructor note

+
    +
  • 35 min teaching/type-along

  • +
  • 40 min exercise

  • +
+
+
+

What is Git, and what is a Git repository?

+
    +
  • Git is a version control system: can record/save snapshots and track the content of a folder as it changes over time.

  • +
  • Every time we commit a snapshot, Git records a snapshot of the entire project, saves it, and assigns it a version.

  • +
  • These snapshots are kept inside a sub-folder called .git.

  • +
  • If we remove .git, we remove the repository and history (but keep the working directory!).

  • +
  • The directory .git uses relative paths - you can move the whole repository somewhere else and it will still work.

  • +
  • Git doesn’t do anything unless you ask it to (it does not record anything automatically).

  • +
  • Multiple interfaces to Git exist (command line, graphical interfaces, web interfaces).

  • +
+
+
+

Recording a snapshot with Git

+
    +
  • Git takes snapshots only if we request it.

  • +
  • We will record changes in two steps (we will later explain why this is a recommended practice).

  • +
  • Example (we don’t need to type yet):

    +
    $ git add FILE.txt
    +$ git commit
    +
    +$ git add FILE.txt ANOTHERFILE.txt
    +$ git commit
    +
    +
    +
  • +
  • We first focus (git add, we “stage” the change), then record (git commit):

  • +
+
+Git staging +
+

Git staging and committing.

+
+
+
+

Question for the more advanced participants

+

What do you think will be the outcome if you +stage a file and then edit it and stage it again, do this several times and +at the end perform a commit? Think of focusing several scenes and pressing the +shutter at the end.

+
+
+
+

Configuring Git command line

+

Before we start using Git on the command line, we need to configure Git. +This is also part of the +installation instructions +but we need to make sure we all have +set name, email address, editor, and +default branch:

+
$ git config --global user.name "Your Name"
+$ git config --global user.email yourname@example.com
+$ git config --global core.editor nano
+$ git config --global init.defaultBranch main
+
+
+

Verify with:

+
$ git config --list
+
+
+
+

Instructor note

+

Instructors, give learners enough time to do the above configuration steps.

+
+
+
+

Type-along: Tracking a guacamole recipe with Git

+

We will learn how to initialize a Git repository, how to track changes, and how +to make delicious guacamole! (Inspiration for this example based on a +suggestion by B. Smith in a discussion in the Carpentries mailing list)

+

The motivation for taking a cooking recipe instead of a program is that everybody can relate to cooking +but not everybody may be able to relate to a program written in e.g. Python or another specific language.

+
+

Instructor note

+

Instructors, please encourage now that participants type along.

+
+
+

Note

+

It is possible to go through this lesson in the command line or in the browser +(on GitHub).

+
    +
  • We recommend to start with the command line but later to also try in the browser.

  • +
  • If you get really stuck in the command line, try following in the browser and +later you can try to return to the command line.

  • +
+
+
+
+

Creating a repository

+

One of the basic principles of Git is that it is easy to create repositories:

+
+
$ mkdir recipe
+$ cd recipe
+$ git init -b main
+
+
+

That’s it! With git init -b main have now created an empty Git repository +where main is the default branch (more about branches later).

+

We will use git status a lot to check out what is going on:

+
$ git status
+
+On branch main
+
+No commits yet
+
+nothing to commit (create/copy files and use "git add" to track)
+
+
+

We will make sense of this information during this workshop.

+
+
+
+

Adding files and committing changes

+

Let us now create two files.

+

One file is called ingredients.txt and contains:

+
* 2 avocados
+* 1 chili
+* 1 lime
+* 2 tsp salt
+
+
+

The second file is called instructions.txt and contains:

+
* chop avocados
+* chop onion
+* chop chili
+* squeeze lime
+* add salt
+* and mix well
+
+
+
+

As mentioned above, in Git you can always check the status of files in your repository using +git status. It is always a safe command to run and in general a good idea to +do when you are trying to figure out what to do next:

+
$ git status
+
+On branch main
+
+No commits yet
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    ingredients.txt
+    instructions.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+
+

The two files are untracked in the repository (directory). You want to add the files (focus the camera) +to the list of files tracked by Git. Git does not track +any files automatically and you need make a conscious decision to add a file. Let’s do what +Git hints at, and add the files, one by one:

+
$ git add ingredients.txt
+$ git status
+
+On branch main
+
+No commits yet
+
+Changes to be committed:
+  (use "git rm --cached <file>..." to unstage)
+    new file:   ingredients.txt
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+    instructions.txt
+
+
+

Now this change is staged and ready to be committed. +Let us now commit the change to the repository:

+
$ git commit -m "adding ingredients"
+
+[main (root-commit) f146d25] adding ingredients
+ 1 file changed, 4 insertions(+)
+ create mode 100644 ingredients.txt
+
+
+

Right after we query the status to get this useful command into our muscle memory:

+
$ git status
+
+
+

Now stage and commit also the other file:

+
$ git add instructions.txt
+$ git commit -m "adding instructions"
+
+
+

We will add a third file to the repository, README.md, containing:

+
# recipe
+
+This is an exercise repository.
+
+
+

Now stage and commit also the README.md file:

+
$ git add README.md
+$ git commit -m "adding README"
+
+
+

What does the -m flag mean? Let us check the help page for that command:

+
$ git help commit
+
+
+

You should see a very long help page as the tool is very versatile (press q to quit). +Do not worry about this now but keep in mind that you can always read the help files +when in doubt. Searching online can also be useful, but choosing search terms +to find relevant information takes some practice and discussions in some +online threads may be confusing. +Note that help pages also work when you don’t have a network connection!

+
+
+
+

Exercise: Record changes

+
+

Basic-1: Record changes

+

Add 1/2 onion to ingredients.txt and also the instruction +to “enjoy!” to instructions.txt.

+
+

After modifying the files, do not stage the changes yet (do not git add +yet).

+

When you are done editing the files, try git diff:

+
$ git diff
+
+
+

You will see (can you identify in there the two added lines?):

+
diff --git a/ingredients.txt b/ingredients.txt
+index 4422a31..ba8854f 100644
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@ -2,3 +2,4 @@
+ * 1 chili
+ * 1 lime
+ * 2 tsp salt
++* 1/2 onion
+diff --git a/instructions.txt b/instructions.txt
+index 7811273..2b11074 100644
+--- a/instructions.txt
++++ b/instructions.txt
+@@ -4,3 +4,4 @@
+ * squeeze lime
+ * add salt
+ * and mix well
++* enjoy!
+
+
+

Now first stage and commit each change separately (what happens when we leave out the -m flag?):

+
$ git add ingredients.txt
+$ git commit -m "add half an onion"
+$ git add instructions.txt
+$ git commit                   # <-- we have left out -m "..."
+
+
+

When you leave out the -m flag, Git should open an editor where you can edit +your commit message. This message will be associated and stored with the +changes you made. This message is your chance to explain what you’ve done and +convince others (and your future self) that the changes you made were +justified. Write a message and save and close the file.

+

When you are done committing the changes, experiment with these commands:

+
$ git log
+$ git log --stat
+$ git log --oneline
+
+
+
+
+
+
+

Git history and log

+
+

If you haven’t yet, please try now git log:

+
$ git log
+
+commit e7cf023efe382340e5284c278c6ae2c087dd3ff7 (HEAD -> main)
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:47 2023 +0200
+
+    don't forget to enjoy
+
+commit 79161b6e67c62ad4688a58c1e54183334611a390
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 19:12:32 2023 +0200
+
+    add half an onion
+
+commit a3394e39535343c4dae3bb4f703741a31aa8b78a
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:47:14 2023 +0200
+
+    adding README
+
+commit 369624674e63de48055a65bf63055bd59c985d22
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:46:58 2023 +0200
+
+    adding instructions
+
+commit f146d25b94569a15e94d7f0da6f15d7554f76c49
+Author: Radovan Bast <bast@users.noreply.github.com>
+Date:   Sun Sep 17 18:35:52 2023 +0200
+
+    adding ingredients
+
+
+
+
    +
  • We can browse the development and access each state that we have committed.

  • +
  • The long hashes uniquely label a state of the code.

  • +
  • They are not just integers counting 1, 2, 3, 4, … (why?).

  • +
  • Output is in reverse chronological order, i.e. newest commits on top.

  • +
  • We will use them when comparing versions and when going back in time.

  • +
  • git log --oneline only shows the first 7 characters of the commit hash and is good to get an overview.

  • +
  • If the first characters of the hash are unique it is not necessary to type the entire hash.

  • +
  • git log --stat is nice to show which files have been modified.

  • +
+
+
+

Optional exercises: Comparing changes

+
+

(optional) Basic-2: Comparing and showing commits

+
+
    +
  1. Have a look at specific commits with git show HASH.

  2. +
  3. Inspect differences between commit hashes with git diff HASH1 HASH2.

  4. +
+
+
+
+

(optional) Basic-3: Visual diff tools

+

This exercise is only relevant for the command line. In the browser, +the preview is already side-by-side and “visual”.

+
    +
  • Make further modifications and experiment with git difftool (requires installing one of the visual diff tools):

  • +
+

On Windows or Linux:

+
$ git difftool --tool=meld HASH
+
+
+

On macOS:

+
$ git difftool --tool=opendiff HASH
+
+
+
+Git difftool using meld +
+

Git difftool using meld.

+
+
+

You probably want to use the same visual diff tool every time and +you can configure Git for that:

+
$ git config --global diff.tool meld
+
+
+
+
+

(optional) Basic-4: Browser and command line

+

You have noticed that it is possible to work either in the command +line or in the browser. It could help to deepen the understanding +trying to do the above steps in both.

+
    +
  • If you have managed to do the above in the command line, try now in the browser.

  • +
  • If you got stuck in the command line and move to the browser, try now to trouble-shoot the command line Git.

  • +
+
+
+
+

Writing useful commit messages

+

Using git log --oneline or browsing a repository on the web, we better +understand that the first line of the commit message is very important.

+

Good example:

+
increase threshold alpha to 2.0
+
+the motivation for this change is
+to enable ...
+...
+this is based on a discussion in #123
+
+
+

Convention: one line summarizing the commit, then one empty line, +then paragraph(s) with more details in free form, if necessary.

+
    +
  • Why something was changed is more important than what has changed.

  • +
  • Cross-reference to issues and discussions if possible/relevant.

  • +
  • Bad commit messages: “fix”, “oops”, “save work”

  • +
  • Bad examples: http://whatthecommit.com

  • +
  • Write commit messages in English that will be understood +15 years from now by someone else than you. Or by your future you.

  • +
  • Many projects start out as projects “just for me” and end up to be successful projects +that are developed by 50 people over decades.

  • +
  • Commits with multiple authors are possible.

  • +
+

Good references:

+ +
+

Note

+

A great way to learn how to write commit messages and to get inspired by their +style choices: browse repositories of codes that you use/like:

+

Some examples (but there are so many good examples):

+ +

When designing commit message styles consider also these:

+
    +
  • How will you easily generate a changelog or release notes?

  • +
  • During code review, you can help each other improving commit messages.

  • +
+
+

But remember: it is better to make any commit, than no commit. Especially in small projects. +Let not the perfect be the enemy of the good enough.

+
+
+

Ignoring files and paths with .gitignore

+
+

Discussion

+
    +
  • Should we add and track all files in a project?

  • +
  • How about generated files?

  • +
  • Why is it considered a bad idea to commit compiled binaries to version control?

  • +
  • What types of generated files do you know?

  • +
+
+

Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files. Example:

+
# ignore compiled python 2 files
+*.pyc
+# ignore compiled python 3 files
+__pycache__
+
+
+

An example taken from the official Git documentation:

+
# ignore objects and archives, anywhere in the tree.
+*.[oa]
+# ignore generated html files,
+*.html
+# except foo.html which is maintained by hand
+!foo.html
+# ignore everything under build directory
+build/
+
+
+
    +
  • .gitignore should be part of the repository because we want to make sure that all developers see the same behavior.

  • +
  • All files should be either tracked or ignored.

  • +
  • .gitignore uses something called a +shell glob syntax for +determining file patterns to ignore. You can read more about the syntax in the +documentation.

  • +
  • You can have .gitignore files in lower level directories and they affect the paths below.

  • +
+
+
+

Graphical user interfaces

+

We have seen how to make commits in the command line and via the GitHub website. +But it is also possible to work from within a Git graphical user interface (GUI):

+ +
+
+

Summary

+

Now we know how to save snapshots:

+
$ git add FILE(S)
+$ git commit
+
+
+

And this is what we do as we program.

+

Every state is then saved and later we will learn how to go back to these “checkpoints” +and how to undo things.

+
$ git init -b main  # initialize new repository (main is default branch)
+$ git add           # add files or stage file(s)
+$ git commit        # commit staged file(s)
+$ git status        # see what is going on
+$ git log           # see history
+$ git diff          # show unstaged/uncommitted modifications
+$ git show          # show the change for a specific commit
+$ git mv            # move/rename tracked files
+$ git rm            # remove tracked files
+
+
+

Git is not ideal for large binary files +(for this consider git-annex).

+
+

Basic-5: Test your understanding

+

Which command(s) below would save the changes of myfile.txt +to an existing local Git repository?

+
    +
  1. $ git commit -m "my recent changes"
    +
    +
    +
  2. +
  3. $ git init myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  4. +
  5. $ git add myfile.txt
    +$ git commit -m "my recent changes"
    +
    +
    +
  6. +
  7. $ git commit -m myfile.txt "my recent changes"
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • It takes only one command to initialize a Git repository: git init -b main.

  • +
  • Commits should be used to tell a story.

  • +
  • Git uses the .git folder to store the snapshots.

  • +
  • Don’t be afraid to stage and commit often. Better too often than not often enough.

  • +
+
+
+
+
+

Branching and merging

+
+

Objectives

+
    +
  • Be able to create and merge branches.

  • +
  • Know the difference between a branch and a tag.

  • +
+
+
+

Instructor note

+
    +
  • 30 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Motivation for branches

+

In the previous section we tracked a guacamole recipe with Git.

+

Up until now our repository had only one branch with one commit coming +after the other:

+
+Linear Git repository +
+

Linear Git repository.

+
+
+
    +
  • Commits are depicted here as little boxes with abbreviated hashes.

  • +
  • Here the branch main points to a commit.

  • +
  • “HEAD” is the current position (remember the recording head of tape +recorders?). When we say HEAD, we mean those literal letters - +this isn’t a placeholder for something else.

  • +
  • When we talk about branches, we often mean all parent commits, not only the commit pointed to.

  • +
+

Now we want to do this:

+
+Branching explained with a gopher +
+

Image created using https://gopherize.me/ +(inspiration).

+
+
+

Software development is often not linear:

+
    +
  • We typically need at least one version of the code to “work” (to compile, to give expected results, …).

  • +
  • At the same time we work on new features, often several features concurrently. +Often they are unfinished.

  • +
  • We need to be able to separate different lines of work really well.

  • +
+

The strength of version control is that it permits the researcher to isolate +different tracks of work, which can later be merged to create a composite +version that contains all changes:

+
+Isolated tracks of work +
+

Isolated tracks of work.

+
+
+
    +
  • We see branching points and merging points.

  • +
  • Main line development is often called main or master.

  • +
  • Other than this convention there is nothing special about main or master, it is a branch like any other.

  • +
  • Commits form a directed acyclic graph (we have left out the arrows to avoid confusion about the time arrow).

  • +
+

A group of commits that create a single narrative are called a branch. +There are different branching strategies, but it is useful to think that a branch +tells the story of a feature, e.g. “fast sequence extraction” or “Python interface” or “fixing bug in +matrix inversion algorithm”.

+
+

An important alias

+

We will now define an alias in Git, to be able to nicely visualize branch +structure in the terminal without having to remember a long Git command +(more details about aliases are given +in a later section). This is extensively used in the rest of this +and other lessons:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+
+
+
+
+

Instructor note

+

Instructors, please demonstrate how to set this alias and ensure that +all create it. This is very important for this lesson and +git-collaborative.

+
+

Let us inspect the project history using the git graph alias:

+
$ git graph
+
+* e7cf023 (HEAD -> main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • We have a couple commits and only +one development line (branch) and this branch is called main.

  • +
  • Commits are states characterized by a 40-character hash (checksum).

  • +
  • git graph print abbreviations of these checksums.

  • +
  • Branches are pointers that point to a commit.

  • +
  • Branch main points to a commit (in this example it is e7cf023efe382340e5284c278c6ae2c087dd3ff7 but on your computer +the hash will be different).

  • +
  • HEAD is another pointer, it points to where we are right now (currently main)

  • +
+

In the following we will learn how to create branches, +how to switch between them, how to merge branches, +and how to remove them afterwards.

+
+
+

Creating and working with branches

+
+

Instructor note

+

We do the following part together. Encourage participants to type along.

+
+
+

It is possible to create and merge branches directly on GitHub

+
    +
  • However, we do not have screenshots for that in this episode

  • +
  • But if you prefer to work in the browser, please try it

  • +
  • Please contribute screenshots to this lesson

  • +
+
+

Let’s create a branch called experiment where we add cilantro to ingredients.txt +(text after “#” are comments and not part of the command).

+
$ git branch experiment main  # creates branch "experiment" from "main"
+$ git switch experiment       # switch to branch "experiment"
+$ git branch                  # list all local branches and show on which branch we are
+
+
+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+
    +
  • Verify that you are on the experiment branch (note that git graph also +makes it clear what branch you are on: HEAD -> branchname):

    +
    $ git branch
    +
    +* experiment
    +  main
    +
    +
    +

    This command shows where we are, it does not create a branch.

    +
  • +
  • Then add 2 tbsp cilantro on top of the ingredients.txt:

    +
    * 2 tbsp cilantro
    +* 2 avocados
    +* 1 chili
    +* 1 lime
    +* 2 tsp salt
    +* 1/2 onion
    +
    +
    +
  • +
  • Stage this and commit it with the message “let us try with some cilantro”.

  • +
  • Then reduce the amount of cilantro to 1 tbsp, stage and commit again with “maybe little bit less cilantro”.

  • +
+

We have created two new commits:

+
$ git graph
+
+* bcb8b78 (HEAD -> experiment) maybe little bit less cilantro
+* f6ec7b7 let us try with some cilantro
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
    +
  • The branch experiment is two commits ahead of main.

  • +
  • We commit our changes to this branch.

  • +
+
+
+

Exercise: Create and commit to branches

+
+

Branch-1: Create and commit to branches

+

In this exercise, you will create another new branch and few more commits. +We will use this in the next section, to practice +merging. The goal of the exercise is to end up with 3 branches.

+
    +
  • Change to the branch main.

  • +
  • Create another branch called less-salt.

    +
      +
    • Note! makes sure you are on main branch when you create the less-salt branch.

    • +
    • A safer way would be to explicitly mention to create from the main branch +as shown below:

      +
      $ git branch less-salt main
      +
      +
      +
    • +
    +
  • +
  • Switch to the less-salt branch.

  • +
  • On the less-salt branch reduce the amount of salt.

  • +
  • Commit your changes to the less-salt branch.

  • +
+

Use the same commands as we used above.

+

We now have three branches (in this case HEAD points to less-salt):

+
$ git branch
+
+  experiment
+* less-salt
+  main
+
+$ git graph
+
+* bf28166 (HEAD -> less-salt) reduce amount of salt
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 (main) don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Here is a graphical representation of what we have created:

+
+_images/git-branch-2.svg
+
    +
  • Now switch to main.

  • +
  • In a new commit, improve the README.md file (we added the word “Guacamole”):

    +
    # Guacamole recipe
    +
    +This is an exercise repository.
    +
    +
    +
  • +
+

Now you should have this situation:

+
$ git graph
+
+* b4af65b (HEAD -> main) improve the documentation
+| * bf28166 (less-salt) reduce amount of salt
+|/
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+
+_images/git-branch-3.svg
+

And for comparison this is how it looks on GitHub.

+
+
+
+

Exercise: Merging branches

+

It turned out that our experiment with cilantro was a good idea. +Our goal now is to merge experiment into main.

+
+

Branch-2: Merge branches

+

Merge experiment and less-salt back into main following the lesson below +until the point where we start deleting branches.

+
+
+

If you got stuck in the above exercises or joined later

+

If you got stuck in the above exercises or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git switch experiment
+$ git switch less-salt
+$ git switch main
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

First we make sure we are on the branch we wish to merge into:

+
$ git branch
+
+  experiment
+  less-salt
+* main
+
+
+

Then we merge experiment into main:

+
$ git merge experiment
+
+
+
+_images/git-merge-1.svg
+

We can verify the result:

+
$ git graph
+
+*   81fcc0c (HEAD -> main) Merge branch 'experiment'
+|\
+| * bcb8b78 (experiment) maybe little bit less cilantro
+| * f6ec7b7 let us try with some cilantro
+* | b4af65b improve the documentation
+|/
+| * bf28166 (less-salt) reduce amount of salt
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

What happens internally when you merge two branches is that Git creates a new +commit, attempts to incorporate changes from both branches and records the +state of all files in the new commit. While a regular commit has one parent, a +merge commit has two (or more) parents.

+

To view the branches that are merged into the current branch we can use the command:

+
$ git branch --merged
+
+  experiment
+* main
+
+
+

We are also happy with the work on the less-salt branch. Let us merge that +one, too, into main:

+
$ git branch  # make sure you are on main
+$ git merge less-salt
+
+
+
+Commit graph after merge
+

Commit graph after merge.

+
+
+

We can verify the result in the terminal:

+
$ git graph
+
+*   4e03d4b (HEAD -> main) Merge branch 'less-salt'
+|\
+| * bf28166 (less-salt) reduce amount of salt
+* |   81fcc0c Merge branch 'experiment'
+|\ \
+| * | bcb8b78 (experiment) maybe little bit less cilantro
+| * | f6ec7b7 let us try with some cilantro
+| |/
+* / b4af65b improve the documentation
+|/
+* e7cf023 don't forget to enjoy
+* 79161b6 add half an onion
+* a3394e3 adding README
+* 3696246 adding instructions
+* f146d25 adding ingredients
+
+
+

Observe how Git nicely merged the changed amount of salt and the new ingredient in the same file +without us merging it manually:

+
$ cat ingredients.txt
+
+* 1 tbsp cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

If the same file is changed in both branches, Git attempts to incorporate both +changes into the merged file. If the changes overlap then the user has to +manually settle merge conflicts (we will do that later).

+
+
+

Deleting branches safely

+

Both feature branches are merged:

+
$ git branch --merged
+
+  experiment
+  less-salt
+* main
+
+
+

This means we can delete the branches:

+
$ git branch -d experiment
+$ git branch -d less-salt
+
+
+

This is the result:

+
+Commit graph after merged branches were deleted
+

Commit graph after merged branches were deleted.

+
+
+

We observe that when deleting branches, +only the pointers (“sticky notes”) disappeared, not the commits.

+

Git will not let you delete a branch which has not been reintegrated unless you +insist using git branch -D. Even then your commits will not be lost but you +may have a hard time finding them as there is no branch pointing to them.

+
+
+

Optional exercises with branches

+

The following exercises are more advanced, absolutely no problem to postpone them to a +few months later. If you give them a go, keep in mind that you might run into conflicts, +which we will learn to resolve in the next section.

+
+

(optional) Branch-3: Perform a fast-forward merge

+
    +
  1. Create a new branch from main and switch to it.

  2. +
  3. Create a couple of commits on the new branch (for instance edit README.md):

    +
    +_images/git-pre-ff.svg
    +
  4. +
  5. Now switch to main.

  6. +
  7. Merge the new branch to main.

  8. +
  9. Examine the result with git graph.

  10. +
  11. Have you expected the result? Discuss what you see.

  12. +
+ +
+
+

(optional) Branch-4: Rebase a branch (instead of merge)

+

As an alternative to merging branches, one can also rebase branches. +Rebasing means that the new commits are replayed on top of another branch +(instead of creating an explicit merge commit). +Note that rebasing changes history and should not be done on public commits!

+
    +
  1. Create a new branch, and make a couple of commits on it.

  2. +
  3. Switch back to main, and make a couple of commits on it.

  4. +
  5. Inspect the situation with git graph.

  6. +
  7. Now rebase the new branch on top of main by first switching to the new branch, and then git rebase main.

  8. +
  9. Inspect again the situation with git graph. Notice that the commit hashes have changed - think about why!

  10. +
+ +
+
+
+

Tags

+
    +
  • A tag is a pointer to a commit but in contrast to a branch it does not ever +move when creating new commits later.

  • +
  • It can be useful to think of branches as sticky notes and of tags as +commemorative plaques.

  • +
  • We use tags to record particular states or milestones of a project at a given +point in time, like for instance versions (have a look at semantic versioning, +v1.0.3 is easier to understand and remember than 64441c1934def7d91ff0b66af0795749d5f1954a).

  • +
  • There are two basic types of tags: annotated and lightweight.

  • +
  • Use annotated tags since they contain the author and can be cryptographically signed using +GPG, timestamped, and a message attached.

  • +
+

Let’s add an annotated tag to our current state of the guacamole recipe:

+
$ git tag -a nobel-2023 -m "recipe I made for the 2023 Nobel banquet"
+
+
+

As you may have found out already, git show is a very versatile command. Try this:

+
$ git show nobel-2023
+
+
+

For more information about tags see for example +the Pro Git book chapter on the +subject.

+
+
+
+

Summary

+

Let us pause for a moment and recapitulate what we have just learned:

+
$ git branch               # see where we are
+$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+$ git merge NAME           # merge branch NAME (to current branch)
+$ git branch -d NAME       # delete branch NAME
+$ git branch -D NAME       # delete unmerged branch NAME
+
+
+

Since the following command combo is so frequent:

+
$ git branch NAME          # create branch NAME
+$ git switch NAME          # switch to branch NAME
+
+
+

There is a shortcut for it:

+
$ git switch --create NAME  # create branch NAME and switch to it
+
+
+
+

Typical workflows

+

With this there are two typical workflows:

+
$ git switch --create new-feature  # create branch, switch to it
+$ git commit                       # work, work, work, ..., and test
+$ git switch main                  # once feature is ready, switch to main
+$ git merge new-feature            # merge work to main
+$ git branch -d new-feature        # remove branch
+
+
+

Sometimes you have a wild idea which does not work. +Or you want some throw-away branch for debugging:

+
$ git switch --create wild-idea    # create branch, switch to it, work, work, work ...
+$ git switch main                  # realize it was a bad idea, back to main
+$ git branch -D wild-idea          # it is gone, off to a new idea
+
+
+
+
+

Branch-5: Test your understanding

+

Which of the following combos (one or more) creates a new branch and makes a commit to it?

+
    +
  1. $ git branch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  2. +
  3. $ git add file.txt
    +$ git branch new-branch
    +$ git switch new-branch
    +$ git commit
    +
    +
    +
  4. +
  5. $ git switch --create new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  6. +
  7. $ git switch new-branch
    +$ git add file.txt
    +$ git commit
    +
    +
    +
  8. +
+ +
+
+

Keypoints

+
    +
  • A branch is a division unit of work, to be merged with other units of work.

  • +
  • A tag is a pointer to a moment in the history of a project.

  • +
+
+
+
+
+
+

Conflict resolution

+
+

Objectives

+
    +
  • Understand merge conflicts sufficiently well to be able to fix them.

  • +
+
+
+

Instructor note

+
    +
  • 20 min teaching/type-along

  • +
  • 20 min exercise

  • +
+
+
+

Conflicts in Git and why they are good

+

Imagine we start with the following text file:

+
1 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch A somebody modifies:

+
2 tbsp cilantro
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1/2 onion
+
+
+

On branch B somebody else modifies:

+
1/2 tbsp cilantro
+2 avocados
+1 chili
+1 lime
+1 tsp salt
+1 onion
+
+
+

When we try to merge Git will figure out that we 2 limes and an entire onion +but does not know whether to reduce or increase the amount of cilantro:

+
?????????????????
+2 avocados
+1 chili
+2 lime
+1 tsp salt
+1 onion
+
+
+

Git is very good at resolving modifications when merging branches and +in most cases a git merge runs smooth and automatic. +Then a merge commit appears (unless fast-forward; see Optional exercises with branches) without you even noticing.

+

But sometimes the same portion of the code/text is modified on two branches +in two different ways and Git issues a conflict. +Then you need to tell Git which version to keep (resolve it).

+

There are several ways to do that as we will see.

+

Please remember:

+
    +
  • It is good that Git conflicts exist: Git will not silently overwrite one of +two differing modifications.

  • +
  • Conflicts may look scary, but are not that bad after a little bit of +practice. Also they are luckily rare.

  • +
  • Don’t be afraid of Git because of conflicts. You may not meet some conflicts +using other systems because you simply can’t do the kinds of things you do +in Git.

  • +
  • You can take human measures to reduce them.

  • +
+
+
+

The human side of conflicts

+
    +
  • What does it mean if two people do the same thing in two different ways?

  • +
  • What if you work on the same file but do two different things in the different sections?

  • +
  • What if you do something, don’t tell someone from 6 months, and then try to combine it with other people’s work?

  • +
  • How are conflicts avoided in other work? (Only one person working at once? +Declaring what you are doing before you start, if there is any chance someone +else might do the same thing, helps.)

  • +
  • Minor conflicts (two people revise spelling) vs semantic (two people rewrite +a function to add two different new features). How did Git solve these in +branching/merging easily?

  • +
+
+

Now we can go to show how Git controls when there is actually a conflict.

+
+
+

Preparing a conflict

+
+

Instructor note

+

We do the following together as type-along/demo.

+
+
+

If you got stuck previously or joined later

+

If you got stuck previously or joined later, +you can apply the commands below. +But skip this box if you managed to create branches.

+
$ cd ..  # step out of the current directory
+
+$ git clone https://github.com/coderefinery/recipe-before-merge.git
+$ cd recipe-before-merge
+
+$ git remote remove origin
+
+$ git graph
+
+
+

Or call a helper to un-stuck it for you.

+
+

We will make two branches, make two conflicting changes (both increase and +decrease the amount of cilantro), and later we will try to merge them +together.

+
    +
  • Create two branches from main: one called like-cilantro, one called dislike-cilantro:

    +
    $ git branch like-cilantro main
    +$ git branch dislike-cilantro main
    +
    +
    +
  • +
  • On the two branches make different modifications to the amount of the same ingredient:

  • +
  • On the branch like-cilantro we have the following change:

    +
    $ git diff main like-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6cacd50 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
  • And on the branch dislike-cilantro we have the following change:

    +
    $ git diff main dislike-cilantro
    +
    +
    +
    diff --git a/ingredients.txt b/ingredients.txt
    +index e83294b..6484462 100644
    +--- a/ingredients.txt
    ++++ b/ingredients.txt
    +@@ -1,4 +1,4 @@
    +-* 1 tbsp cilantro
    ++* 1/2 tbsp cilantro
    + * 2 avocados
    + * 1 chili
    + * 1 lime
    +
    +
    +
  • +
+
+
+

Merging conflicting changes

+

What do you expect will happen when we try to merge these two branches into +main?

+
+

Note

+

In case git switch does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git switch.

+
+

The first merge will work:

+
$ git switch main
+$ git status
+$ git merge like-cilantro
+
+Updating 4e03d4b..3caa632
+Fast-forward
+ ingredients.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+
+

But the second will fail:

+
$ git merge dislike-cilantro
+
+Auto-merging ingredients.txt
+CONFLICT (content): Merge conflict in ingredients.txt
+Automatic merge failed; fix conflicts and then commit the result.
+
+
+

Without conflict Git would have automatically created a merge commit, +but since there is a conflict, Git did not commit:

+
$ git status
+
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+  (use "git merge --abort" to abort the merge)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+	both modified:   ingredients.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+
+
+

Git won’t decide which to take and we need to decide. Observe how Git gives +us clear instructions on how to move forward.

+

Let us inspect the conflicting file:

+
$ cat ingredients.txt
+
+<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+* 2 avocados
+* 1 chili
+* 1 lime
+* 1 tsp salt
+* 1/2 onion
+
+
+

Git inserted resolution markers (the <<<<<<<, >>>>>>>, and =======).

+

Try also git diff:

+
$ git diff
+
+
+
diff --cc ingredients.txt
+index 6cacd50,6484462..0000000
+--- a/ingredients.txt
++++ b/ingredients.txt
+@@@ -1,4 -1,4 +1,10 @@@
+++<<<<<<< HEAD
+ +* 2 tbsp cilantro
+++=======
++ * 1/2 tbsp cilantro
+++>>>>>>> dislike-cilantro
+  * 2 avocados
+  * 1 chili
+  * 1 lime
+
+
+

git diff now only shows the conflicting part, nothing else.

+
+
+

Conflict resolution

+
<<<<<<< HEAD
+* 2 tbsp cilantro
+=======
+* 1/2 tbsp cilantro
+>>>>>>> dislike-cilantro
+
+
+

We have to edit the code/text between the resolution markers. You +only have to care about what Git shows you: Git stages all files +without conflicts and leaves the files with conflicts unstaged.

+
+

Steps to resolve a conflict

+
    +
  • Check status with git status and git diff.

  • +
  • Decide what you keep (the one, the other, or both or something +else). Edit the file to do this.

    +
      +
    • Remove the resolution markers, if not already done.

    • +
    • The file(s) should now look exactly how you want them.

    • +
    +
  • +
  • Check status with git status and git diff.

  • +
  • Tell Git that you have resolved the conflict with git add ingredients.txt +(if you use the Emacs editor with a certain plugin the editor may stage the +change for you after you have removed the conflict markers).

  • +
  • Verify the result with git status.

  • +
  • Finally commit the merge with only git commit. Everything is pre-filled.

  • +
+
+
+
+

Exercise: Create and resolve a conflict

+
+

Conflict-1: Create another conflict and resolve

+

In this exercise, we repeat almost exactly what we did above with a +different ingredient.

+
    +
  1. Create two branches before making any modifications.

  2. +
  3. Again modify some ingredient on both branches.

  4. +
  5. Merge one, merge the other and observe a conflict, resolve the conflict and commit the merge.

  6. +
  7. What happens if you apply the same modification on both branches?

  8. +
  9. If you create a branch like-avocados, commit a change, then from this +branch create another banch dislike-avocados, commit again, and try to +merge both branches into main you will not see a conflict. Can you +explain, why it is different this time?

  10. +
+ +
+
+
+

Optional exercises with conflict resolution

+
+

(optional) Conflict-2: Resolve a conflict when rebasing a branch

+
    +
  1. Create two branches where you anticipate a conflict.

  2. +
  3. Try to merge them and observe that indeed they conflict.

  4. +
  5. Abort the merge with git merge --abort.

  6. +
  7. What do you expect will happen if you rebase one branch on top of the +other? Do you anticipate a conflict? Try it out.

  8. +
+ +
+
+

(optional) Conflict-3: Resolve a conflict using mergetool

+
    +
  • Again create a conflict (for instance disagree on the number of avocados).

  • +
  • Stop at this stage:

    +
    Auto-merging ingredients.txt
    +CONFLICT (content): Merge conflict in ingredients.txt
    +Automatic merge failed; fix conflicts and then commit the result.
    +
    +
    +
  • +
  • Instead of resolving the conflict manually, use a visual tool +(requires installing one of the visual diff tools):

    +
    $ git mergetool
    +
    +
    +
    +Conflict resolution using mergetool +
    +
  • +
  • Your current branch is left, the branch you merge is right, result is in the middle.

  • +
  • After you are done, close and commit, git add is not needed when using git mergetool.

  • +
+

If you have not instructed Git to avoid creating backups when using mergetool, then to be on +the safe side there will be additional temporary files created. To remove those you can do +a git clean after the merging.

+

To view what will be removed:

+
$ git clean -n
+
+
+

To remove:

+
$ git clean -f
+
+
+

To configure Git to avoid creating backups at all:

+
$ git config --global mergetool.keepBackup false
+
+
+
+
+
+
+

Using “ours” or “theirs” strategy

+
    +
  • Sometimes you know that you want to keep “ours” version (version on the branch you are on) +or “theirs” (version on the merged branch).

  • +
  • Then you do not have to resolve conflicts manually.

  • +
  • See merge strategies.

  • +
+

Example (merge and in doubt take the changes from current branch):

+
$ git merge -s recursive -Xours less-avocados
+
+
+

Or (merge and in doubt take the changes from less-avocados branch):

+
$ git merge -s recursive -Xtheirs less-avocados
+
+
+
+
+
+

Aborting a conflicting merge

+

Sometimes you get a merge conflict but realize that you can’t solve it without +talking to a colleague (who created the other change) first. What to do?

+

You can abort the merge and postponing conflict resolution by resetting the +repository to HEAD (last committed state):

+
$ git merge --abort
+
+
+

The repository looks then exactly as it was before the merge.

+
+
+
+

Avoiding conflicts

+
    +
  • Human measures

    +
      +
    • Think and plan to which branch you will commit to.

    • +
    • Do not put unrelated changes on the same branch.

    • +
    +
  • +
  • Collaboration measures

    +
      +
    • Open an issue and discuss with collaborators before starting a long-living +branch.

    • +
    +
  • +
  • Project layout measures

    +
      +
    • Modifying global data often causes conflicts.

    • +
    • Modular programming reduces this risk.

    • +
    +
  • +
  • Technical measures

    +
      +
    • Share your changes early and often - this is one of the happy, +rare circumstances when everyone doing the selfish thing (e.g. git push as +early as practical) results in best case for everyone!

    • +
    • Pull/rebase often to keep up to date with upstream.

    • +
    • Resolve conflicts early.

    • +
    +
  • +
+
+

Discussion

+

Discuss how Git handles conflicts compared to services like Google Drive.

+
+
+

Keypoints

+
    +
  • Conflicts often appear because of not enough communication or not optimal +branching strategy.

  • +
+
+
+
+
+
+
+

Using the Git staging area

+
+

Objectives

+
    +
  • Learn how to tell a story with your commit history.

  • +
  • Demystify the Git staging area.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 10 min exercise

  • +
+
+
+

Commit history is telling a story

+

Your current code is very important, but the history can be just +as important - it tells a story about how your code came to be.

+
    +
  • Each individual line of code rarely stands alone.

  • +
  • You often want to see all the related changes together.

  • +
  • But you also hardly ever do one thing at once.

  • +
+

Along with your code, Git creates a history for you, and if your +history is clear then you are a long way to organized code.

+
+

Discussion

+

Here are five types of history. What are the advantages and +disadvantages of each, when you look at it later?

+

Example 1:

+
b135ec8 add features A, B, and C
+
+
+

Example 2 (newest commit is on top):

+
6f0d49f implement feature C
+fee1807 implement feature B
+6fe2f23 implement feature A
+
+
+

Example 3:

+
ab990f4 saving three months of miscellaneous work I forgot to commit
+
+
+

Example 4 (newest commit is on top):

+
bf39f9d more work on feature B
+45831a5 removing debug prints for feature A and add new file
+bddb280 more work on feature B and make feature A compile again
+72d78e7 feature A did not work and started work on feature B
+b135ec8 now feature A should work
+72e0211 another fix to make it compile
+61dd3a3 forgot file and bugfix
+49dc419 wip (work in progress)
+
+
+

Example 5 (newest commit is on top):

+
1949dc4 Work of 2020-04-07
+a361dd3 Work of 2020-04-06
+1172e02 Work of 2020-04-03
+e772d78 Work of 2020-04-02
+
+
+

Discuss these examples. Can you anticipate problems?

+
+

We want to have nice commits. But we also want to “save often” +(checkpointing) - how can we have both?

+
    +
  • We will now learn to create nice commits using git commit --patch and/or the staging area.

  • +
  • Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits.

  • +
  • The staging area isn’t the only way to organize your history nicely, some alternatives are discussed at the end of the lesson.

  • +
+
+
+

Interactive commits

+
    +
  • The simplest ways to solve this is to do interactive commits: +the git commit --patch option (or git commit -p for short).

  • +
  • It will present you with every change you have made individually, +and you can decide which ones to commit right now.

  • +
  • Reference and key commands

    +
      +
    • git commit --patch to start the interactive commit

    • +
    • y to use the change

    • +
    • n to skip the change

    • +
    • s (split) if there are several changes grouped together, but +separated by a blank line, split them into separate choices.

    • +
    • q aborts everything.

    • +
    • ? for more options.

    • +
    +
  • +
  • The -p option is also available on commit, restore, checkout, reset, and add.

  • +
+
+
+

Exercise: Interactive commits

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+
+
+

The staging area

+
    +
  • The interactive commits above are great, but what if there are so +many changes that you can’t sort them out in one shot?

  • +
  • What if you make progress and want to record it somehow, but it’s +not ready to be committed?

  • +
  • The staging area is a place to record things before committing.

  • +
+
+

Instructor note

+

We give two examples and the instructor can pick one or both:

+
    +
  • Analogy using moving boxes

  • +
  • Analogy using shopping receipts

  • +
+
+
+

Discussion

+

Analogy using moving boxes

+
    +
  • You’re moving and you have a box to pack your things in.

  • +
  • You can put stuff into the box, but you can also take stuff out of the box.

  • +
  • You wouldn’t want to mix items from the bathroom, kitchen, and living room +into the same box.

  • +
  • The box corresponds to the staging area of Git, where you can craft your commits.

  • +
  • Committing is like sealing the box and sticking a label on it.

  • +
  • You wouldn’t want to label your box with “stuff”, but rather give a more +descriptive label.

  • +
  • See also https://dev.to/sublimegeek/git-staging-area-explained-like-im-five-1anh

  • +
+

Analogy using shopping receipts

+
    +
  • You need to go shopping and buy some stuff for work and for home. +You need two separate receipts.

  • +
  • Bad idea: go through the store get home stuff, pay, start at the +beginning and go through the store again. This is inefficient and +annoying.

  • +
  • What you actually do:

    +
      +
    • Go through the store and put everything you need in your shopping +basket.

    • +
    • Get to the check-out. Put your home stuff on the conveyor belt +(git add). Check both the belt (git diff --staged) and your +basket (git diff) to make sure you got all your home stuff.

    • +
    • Pay (git commit)

    • +
    • Repeat for work stuff.

    • +
    +
  • +
+

In order to keep organized, you have to use multiple locations to +stage things in sequence.

+
+
+
+

Staging area commands

+

The staging area is a middle ground between what you have done to your files +(the working directory) and what you have last committed (the HEAD commit). +Just like the name implies, it lets you prepare (stage) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since you can modify and stage several times before committing.

+

git add stages/prepares for the next commit:

+
                git add
+ [project*]  <------------  project*
+                               ^
+                               | modify with editor
+                               |
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git commit creates a new commit:

+
  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+  HEAD~2          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git reset --soft HEAD~1 (move HEAD back by one but keep changes and stage +them) would do the opposite of git commit. (in this case, HEAD +is literally this - not a replacement)

+

Going back to the last staged version:

+
              git restore
+ [project*]  ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Unstaging changes with git restore --staged:

+
          git restore --staged
+             ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Discarding unstaged changes:

+
                            project*
+                               |
+                               | git restore
+                               v
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Comparing:

+
                git diff
+ [project*]  <----------->  project*
+    ^                          ^
+    | git diff --staged        | git diff HEAD
+    v                          v
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+
+Staging basics +
+

The different states of the repository and the commands to move from one to +another.

+
+
+
+
+

Exercise: Using the staging area

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+

Discussion

+
    +
  • When is it better to “save” a change as commit, when is it better to “save” +it with git add?

  • +
  • Is it a problem to commit many small changes?

  • +
+
+
+

Keypoints

+
    +
  • The staging area helps us to create well-defined commits.

  • +
+
+
+
+
+

Undoing and recovering

+
+

Objectives

+
    +
  • Learn to undo changes safely

  • +
  • See when undone changes are permanently deleted and when they can be retrieved

  • +
+
+
+

Instructor note

+
    +
  • 25 min teaching/type-along

  • +
  • 25 min exercise

  • +
+
+

One of the main points of version control is that you can go back in +time to recover. Unlike this xkcd comic implies: https://xkcd.com/1597/

+

In this episode we show a couple of commands that can be used to undo mistakes. +We also list a couple of common mistakes and discuss how to recover from them. +Some commands preserve the commit history and some modify commit history. +Modifying history? Isn’t a “commit” permanent?

+
    +
  • You can modify old commit history.

  • +
  • But if you have shared that history already, modifying it can make +a huge mess.

  • +
+
+

It is almost always possible to recover

+

As long as you commit something once (or at least git add it), you +can almost always go back to it, no matter what you do. +But you may need to ask Stack Overflow or your local +guru… until that guru becomes you.

+
+
+

Nice resource to visually simulate Git operation

+

git-sim +is a nice resouce to visually simulate Git operations listed in this episode +below, in your own repos with a single terminal command.

+
+
+
+

Undoing your recent, uncommitted and unstaged changes (preserves history)

+
+

Note

+

In case git restore does not work, your Git version might be older than from 2019. +On older Git it is git checkout instead of git restore.

+
+

You do some work, and want to undo your uncommitted and unstaged modifications. +You can always do that with:

+
    +
  • git restore . (the dot means “here and in all folders below”)

  • +
+

You can also undo things selectively:

+
    +
  • git restore -p (decide which portions of changes to undo) or git restore PATH (decide which path/file)

  • +
+

If you have staged changes, you have at least two options to undo the staging:

+
    +
  • git restore --staged . followed by git status and git restore .

  • +
  • git reset --hard HEAD throws away everything that is not in last +commit (HEAD - this literal word, this isn’t a placeholder)

  • +
+
+
+
+

Reverting commits (preserves history)

+

Imagine we made a few commits. +We realize that the latest commit e02efcd was a mistake and we wish to undo it:

+
$ git log --oneline
+
+e02efcd (HEAD -> main) not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

A safe way to undo the commit is to revert the commit with git revert:

+
$ git revert e02efcd
+
+
+

This creates a new commit that does the opposite of the reverted commit. +The old commit remains in the history:

+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+

You can revert any commit, no matter how old it is. It doesn’t affect +other commits you have done since then - but if they touch the same +code, you may get a conflict (which we’ll learn about later).

+
+

Exercise: Revert a commit

+
+

Undoing-1: Revert a commit

+
    +
  • Create a commit (commit A).

  • +
  • Revert the commit with git revert (commit B).

  • +
  • Inspect the history with git log --oneline.

  • +
  • Now try git show on both the reverted (commit A) and the newly created commit (commit B).

  • +
+
+
+
+
+

Adding to the previous commit (modifies history)

+

Sometimes we commit but realize we forgot something. +We can amend to the last commit:

+
$ git commit --amend
+
+
+

This can also be used to modify the last commit message.

+

Note that this will change the commit hash. This command modifies the history. +This means that we avoid this command on commits that we have shared with others.

+
+

Exercise: Modify a previous commit

+
+

Undoing-2: Modify a previous commit

+
    +
  1. Make an incomplete change to the recipe or a typo in your change, git add and git commit the incomplete/unsatisfactory change.

  2. +
  3. Inspect the unsatisfactory but committed change with git show. Remember +or write down the commit hash.

  4. +
  5. Now complete/fix the change but instead of creating a new commit, add the +correction to the previous commit with git add, followed by git commit --amend. What changed?

  6. +
+ +
+
+
+
+

Rewinding branches (modifies history)

+

You can reset branch history to move your branch back to some +point in the past.

+
    +
  • git reset --hard HASH will force a branch label to any other point. All +other changes are lost (but it is possible to recover if you force reset by mistake).

  • +
  • Be careful if you do this - it can mess stuff up. Use git graph a +lot before and after.

  • +
+
+

Exercise: Git reset

+
+

Undoing-3: Destroy our experimentation in this episode

+

After we have experimented with reverts and amending, let us destroy +all of that and get our repositories to a similar state.

+
    +
  • First, we will look at our history (git log/git graph) and +find the last commit HASH before our tests.

  • +
  • Then, we will git reset --hard HASH to that.

  • +
  • Then, git graph again to see what happened.

  • +
+
$ git log --oneline
+
+d3fc63a (HEAD -> main) Revert "not sure this is a good idea"
+e02efcd not sure this is a good idea
+b4af65b improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+$ git reset --hard b4af65b
+
+HEAD is now at b4af65b improve the documentation
+
+$ git log --oneline
+
+b4af65b (HEAD -> main) improve the documentation
+e7cf023 don't forget to enjoy
+79161b6 add half an onion
+a3394e3 adding README
+3696246 adding instructions
+f146d25 adding ingredients
+
+
+
+
+
+
+
+

Recovering from committing to the wrong branch

+

It is easy to forget to create a branch or to create it and forget to switch to +it when committing changes.

+

Here we assume that we made a couple of commits but we realize they went to the +wrong branch.

+

Solution 1 using git cherry-pick:

+
    +
  1. Make sure that the correct branch exists and if not, create it. Make sure to +create it from the commit hash where you wish you had created it from: git branch BRANCHNAME HASH

  2. +
  3. Switch to the correct branch.

  4. +
  5. git cherry-pick HASH can be used to take a specific commit to the +current branch. Cherry-pick all commits that should have gone to the correct +branch, from oldest to most recent.

  6. +
  7. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  8. +
+

Solution 2 using git reset --hard (makes sense if the correct branch should +contain all commits of the accidentally modified branch):

+
    +
  1. Create the correct branch, pointing at the latest commit: git branch BRANCHNAME.

  2. +
  3. Check with git log or git graph that both branches point to the same, latest, commit.

  4. +
  5. Rewind the branch that accidentally got wrong commits with git reset --hard (see also above).

  6. +
+
+
+

Recovering from merging/pulling into the wrong branch

+

git merge, git rebase, and git pull modify the current branch, never +the other branch. But sometimes we run this command on the wrong branch.

+
    +
  1. Check with git log the commit hash that you would like to rewind the +wrongly modified branch to.

  2. +
  3. Rewind the branch that accidentally got wrong commits with git reset --hard HASH (see also above).

  4. +
+
+
+

Recovering from conflict after pulling changes

+

Pulling changes with +git pull can create a conflict since git pull always also includes a git merge (more about this +in the collaborative Git lesson).

+

The recovery is same as described in Conflict resolution. Either +resolve conflicts or abort the merge with git merge --abort.

+
+
+

Undoing-4: Test your understanding

+
    +
  1. What happens if you accidentally remove a tracked file with git rm, is it gone forever?

  2. +
  3. Is it OK to modify commits that nobody has seen yet?

  4. +
  5. What situations would justify to modify the Git history and possibly remove commits?

  6. +
+ +
+
+
+
+

Interrupted work

+
+

Objectives

+
    +
  • Learn to switch context or abort work without panicking.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+

Keypoints

+
    +
  • There is almost never reason to clone a fresh copy to complete a task that +you have in mind.

  • +
+
+
+

Frequent situation: interrupted work

+

We all wish that we could write beautiful perfect code. But the real world is +much more chaotic:

+
    +
  • You are in the middle of a “Jackson-Pollock-style” debugging spree with 27 modified files +and debugging prints everywhere.

  • +
  • Your colleague comes in and wants you to fix/commit something right now.

  • +
  • What to do?

  • +
+

Git provides lots of ways to switch tasks without ruining everything.

+
+
+

Option 1: Stashing

+

The stash is the first and easiest place to temporarily “stash” +things.

+
    +
  • git stash will put working directory and staging area changes +away. Your code will be same as last commit.

  • +
  • git stash pop will return to the state you were before. Can give it a list.

  • +
  • git stash list will list the current stashes.

  • +
  • git stash save NAME is like the first, but will give it a name. +Useful if it might last a while.

  • +
  • git stash save [-p] [filename] will stash certain files files +and/or by patches.

  • +
  • git stash drop will drop the most recent stash (or whichever stash +you give).

  • +
  • The stashes form a stack, so you can stash several batches of modifications.

  • +
+
+

Exercise: Stashing

+
+

Interrupted-1: Stash some uncommitted work

+
    +
  1. Make a change.

  2. +
  3. Check status/diff, stash the change with git stash, check status/diff again.

  4. +
  5. Make a separate, unrelated change which doesn’t touch the same +lines. Commit this change.

  6. +
  7. Pop off the stash you saved with git stash pop, and check status/diff.

  8. +
  9. Optional: Do the same but stash twice. Also check git stash list. +Can you pop the stashes in the opposite order?

  10. +
  11. Advanced: What happens if stashes conflict with other changes? Make +a change and stash it. Modify the same line or one right above or +below. Pop the stash back. Resolve the conflict. Note there is no +extra commit.

  12. +
  13. Advanced: what does git graph show when you have something +stashed?

  14. +
+ +
+
+
+
+

Option 2: Create branches

+

You can use branches almost like you have already been doing if you +need to save some work. You need to do something else for a bit? +Sounds like a good time to make a feature branch.

+

You basically know how to do this:

+
$ git switch --create temporary  # create a branch and switch to it
+$ git add PATHS                  # stage changes
+$ git commit                     # commit them
+$ git switch main                # back to main, continue your work there ...
+$ git switch temporary           # continue again on "temporary" where you left off
+
+
+

Later you can merge it to main or rebase it on top of main and resume work.

+
+
+

Storing various junk you don’t need but don’t want to get rid of

+

It happens often that you do something and don’t need it, but you don’t want to +lose it right away. You can use either of the above strategies to stash/branch +it away: using branches is probably better because branches are less easily +overlooked if you come back to the repository in few weeks. Note that if you +try to use a branch after a long time, conflicts might get really bad but at +least you have the data still.

+
+
+
+

Aliases and configuration

+
+

Objectives

+
    +
  • Learn to use aliases for most common commands.

  • +
+
+

Are you getting tired of typing so much? In Git you can define aliases (shortcuts):

+
    +
  • These are great because they can save you time typing.

  • +
  • But it’s easy to forget them, get confused, or be inconsistent with your colleagues.

  • +
+

There is plenty of other configuration for Git, that can make it nicer.

+
+

Aliases

+
    +
  • Aliases offer a way to improve the usability of Git: for +example git ci instead of git commit.

  • +
  • Aliases are based on simple string replacement in the command.

  • +
  • Aliases can either be specific to a repository or global.

    +
      +
    • Global aliases help you do the things you are used to across Git projects.

    • +
    • Per-project aliases can also be created.

    • +
    +
  • +
  • Global aliases are stored in ~/.gitconfig.

  • +
+
+
+

Example alias: git graph

+

A very useful shortcut which we use a lot in our workshops:

+
$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ cd your_git_repository
+$ git graph
+
+
+
+
+

Using external commands

+

It is possible to call external commands using the exclamation mark character “!”. +In this example here we create a local alias which is +stored in .git/config and not synchronized with remotes:

+
$ cd your_git_repository
+$ git config alias.hi '!echo hello'
+$ git hi
+
+
+
+

Food for thought: When to alias?

+
    +
  • How many times should you wait before aliasing a command?

  • +
  • Do you believe a list of generic two-letter acronyms for common commands will +save your time?

  • +
+
+
+
+

List of aliases the instructors use

+

You are welcome to reuse, suggest, improve. +You can see your current aliases in ~/.gitconfig.

+
$ git config --global alias.ap "add --patch"
+$ git config --global alias.br branch
+$ git config --global alias.ci "commit -v"
+$ git config --global alias.cip "commit --patch -v"
+$ git config --global alias.cl "clone --recursive"
+$ git config --global alias.di diff
+$ git config --global alias.dic "diff --staged --color-words"
+$ git config --global alias.diw "diff --color-words"
+$ git config --global alias.dis "!git --no-pager diff --stat"
+$ git config --global alias.fe fetch
+$ git config --global alias.graph "log --all --graph --decorate --oneline"
+$ git config --global alias.rem remote
+$ git config --global alias.st status
+$ git config --global alias.su "submodule update --init --recursive"
+
+
+

Here is what they do:

+
    +
  • ap: add, selecting parts individually, interactively.

  • +
  • br: branch (obvious)

  • +
  • ci: commit (check in), with -v option for clarity

  • +
  • cip: commit, selecting parts individually, interactively.

  • +
  • cl: clone, init submodules (submodules are an advanced topic)

  • +
  • di: diff (obvious)

  • +
  • dic: diff of staging area vs last commit (what is about to be committed)

  • +
  • diw: a word diff, color. Useful for small changes.

  • +
  • dis: a “diffstat”: what files are changed, not contents

  • +
  • fe: fetch (obvious)

  • +
  • graph: show whole git graph (so useful, some of us call it l)

  • +
  • rem: remote (obvious)

  • +
  • st: status (obvious)

  • +
  • su: submodule update (advanced)

  • +
+

A useful setting for the p aliases:

+
$ git config --global interactive.singlekey true
+
+
+
+
+

Advanced aliases

+

These are advanced aliases and configuration options. We won’t explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages!

+
$ git config --global alias.cif "commit -v -p --fixup"
+$ git config --global alias.rb "rebase --autosquash"
+$ git config --global alias.rbi "rebase --interactive --autosquash"
+$ git config --global alias.rbis "rebase --interactive --autosquash --autostash"
+$ git config --global alias.rbs "rebase --autosquash --autostash"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard"
+$ git config --global alias.new "log HEAD..HEAD@{upstream}"
+$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}"
+$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}"
+$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}"
+$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD"
+$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all"
+$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD"
+$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat"
+
+
+
+
+

Advanced Git configuration

+

Besides aliases, you can do plenty of other configuration of git. +Here are some of the most common ones:

+
$ git config --global interactive.singlekey true
+$ git config --global core.pager "less -RS"
+$ git config --global core.excludesfile ~/.gitignore
+$ git config --global merge.conflictstyle diff3
+$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]"
+$ git config --global diff.mnemonicPrefix true
+
+
+

Do you get tired of typing and copying and pasting your remote names +all the time, like git@github.com:myusername? You can create remote +aliases like this:

+
$ git config --global url.git@github.com:.insteadOf gh:
+$ git config --global url.git@github.com:/username/.insteadOf ghu:
+
+
+

Then, when you add a remote ghu:recipe, it will automatically be +translated to git@github.com:/username/recipe using a simple prefix +matching.

+
+

Keypoints

+
    +
  • If you are frustrated about remembering a command, you should create an alias.

  • +
+
+
+
+
+

Git under the hood

+
+

Objectives

+
    +
  • Verify that branches are pointers to commits and extremely lightweight.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+Git under the hood +
+
+

Down the rabbit hole

+

When working with Git, you will never need to go inside .git, but in this +exercise we will, in order to learn about how branches are implemented in Git.

+

For this exercise create a new repository and commit a couple of changes.

+

Now that we’ve made a couple of commits let us look at what is happening under +the hood.

+
$ cd .git
+$ ls -l
+
+drwxr-xr-x   - user 25 Aug 15:51 branches
+.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG
+.rw-r--r--  92 user 25 Aug 15:51 config
+.rw-r--r--  73 user 25 Aug 15:51 description
+.rw-r--r--  21 user 25 Aug 15:51 HEAD
+drwxr-xr-x   - user 25 Aug 15:51 hooks
+.rw-r--r-- 137 user 25 Aug 15:52 index
+drwxr-xr-x   - user 25 Aug 15:51 info
+drwxr-xr-x   - user 25 Aug 15:52 logs
+drwxr-xr-x   - user 25 Aug 15:52 objects
+drwxr-xr-x   - user 25 Aug 15:51 refs
+
+
+

Git stores everything under the .git folder in your repository. In fact, the +.git directory is the Git repository.

+

Previously when you wrote the commit messages using your text editor, they +were in fact saved to COMMIT_EDITMSG.

+

Each commit in Git is stored as a “blob”. This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file.

+

Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string).

+
+A commit inside Git +
+

States of a Git file. Image from the Pro Git book. License CC BY 3.0.

+
+
+

Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a directed acyclic +graph (do not worry +if the term is not familiar).

+
+A commit and its parents +
+

A commit and its parents. Image from the Pro Git book. License CC BY 3.0.

+
+
+

All branches and tags in Git are pointers to commits.

+
+
+

Git is basically a content-addressed storage system

+ +

Let us poke a bit into raw objects! Start with:

+
$ git cat-file -p HEAD
+
+
+

Then explore the tree object, then the file object, etc. recursively using the hashes you see.

+
+
+

Demonstration: experimenting with branches

+

Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an “Aha!” moment and provide us a +good understanding of the underlying model.

+

We are starting from the main branch and create an idea branch:

+
$ git status
+
+On branch main
+nothing to commit, working tree clean
+
+
+
$ git switch --create idea
+
+Switched to a new branch 'idea'
+
+
+
$ git branch
+
+* idea
+  main
+
+
+

Now let us go in:

+
$ cd .git
+$ cd refs/heads
+$ ls -l
+
+.rw-r--r-- 41 user 25 Aug 15:54 idea
+.rw-r--r-- 41 user 25 Aug 15:52 main
+
+
+

Let us check what the idea file looks like +(do not worry if the hash is different):

+
$ cat idea
+
+045e3db14740c60684d745e5fb891ae71e335611
+
+
+

Now let us replicate this file:

+
$ cp idea idea-2
+$ cp idea idea-3
+$ cp idea idea-4
+$ cp idea idea-5
+
+
+

Let us go up two levels and inspect the file HEAD:

+
$ cd ../..
+$ cat HEAD
+
+ref: refs/heads/idea
+
+
+

Let us open this file and change it to:

+
ref: refs/heads/idea-3
+
+
+

Now we are ready for the aha moment! +First let us go back to the working area:

+
$ cd ..
+
+
+

Now - on which branch are we?

+
$ git branch
+
+  idea
+  idea-2
+* idea-3
+  idea-4
+  idea-5
+  main
+
+
+
+

Discussion

+

Discuss the findings with other course participants.

+
+
+
+
+
+
+

Quick reference

+
+

Other cheatsheets

+ +
+
+

Glossary

+
+
alias

With aliases you can define your own shortcuts for Git commands.

+
+
version control system

A system that records changes to a file or set of files over time so that +you can recall specific versions later.

+
+
git

Implementation of a version control system. Currently the most popular one.

+
+
commit

As a verb, the process of recording more changes. +As a noun, the name of the record of changes. +A commit is identified by something such as 554c187.

+
+
working directory
workspace

the actual files you see and edit

+
+
staging area

Place files go after git add and before git commit

+
+
hash

Unique reference of any commit or state. Comes from hash +functions such as MD5 +or SHA1.

+
+
branch

One line of work. Different branches can exist at the same time +and split/merge. Committing on a branch updates that branch.

+
+
tag

Like a branch in that it points to a commit for reference. +It is designed to be permanent an not updated.

+
+
HEAD

Pointer to the most recent commit on the current branch.

+
+
remote

Roughly, another server that holds .git.

+
+
origin

Default name for a remote repository.

+
+
repository

One collection of files managed by Git. It contains entire history +of all files managed by git. GitHub has one repository as one +GitHub repository. VS Code has one repository as one directory you +can open. The command line has one repository as one directory.

+
+
clone

As a verb, the process of making a copy of a repository locally. +It brings in all history and all files. (As a noun, the copy that +was made when cloning).

+
+
GitHub repository

The files from the Git repository, but also other things from +GitHub such as access permissions, issues, and pull requests.

+
+
upstream

The original repository from which the code comes. If you +fork the repository, it is your upstream and it is easy to +send changes back to there.

+
+
fork

As a noun: a one person’s copy of a repository. +As a verb: making that copy. +As a verb on GitHub: Making a copy of a repository linked to the +original. It is easy to send changes to the original

+
+
issue

Within a web repository like GitHub, discussion of a topic, for +example a problem or improvement suggestion. These are a property +of the web platform and not of the Git program itself.

+
+
pull request

A GitHub concept: change proposal. A proposal to merge one branch +into another. Usually used to contribute code back to +upstream.

+
+
push

Moving changes from your local copy to another copy

+
+
pull

Getting changes from another copy to your own copy. git pull +does this fetch, and also tries to automatically merge.

+
+
master

Default name for main branch on Git. Depending on the configuration and service, +the default branch is sometimes main. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

+
+
main

Default name for main branch on GitLab and GitHub. +In this lesson we configure Git so that the default branch is +called main to be more consistent with GitHub and GitLab.

+
+
merge
merging

Bringing changes from one branch into another, either as a noun or +verb.

+
+
VS Code

A text editor and development environment by Microsoft. It’s quite +popular, partly because it is powerful and easy to use. VS +Codium is the same but without Microsoft +tracking.

+
+
+
+
+

Commands we use

+

Setup:

+
    +
  • git config: edit configuration options

  • +
  • git init -b main: create new repository with main as the default branch

  • +
+

See our status:

+
    +
  • git status: see status of files - use often!

  • +
  • git log: see history of commits and their messages, newest first

  • +
  • git graph: see a detailed graph of commits. Create this command +with git config --global alias.graph "log --all --graph --decorate --oneline"

  • +
  • git diff: show difference between working directory and last commit

  • +
  • git diff --staged: show difference between staging area and last commit

  • +
  • git show COMMIT: inspect individual commits

  • +
+

General work:

+
    +
  • git add FILE:

    +
      +
    • Add a new file

    • +
    • Add a file to staging

    • +
    +
  • +
  • git commit: record a version, add it to current branch

  • +
  • git commit --amend: amend our last commit

  • +
  • git branch: show which branch we’re on

  • +
  • git branch NAME: create a new branch called “name”

  • +
  • git restore FILE: restore last committed/staged version of FILE, losing unstaged changes

  • +
  • git switch --create BRANCH-NAME: create a new branch and switch to it

  • +
  • git revert HASH: create a new commit which reverts commit HASH

  • +
  • git reset --soft HASH: remove all commits after HASH, but keep their modifications as staged changes

  • +
  • git reset --hard HASH: remove all commits after HASH, permanently throwing away their changes

  • +
  • git merge BRANCH-NAME: merge branch BRANCH-NAME into current branch

  • +
  • git grep PATTERN: search for patterns in tracked files

  • +
  • git annotate FILE: find out when a specific line got introduced and by whom

  • +
  • git bisect: find a commit which broke some functionality

  • +
+
+
+
+

Customizing Git

+
+

Shell prompt

+
+

Instructor note

+

Here the instructor can demonstrate how a context-aware and Git-aware shell +prompt can look like.

+
+

You can make your shell display contextual information about +your Git state even at all times.

+

Here are few example projects that make this possible and easy:

+ +
+
+

More useful “diff” output

+

Delta is a syntax-highlighting pager for +git, diff, and grep output. You can customize how you want to highlight the +“diff” output. It allows side-by-side view, word-level diff highlighting, +improved merge conflict display, and much more.

+
+
+
+

Other resources

+ +
+
+

List of exercises

+

This is a list of all exercises and solutions in this lesson, mainly +as a reference for helpers and instructors. This list is +automatically generated from all of the other pages in the lesson. +Any single teaching event will probably cover only a subset of these, +depending on their interests.

+
+
+

Instructor guide

+
+

Exercise preparation: one day before the workshop

+ +
+
+

Privacy

+

When presenting the material in a streamed and recorded workshop, make sure to +only show the https://github.com/coderefinery/recipe-book-recorded +repository.

+
+
+

Schedule Day 1

+

Times here are in CE(S)T.

+ +
+
+

Schedule Day 2

+

Times here are in CE(S)T.

+ +
+
+

Why we teach this lesson

+

Everyone should be using a version control system for their work, even if they’re working alone. +There are many version control systems out there, but Git is an industry standard and even if one uses another +system chances are high one still encounters Git repositories.

+

Specific motivations:

+
    +
  • Code easily becomes a disaster without version control

  • +
  • Mistakes happen - Git offers roll-back functionality and easy backup mechanism

  • +
  • One often needs to work on multiple things in parallel - branches solve that problem

  • +
  • Git enables people to collaborate on code or text without stepping on each other’s toes

  • +
  • Reproducibility: You can specify exact versions in publications enabling others to reproduce your work, +and if bugs are found one can find out exactly when it was introduced

  • +
+

Many learners in a CodeRefinery workshop have developed code for a few years. A majority have +already encountered Git and have used it to some extent, but in most cases they do not yet feel +comfortable with it. They lack a good mental model of how Git operates and are afraid of making mistakes. +Other learners have never used Git before. +This lesson teaches how things are done in Git, which is useful for the newcomers, +but also how Git operates (e.g. what commits and branches really are) and what are some good +practices.

+
+
+

Intended learning outcomes

+

By the end of this lesson, learners should:

+
    +
  • realize that version control is very important and Git is a valuable tool to learn and use

  • +
  • understand that Git is configurable and know how to set basic configurations

  • +
  • be able to set up Git repositories and make commits

  • +
  • know how to write good commit messages

  • +
  • have an idea of how the staging area can be used to craft good commits

  • +
  • know how to create branches and switch between branches

  • +
  • have a mental model of how branches work and get used to thinking of branches in a graphical (tree-structure) way

  • +
  • know how to merge branches and understand what that means in terms of combining different modifications

  • +
  • realize that conflicts are generally a good thing since they prevent incorrect merges

  • +
  • be able to set up a repository on GitHub and connect it with local repository

  • +
  • push changes to a remote repository

  • +
  • know a few ways to search through a repository and its history

  • +
+
+
+

Inspecting history

+

Key lesson is how to find when something is broken or what commit has broken +the code.

+

It can be useful to emphasize that it can be really valuable to be able to +search through the history of a project efficiently to find when bugs were +introduced or when something changed and why. Also show that git annotate +and git show are available on GitHub and GitLab.

+

When discussing git annotate and git bisect the “when” is more important +than “who”. It is not to blame anybody but rather to find out whether published +results are affected.

+

Discuss how one would find out this information without version control.

+

Questions to involve participants:

+
    +
  • Have you ever found a bug in your code and wondered whether it has affected published results?

  • +
  • Have you ever wondered when, and by whom, a particular line of code was introduced?

  • +
  • Have you ever found out that a code behaves differently than it used to but you are not sure when +precisely this changed?

  • +
+

Confusion during git bisect exercise:

+

Learners may get stuck in the git bisect exercise if they incorrectly assign a commit +as bad or good. +To leave the bisect mode and return to the commit before git bisect start was issued, +one can do

+
$ git bisect reset
+
+
+

and start over if needed.

+
+

Live better than reading the website material

+

It is better to demonstrate the commands live and type-along. Ideally connecting +to examples discussed earlier.

+
+
+

Log your history in a separate window

+

The screencasting (shell window cheatsheet) hints have been moved to +the presenting +manual.

+
+
+

Create a cheatsheet on the board

+

For in-person workshops, create a “cheatsheet” on the board as you go. After +each command is introduced, write it on the board. After each module, make sure +you haven’t forgotten anything. Re-create and expand in future git lessons. +One strategy is:

+
    +
  • a common section for basic commands: init, config, clone, help, stash

  • +
  • info commands, can be run anytime: status, log, diff, graph

  • +
  • A section for all the commands that move code from different states: +add, commit, etc. See the visual cheat sheet below.

  • +
+

You can get inspired by http://www.ndpsoftware.com/git-cheatsheet.html +to make your cheat sheet, but if you show this make it clear there are +far, far more commands on there than you need to know right now., and +it’s probably too confusing to use after this course. But, the idea +of commands moving from the “working dir”, “staging area”, “commits”, +etc is good.

+
+Example cheat sheet +
+

Example cheat sheet.

+
+
+

We also recommend to draw simple diagrams up on the board (e.g.: working +directory - staging area - repository with commands to move between) and keep +them there for students to refer to.

+
+
+

Draw a graph on the board

+

Draw the standard commit graphs on the board early on - you know, the +thing in all the diagrams. Keep it updated all the time. After the +first few samples, you can basically keep using the same graph the +whole lesson. When you are introducing new commands, explain and +update the graph first, then run git graph, then do the command, +then look at git graph again.

+
+
+

Repeat the following points

+
    +
  • Always check git status, git diff, and git graph (our alias) before and +after every command until you get used to things. These give you a clear view +into what is going on, the key to knowing what you are doing. Even +after you are used to things… anytime you do something you do +infrequently, it’s good to check.

  • +
  • git graph is a direct representation of what we are drawing on the +board and should constantly be compared to it.

  • +
  • Once you git add something, it’s almost impossible to lose it. +This is used all the time, for example once you commit or even add +it is hard to lose. Commit before you merge or rebase. And so on.

  • +
+
+
+

Start from identical environment

+

You probably have a highly optimized bash and git environment - one +that is different from students. Move .gitconfig and .bashrc out +of the way before you start so that your environment is identical to +what students have.

+
+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/singlehtml/objects.inv b/branch/main/singlehtml/objects.inv new file mode 100644 index 00000000..66e23ea9 Binary files /dev/null and b/branch/main/singlehtml/objects.inv differ diff --git a/branch/main/staging-area/index.html b/branch/main/staging-area/index.html new file mode 100644 index 00000000..0eb66126 --- /dev/null +++ b/branch/main/staging-area/index.html @@ -0,0 +1,515 @@ + + + + + + + Using the Git staging area — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Using the Git staging area

+
+

Objectives

+
    +
  • Learn how to tell a story with your commit history.

  • +
  • Demystify the Git staging area.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 10 min exercise

  • +
+
+
+

Commit history is telling a story

+

Your current code is very important, but the history can be just +as important - it tells a story about how your code came to be.

+
    +
  • Each individual line of code rarely stands alone.

  • +
  • You often want to see all the related changes together.

  • +
  • But you also hardly ever do one thing at once.

  • +
+

Along with your code, Git creates a history for you, and if your +history is clear then you are a long way to organized code.

+
+

Discussion

+

Here are five types of history. What are the advantages and +disadvantages of each, when you look at it later?

+

Example 1:

+
b135ec8 add features A, B, and C
+
+
+

Example 2 (newest commit is on top):

+
6f0d49f implement feature C
+fee1807 implement feature B
+6fe2f23 implement feature A
+
+
+

Example 3:

+
ab990f4 saving three months of miscellaneous work I forgot to commit
+
+
+

Example 4 (newest commit is on top):

+
bf39f9d more work on feature B
+45831a5 removing debug prints for feature A and add new file
+bddb280 more work on feature B and make feature A compile again
+72d78e7 feature A did not work and started work on feature B
+b135ec8 now feature A should work
+72e0211 another fix to make it compile
+61dd3a3 forgot file and bugfix
+49dc419 wip (work in progress)
+
+
+

Example 5 (newest commit is on top):

+
1949dc4 Work of 2020-04-07
+a361dd3 Work of 2020-04-06
+1172e02 Work of 2020-04-03
+e772d78 Work of 2020-04-02
+
+
+

Discuss these examples. Can you anticipate problems?

+
+

We want to have nice commits. But we also want to “save often” +(checkpointing) - how can we have both?

+
    +
  • We will now learn to create nice commits using git commit --patch and/or the staging area.

  • +
  • Staging addresses the issue of having unrelated changes in the same +commit or having one logical change spread over several commits.

  • +
  • The staging area isn’t the only way to organize your history nicely, some alternatives are discussed at the end of the lesson.

  • +
+
+
+

Interactive commits

+
    +
  • The simplest ways to solve this is to do interactive commits: +the git commit --patch option (or git commit -p for short).

  • +
  • It will present you with every change you have made individually, +and you can decide which ones to commit right now.

  • +
  • Reference and key commands

    +
      +
    • git commit --patch to start the interactive commit

    • +
    • y to use the change

    • +
    • n to skip the change

    • +
    • s (split) if there are several changes grouped together, but +separated by a blank line, split them into separate choices.

    • +
    • q aborts everything.

    • +
    • ? for more options.

    • +
    +
  • +
  • The -p option is also available on commit, restore, checkout, reset, and add.

  • +
+
+
+

Exercise: Interactive commits

+
+

Staging-1: Perform an interactive commit

+

One option to help us create nice logical commits is to stage interactively +with git commit --patch:

+
    +
  1. Make two changes in instructions.txt, at the top and bottom +of the file. +Make sure that they are separated by at least several unmodified lines.

  2. +
  3. Run git commit --patch. Using the keystrokes above, commit one of +the changes.

  4. +
  5. Do it again for the other change.

  6. +
  7. When you’re done, inspect the situation with git log, git status, git diff and git diff --staged.

  8. +
  9. When would this be useful?

  10. +
+ +
+
+
+

The staging area

+
    +
  • The interactive commits above are great, but what if there are so +many changes that you can’t sort them out in one shot?

  • +
  • What if you make progress and want to record it somehow, but it’s +not ready to be committed?

  • +
  • The staging area is a place to record things before committing.

  • +
+
+

Instructor note

+

We give two examples and the instructor can pick one or both:

+
    +
  • Analogy using moving boxes

  • +
  • Analogy using shopping receipts

  • +
+
+
+

Discussion

+

Analogy using moving boxes

+
    +
  • You’re moving and you have a box to pack your things in.

  • +
  • You can put stuff into the box, but you can also take stuff out of the box.

  • +
  • You wouldn’t want to mix items from the bathroom, kitchen, and living room +into the same box.

  • +
  • The box corresponds to the staging area of Git, where you can craft your commits.

  • +
  • Committing is like sealing the box and sticking a label on it.

  • +
  • You wouldn’t want to label your box with “stuff”, but rather give a more +descriptive label.

  • +
  • See also https://dev.to/sublimegeek/git-staging-area-explained-like-im-five-1anh

  • +
+

Analogy using shopping receipts

+
    +
  • You need to go shopping and buy some stuff for work and for home. +You need two separate receipts.

  • +
  • Bad idea: go through the store get home stuff, pay, start at the +beginning and go through the store again. This is inefficient and +annoying.

  • +
  • What you actually do:

    +
      +
    • Go through the store and put everything you need in your shopping +basket.

    • +
    • Get to the check-out. Put your home stuff on the conveyor belt +(git add). Check both the belt (git diff --staged) and your +basket (git diff) to make sure you got all your home stuff.

    • +
    • Pay (git commit)

    • +
    • Repeat for work stuff.

    • +
    +
  • +
+

In order to keep organized, you have to use multiple locations to +stage things in sequence.

+
+
+
+

Staging area commands

+

The staging area is a middle ground between what you have done to your files +(the working directory) and what you have last committed (the HEAD commit). +Just like the name implies, it lets you prepare (stage) what the next commit will be and most importantly give you tools to easily know what is going on. +This adds some complexity but also adds more flexibility to selectively +prepare commits since you can modify and stage several times before committing.

+

git add stages/prepares for the next commit:

+
                git add
+ [project*]  <------------  project*
+                               ^
+                               | modify with editor
+                               |
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git commit creates a new commit:

+
  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+  HEAD~2          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

git reset --soft HEAD~1 (move HEAD back by one but keep changes and stage +them) would do the opposite of git commit. (in this case, HEAD +is literally this - not a replacement)

+

Going back to the last staged version:

+
              git restore
+ [project*]  ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Unstaging changes with git restore --staged:

+
          git restore --staged
+             ------------>  project*
+
+
+
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Discarding unstaged changes:

+
                            project*
+                               |
+                               | git restore
+                               v
+  HEAD            .         project
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+

Comparing:

+
                git diff
+ [project*]  <----------->  project*
+    ^                          ^
+    | git diff --staged        | git diff HEAD
+    v                          v
+  HEAD            .
+    |             .
+    |             .
+    |             .
+  HEAD~1          .
+    |             .
+    |             .
+    |             .
+                  .
+  .git            .     working directory
+(history)         .      (files we see)
+
+
+
+Staging basics +
+

The different states of the repository and the commands to move from one to +another.

+
+
+
+
+

Exercise: Using the staging area

+
+

Staging-2: Use the staging area to make a commit in two steps

+
    +
  1. In your recipe example, make two different changes to +ingredients.txt and instructions.txt which do not go together.

  2. +
  3. Use git add to stage one of the changes.

  4. +
  5. Use git status to see what’s going on, and use git diff and git diff --staged to see the changes.

  6. +
  7. Feel some regret and unstage the staged change.

  8. +
+
+
+

Discussion

+
    +
  • When is it better to “save” a change as commit, when is it better to “save” +it with git add?

  • +
  • Is it a problem to commit many small changes?

  • +
+
+
+

Keypoints

+
    +
  • The staging area helps us to create well-defined commits.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/under-the-hood/index.html b/branch/main/under-the-hood/index.html new file mode 100644 index 00000000..2c7f812b --- /dev/null +++ b/branch/main/under-the-hood/index.html @@ -0,0 +1,343 @@ + + + + + + + Git under the hood — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Git under the hood

+
+

Objectives

+
    +
  • Verify that branches are pointers to commits and extremely lightweight.

  • +
+
+
+

Instructor note

+
    +
  • 10 min teaching/type-along

  • +
  • 15 min exercise

  • +
+
+
+Git under the hood +
+
+

Down the rabbit hole

+

When working with Git, you will never need to go inside .git, but in this +exercise we will, in order to learn about how branches are implemented in Git.

+

For this exercise create a new repository and commit a couple of changes.

+

Now that we’ve made a couple of commits let us look at what is happening under +the hood.

+
$ cd .git
+$ ls -l
+
+drwxr-xr-x   - user 25 Aug 15:51 branches
+.rw-r--r-- 499 user 25 Aug 15:52 COMMIT_EDITMSG
+.rw-r--r--  92 user 25 Aug 15:51 config
+.rw-r--r--  73 user 25 Aug 15:51 description
+.rw-r--r--  21 user 25 Aug 15:51 HEAD
+drwxr-xr-x   - user 25 Aug 15:51 hooks
+.rw-r--r-- 137 user 25 Aug 15:52 index
+drwxr-xr-x   - user 25 Aug 15:51 info
+drwxr-xr-x   - user 25 Aug 15:52 logs
+drwxr-xr-x   - user 25 Aug 15:52 objects
+drwxr-xr-x   - user 25 Aug 15:51 refs
+
+
+

Git stores everything under the .git folder in your repository. In fact, the +.git directory is the Git repository.

+

Previously when you wrote the commit messages using your text editor, they +were in fact saved to COMMIT_EDITMSG.

+

Each commit in Git is stored as a “blob”. This blob contains information about +the author and the commit message. The blob references another blob that lists +the files present in the directory at the time and references blobs that record +the state of each file.

+

Commits are referenced by a SHA-1 hash (a 40-character hexadecimal string).

+
+A commit inside Git +
+

States of a Git file. Image from the Pro Git book. License CC BY 3.0.

+
+
+

Once you have several commits, each commit blob also links to the hash of the +previous commit. The commits form a directed acyclic +graph (do not worry +if the term is not familiar).

+
+A commit and its parents +
+

A commit and its parents. Image from the Pro Git book. License CC BY 3.0.

+
+
+

All branches and tags in Git are pointers to commits.

+
+
+

Git is basically a content-addressed storage system

+ +

Let us poke a bit into raw objects! Start with:

+
$ git cat-file -p HEAD
+
+
+

Then explore the tree object, then the file object, etc. recursively using the hashes you see.

+
+
+

Demonstration: experimenting with branches

+

Let us lift the hood and create few branches manually. The +goal of this exercise is to hopefully create an “Aha!” moment and provide us a +good understanding of the underlying model.

+

We are starting from the main branch and create an idea branch:

+
$ git status
+
+On branch main
+nothing to commit, working tree clean
+
+
+
$ git switch --create idea
+
+Switched to a new branch 'idea'
+
+
+
$ git branch
+
+* idea
+  main
+
+
+

Now let us go in:

+
$ cd .git
+$ cd refs/heads
+$ ls -l
+
+.rw-r--r-- 41 user 25 Aug 15:54 idea
+.rw-r--r-- 41 user 25 Aug 15:52 main
+
+
+

Let us check what the idea file looks like +(do not worry if the hash is different):

+
$ cat idea
+
+045e3db14740c60684d745e5fb891ae71e335611
+
+
+

Now let us replicate this file:

+
$ cp idea idea-2
+$ cp idea idea-3
+$ cp idea idea-4
+$ cp idea idea-5
+
+
+

Let us go up two levels and inspect the file HEAD:

+
$ cd ../..
+$ cat HEAD
+
+ref: refs/heads/idea
+
+
+

Let us open this file and change it to:

+
ref: refs/heads/idea-3
+
+
+

Now we are ready for the aha moment! +First let us go back to the working area:

+
$ cd ..
+
+
+

Now - on which branch are we?

+
$ git branch
+
+  idea
+  idea-2
+* idea-3
+  idea-4
+  idea-5
+  main
+
+
+
+

Discussion

+

Discuss the findings with other course participants.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/main/what-to-avoid/index.html b/branch/main/what-to-avoid/index.html new file mode 100644 index 00000000..785f55ea --- /dev/null +++ b/branch/main/what-to-avoid/index.html @@ -0,0 +1,231 @@ + + + + + + + What to avoid — Introduction to version control with Git documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

What to avoid

+

The idea for this page came up during a discussion: quick reference page of +things that you should not do with Git. Basically, a list of some common Git +gotchas.

+

Postponing commits because the changes are “unfinished”/”ugly”: It is +better to have many OK-ish commits than too few perfect commits. Too few +perfect commits are probably too large and make undoing more difficult. It is +also easier to combine too small commits than it is to split too large commits. +The longer you wait because of this, the harder it will be to +commit it at all.

+

Not updating your branch before starting new work: Few things are worse +than doing work and then noticing a lot of conflicts because +unrelated but conflicting work was done in the meantime or even before you started. Or noticing that someone +else has already done it. This problem is largest when you come back +to an active project weeks or months later. +So update your branch before adding new commits.

+

Commit unrelated changes together: Makes it difficult to undo changes since +it can undo also the unrelated change. +But, this is the counterpoint to the first point: In the end, it is probably better to make big +ugly commits than to never commit. This is especially true in in the chaotic early +phases of small projects.

+

Too ambitious branch which risks to never get completed: The branch will +never merge back and be so big and so ambitious with too many/big features that +the risk is high that once it is really ready, there are conflicts everywhere.

+

Committing generated files: Compiled and generated files are not +committed to version control. There are many reasons for this:

+
    +
  • These files can make it more difficult to run on different platforms.

  • +
  • These files are automatically generated and thus do not contribute in any meaningful way.

  • +
  • When tracking generated files you could see differences in the code although you haven’t touched the code.

  • +
+

For this we use .gitignore files where +you can list which files and paths should be ignored by Git. You can also use +wild-cards to ignore files with a certain extension or files in a certain +directory.

+

Over-engineering the branch layout and safeguards in small projects: This +may prevent people from contributing (maybe even including yourself?). Add more +restrictions and safeguards only as the project and the group of collaborators +grows.

+

Commit messages that explain what has been changed but do not explain why it has been +changed: This is as useful as code comments which describe the “obvious” such +as “this is a loop” instead of explaining why something is done this way. +But don’t let perfect commit messages stop you from the most important point, committing often (first point).

+

Commit huge files: Huge files get sometimes accidentally added and +committed which can significantly increase the repository size. Note that a +subsequent git rm does not remove the addition from the repository history. +Code review can help detecting accidental large file additions. +You can also add an automated test which checks for file sizes during a pull request or merge request.

+
+

Discussion

+

Question to all seasoned Git users: What are we missing on this page? Please +contribute improvements.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/branch/sphinx-book-theme-old-copybutton/.buildinfo b/branch/sphinx-book-theme-old-copybutton/.buildinfo new file mode 100644 index 00000000..f391f6fe --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 566e1f45f64b701c94f54f123f87b9e6 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/branch/sphinx-book-theme-old-copybutton/.nojekyll b/branch/sphinx-book-theme-old-copybutton/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/branch/sphinx-book-theme-old-copybutton/_images/cheat-sheet.jpg b/branch/sphinx-book-theme-old-copybutton/_images/cheat-sheet.jpg new file mode 100644 index 00000000..69c947cb Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/cheat-sheet.jpg differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/commit-and-tree.png b/branch/sphinx-book-theme-old-copybutton/_images/commit-and-tree.png new file mode 100644 index 00000000..57cdebfa Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/commit-and-tree.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/commits-and-parents.png b/branch/sphinx-book-theme-old-copybutton/_images/commits-and-parents.png new file mode 100644 index 00000000..62336de2 Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/commits-and-parents.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/created.png b/branch/sphinx-book-theme-old-copybutton/_images/created.png new file mode 100644 index 00000000..1d657d77 Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/created.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/creating.png b/branch/sphinx-book-theme-old-copybutton/_images/creating.png new file mode 100644 index 00000000..ff61a75a Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/creating.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-branch-1.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-1.svg new file mode 100644 index 00000000..aaaa8a04 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-1.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + m3 + + + m2 + + + m1 + + + + + master + + + + + HEAD + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-branch-2.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-2.svg new file mode 100644 index 00000000..af25bd2d --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-2.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + m3 + + + l1 + + + e1 + + + e2 + + + m2 + + + m1 + + + + + master + + + + + experiment + + + + + less-salt + + + + + HEAD + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-branch-3.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-3.svg new file mode 100644 index 00000000..ce525698 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-branch-3.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + e2 + + + m3 + + + m4 + + + l1 + + + e1 + + + + + experiment + + + + + less-salt + + + + + master + + + + + HEAD + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-collaborative.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-collaborative.svg new file mode 100644 index 00000000..1e0755ed --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-collaborative.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + x1 + + + m1 + + + m2 + + + c2 + + + m3 + + + b1 + + + b2 + + + x3 + + + b3 + + + c1 + + + x2 + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-deleted-branches.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-deleted-branches.svg new file mode 100644 index 00000000..094c3a3d --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-deleted-branches.svg @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + l1 + + + m6 + + + e2 + + + m2 + + + m3 + + + e1 + + + m1 + + + + + master + + + + + HEAD + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-merge-1.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-merge-1.svg new file mode 100644 index 00000000..f0ee336c --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-merge-1.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m1 + + + m2 + + + m4 + + + m5 + + + m3 + + + l1 + + + e2 + + + e1 + + + + + less-salt + + + + + master + + + + + HEAD + + + + + experiment + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-merge-2.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-merge-2.svg new file mode 100644 index 00000000..45af4301 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-merge-2.svg @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m4 + + + m5 + + + l1 + + + m6 + + + e2 + + + m2 + + + m3 + + + e1 + + + m1 + + + + + experiment + + + + + less-salt + + + + + master + + + + + HEAD + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git-pre-ff.svg b/branch/sphinx-book-theme-old-copybutton/_images/git-pre-ff.svg new file mode 100644 index 00000000..13010951 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git-pre-ff.svg @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + e2 + + + m5 + + + n2 + + + n3 + + + m3 + + + l1 + + + e1 + + + n1 + + + m4 + + + m2 + + + m6 + + + m1 + + + + + update-readme + + + + + HEAD + + + + + master + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/git_stage_commit.svg b/branch/sphinx-book-theme-old-copybutton/_images/git_stage_commit.svg new file mode 100644 index 00000000..2cf638b9 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/git_stage_commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/meld.png b/branch/sphinx-book-theme-old-copybutton/_images/meld.png new file mode 100644 index 00000000..fee5e33a Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/meld.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/mergetool.png b/branch/sphinx-book-theme-old-copybutton/_images/mergetool.png new file mode 100644 index 00000000..091aa720 Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/mergetool.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/new-top-left.png b/branch/sphinx-book-theme-old-copybutton/_images/new-top-left.png new file mode 100644 index 00000000..80c5f16b Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/new-top-left.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/new-top-right.png b/branch/sphinx-book-theme-old-copybutton/_images/new-top-right.png new file mode 100644 index 00000000..6dabf482 Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/new-top-right.png differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/octopus.jpeg b/branch/sphinx-book-theme-old-copybutton/_images/octopus.jpeg new file mode 100644 index 00000000..b26dc37e Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/octopus.jpeg differ diff --git a/branch/sphinx-book-theme-old-copybutton/_images/staging-basics.svg b/branch/sphinx-book-theme-old-copybutton/_images/staging-basics.svg new file mode 100644 index 00000000..6c7a2c3c --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_images/staging-basics.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + commit + + WORKING DIR + + + + COMMITTED + + + + STAGED + + + + + + checkout + add + commit + checkout + reset + + + + diff HEAD + diff + diff --staged + + diff --git a/branch/sphinx-book-theme-old-copybutton/_images/stranger.jpg b/branch/sphinx-book-theme-old-copybutton/_images/stranger.jpg new file mode 100644 index 00000000..bd3985d2 Binary files /dev/null and b/branch/sphinx-book-theme-old-copybutton/_images/stranger.jpg differ diff --git a/branch/sphinx-book-theme-old-copybutton/_sources/aliases.md.txt b/branch/sphinx-book-theme-old-copybutton/_sources/aliases.md.txt new file mode 100644 index 00000000..9d88c364 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_sources/aliases.md.txt @@ -0,0 +1,158 @@ +# Aliases and configuration + +```{objectives} +- Learn to use aliases for most common commands. +``` + +Are you getting tired of typing so much? In Git you can define aliases (shortcuts): +- These are great because they can save you time typing. +- But it's easy to forget them, get confused, or be inconsistent with your colleagues. + +There is plenty of other configuration for Git, that can make it nicer. + + +## Aliases + +- Aliases are a simple way to improve the usability of Git: for + example `git ci` instead of `git commit`. +- Aliases are based on simple string replacement in the command. +- Aliases can either be specific to a repository or global. + - Global aliases help you do the things you are used to across Git projects. + - Per-project aliases can also be created. +- Global aliases are stored in `~/.gitconfig`. + + +## Example alias: git graph + +A very useful shortcut which we use a lot in our workshops: + +```console +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ cd your_git_repository +$ git graph +``` + + +## Using external commands + +It is possible to call external commands using the exclamation mark character "!". +In this case we create a local alias which is +stored in `.git/config` and not synchronized with remotes: + +```console +$ cd your_git_repository +$ git config alias.hi '!echo hello' +$ git hi +``` + +```{discussion} Food for thought: When to alias? +- How many times should you wait before aliasing a command? +- Do you believe a list of generic two-letter acronyms for common commands will + save your time? +``` + + +## List of aliases the instructors use + +You are welcome to reuse, suggest, improve. +You can see your current aliases in `~/.gitconfig`. + +```console +$ git config --global alias.ap "add --patch" +$ git config --global alias.br branch +$ git config --global alias.ci "commit -v" +$ git config --global alias.cip "commit --patch -v" +$ git config --global alias.cl "clone --recursive" +$ git config --global alias.co checkout +$ git config --global alias.cop "checkout --patch" +$ git config --global alias.di diff +$ git config --global alias.dic "diff --cached --color-words" +$ git config --global alias.diw "diff --color-words" +$ git config --global alias.dis "!git --no-pager diff --stat" +$ git config --global alias.fe fetch +$ git config --global alias.graph "log --all --graph --decorate --oneline" +$ git config --global alias.rem remote +$ git config --global alias.st status +$ git config --global alias.su "submodule update --init --recursive" +``` + +Here is what they do: +- `ap`: add, selecting parts individually, interactively. +- `br`: branch (obvious) +- `ci`: commit (check in), with `-v` option for clarity +- `cip`: commit, selecting parts individually, interactively. +- `cl`: clone, init submodules (submodules are an advanced topic) +- `co`: checkout (obvious) +- `cop`: checkout, selecting parts individually, interactively. +- `di`: diff (obvious) +- `dic`: diff of staging area vs last commit (what is about to be committed) +- `diw`: a word diff, color. Useful for small changes. +- `dis`: a "diffstat": what files are changed, not contents +- `fe`: fetch (obvious) +- `graph`: show whole git graph (so useful, some of us call it `l`) +- `rem`: remote (obvious) +- `st`: status (obvious) +- `su`: submodule update (advanced) + +A useful setting for the `p` aliases: +```console +$ git config --global interactive.singlekey true +``` + + +## Advanced aliases + +These are advanced aliases and configuration options. We won't explain them, +but if you are bored, have some time, or want to go deeper, try to +figure out what they do. You might want to check the Git manual +pages! + +```console +$ git config --global alias.cif "commit -v -p --fixup" +$ git config --global alias.rb "rebase --autosquash" +$ git config --global alias.rbi "rebase --interactive --autosquash" +$ git config --global alias.rbis "rebase --interactive --autosquash --autostash" +$ git config --global alias.rbs "rebase --autosquash --autostash" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.ls-ignored "ls-files -o -i --exclude-standard" +$ git config --global alias.new "log HEAD..HEAD@{upstream}" +$ git config --global alias.news "log --stat HEAD..HEAD@{upstream}" +$ git config --global alias.newd "log --patch --color-words HEAD..HEAD@{upstream}" +$ git config --global alias.newdi "diff --color-words HEAD...HEAD@{upstream}" +$ git config --global alias.rec "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD" +$ git config --global alias.reca "!git --no-pager log --oneline --graph --decorate -n10 --all" +$ git config --global alias.recd "log --decorate --patch @{upstream}^^^..HEAD" +$ git config --global alias.recs "!git --no-pager log --oneline --graph --decorate @{upstream}^^^..HEAD --stat" +``` + +## Advanced Git configuration + +Besides aliases, you can do plenty of other configuration of `git`. +Here are some of the most common ones: + +```console +$ git config --global interactive.singlekey true +$ git config --global core.pager "less -RS" +$ git config --global core.excludesfile ~/.gitignore +$ git config --global merge.conflictstyle diff3 +$ git config --global diff.wordRegex "[a-zA-Z0-9_]+|[^[:space:]]" +$ git config --global diff.mnemonicPrefix true +``` + +Do you get tired of typing and copying and pasting your remote names +all the time, like `git@github.com:myusername`? You can create remote +aliases like this: + +```console +$ git config --global url.git@github.com:.insteadOf gh: +$ git config --global url.git@github.com:/username/.insteadOf ghu: +``` + +Then, when you add a remote `ghu:recipe`, it will automatically be +translated to `git@github.com:/username/recipe` using a simple prefix +matching. + + +```{keypoints} +- If you are frustrated about remembering a command, you should create an alias. +``` diff --git a/branch/sphinx-book-theme-old-copybutton/_sources/archaeology.md.txt b/branch/sphinx-book-theme-old-copybutton/_sources/archaeology.md.txt new file mode 100644 index 00000000..a387a3e6 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_sources/archaeology.md.txt @@ -0,0 +1,357 @@ +# Inspecting history + +```{objectives} +- Quickly find a line of code, find out why it was introduced and when. +- Quickly find the commit that changed a behavior. +``` + +```{instructor-note} +- 15 min teaching/type-along +- 30 min exercise +``` + +````{prereq} Preparation +Please make sure that you do not clone repositories inside an already tracked folder: + +```console +$ git status +``` + +If you are inside an existing Git repository, step out of it. +You need to find a different location since we will clone a new repository. + +If you see this message, this is good in this case: + +```shell +fatal: not a git repository (or any of the parent directories): .git +``` +```` + + +## Our toolbox for history inspection + +```{instructor-note} +First the instructor demonstrates few commands on a real life example +repository (mentioned in the amazing site [The +Programming Historian](https://programminghistorian.org/)). +Later we will practice these in groups in an archaeology exercise (below). +After demonstrating the command line tools, the instructor can also demonstrate searching, "show" and "annotate" +in the GitHub browser for this example project. +``` + + +### Warm-up: ["Git History" browser](https://githistory.xyz/) + +As a warm-up we can try the ["Git History" browser](https://githistory.xyz/) +on the README.rst file of the [networkx](https://github.com/networkx/networkx) repository: + +- Visit and browse (use left/right keys). +- You can try this on some of your GitHub repositories, too! + + +### git grep: to search through the repository + +With `git grep` you can find all lines in a repository which contain some string or regular expression. +This is useful to find out where in the code some variable is used or some error message printed: + +```console +$ git grep sometext +$ git grep "some text with spaces" +``` + +In the [networkx](https://github.com/networkx/networkx) repository you can try: + +```console +$ git clone https://github.com/networkx/networkx +$ cd networkx +$ git grep -i fixme +``` + + +### git log -S: to search through the history of changes + +While `git grep` searches the **current state** of the repository, +it is also possible to search through all changes for "sometext": + +```console +$ git log -S sometext +``` + +In the [networkx](https://github.com/networkx/networkx) repository you can try: + +```console +$ git log -S test_weakly_connected_component +``` + + +### git show: to inspect commits + +We have seen this one before already. Using `git show` we can inspect an individual commit if +we know its hash: + +```console +$ git show somehash +``` + +For instance: + +```console +$ git show 759d589bdfa61aff99e0535938f14f67b01c83f7 +``` + + +### git annotate: to annotate code with commit metadata + +Try it out on a file - with `git annotate` you can see line by line who and **when** the line was modified +last. It also prints the precise hash of the last change which modified each line. Incredibly useful +for reproducibility. + +```console +$ git annotate somefile +``` + +Example: + +```console +$ git annotate networkx/convert_matrix.py +``` + +If you annotate in a terminal and the file is longer than the screen, Git by default uses the program `less` to +scroll the output. +Use `/sometext` `` to find "sometext" and you can cycle through the results with `n` (next) and `N` (last). +You can also use page up/down to scroll. You can quit with `q`. + +```{discussion} +Discuss how these two affect the annotation: +- wrapping long lines of text/code into shorter lines +- autoformatting tools such as `black` +``` + + +### git checkout -b: to inspect code in the past + +We can create branches pointing to a commit in the past. +This is the recommended mechanism to inspect old code: + +```console +$ git checkout -b branchname somehash +``` + +Example (lines starting with "#" are only comments): + +```console +$ # create branch called "older-code" from hash 347e6292419b +$ git checkout -b older-code 347e6292419bd0e4bff077fe971f983932d7a0e9 + +$ # now you can navigate and inspect the code as it was back then +$ # ... + +$ # after we are done we can switch back to "main" +$ git checkout main + +$ # if we like we can delete the "older-code" branch +$ git branch -d older-code +``` + +On newer Git versions this is the preferred command: + +```console +$ git switch --create branchname somehash +``` + +(exercise-history)= + +## Exercise: Basic archaeology commands + +`````{exercise} History-1: Explore basic archaeology commands + Let us explore the value of these commands in an exercise. Future + exercises do not depend on this, so it is OK if you do not complete + it fully. + + **In-person workshops**: We recommend that you + do this exercise in groups of two and discuss with your neighbors. + + **Video workshops**: We will group you in breakout rooms of ~4 persons where you + can work and discuss together. A helper or instructor will pop in to help out. + In the group one participant can share their screen and others + in the group help out, discuss, and try to follow along. + Please write down questions in the collaborative notes. + After 15-20 minutes we will bring you back into the main room and discuss. + + Exercise steps: + - Clone this repository: + . + Then step into the new directory and create an exercise branch from the networkx-2.6.3 tag/release: + ```console + $ git clone https://github.com/networkx/networkx.git + $ cd networkx + $ git checkout -b exercise networkx-2.6.3 + ``` + + Then using the above toolbox try to: + 1. Find the code line which contains `"Logic error in degree_correlation"`. + 2. Find out when this line was last modified or added. Find the actual commit which modified that line. + 3. Inspect that commit with `git show`. + 4. Create a branch pointing to the past when that commit was created to be + able to browse and use the code as it was back then. + 5. How would can you bring the code to the commit precisely before that line was last modified? + + ````{solution} + 1. We use `git grep`: + ```console + $ git grep "Logic error in degree_correlation" + ``` + This gives the output: + ``` + networkx/algorithms/threshold.py: print("Logic error in degree_correlation", i, rdi) + ``` + Maybe you also want to know the line number: + ```console + $ git grep -n "Logic error in degree_correlation" + ``` + 2. We use `git annotate`: + ```console + $ git annotate networkx/algorithms/threshold.py + ``` + Then search for "Logic error" by typing "/Logic error" followed by Enter. + The last commit that modified it was `90544b4fa` (unless that line changed since). + 3. We use `git show`: + ```console + $ git show 90544b4fa + ``` + 4. Create a branch pointing to that commit (here we called the branch "past-code"): + ```console + $ git branch past-code 90544b4fa + ``` + 5. This is a compact way to access the first parent of `90544b4fa` (here we + called the branch "just-before"): + ```console + $ git checkout -b just-before 90544b4fa~1 + ``` + ```` +````` + +--- + +## Finding out when something broke/changed with git bisect + +> *But I am sure it used to work! Strange.* + +- Sometimes you realize that something broke. +- You know that it used to work. +- You do not know when it broke. + +```{discussion} How would you solve this? +Before we go on first discuss how you would solve this problem: You know that it worked +500 commits ago but it does not work now. + +- How would you find the commit which changed it? +- Why could it be useful to know the commit that changed it? + +**Video workshops**: Write down ideas on how you would solve it in the collaborative +note and we will discuss various approaches. +``` + +We will probably arrive at a solution which is similar to `git bisect`: + +- First find out a commit in past when it worked. +- Then bisect your way until you find the commit that broke it. + +```console +$ git bisect start +$ git bisect good f0ea950 # this is a commit that worked +$ git bisect bad main # last commit is broken + +$ # now compile and/or run +$ # after that decide whether +$ git bisect good +$ # or +$ git bisect bad + +$ # now compile and/or run +$ # after that decide whether +$ git bisect good +$ # or +$ git bisect bad + +$ # iterate until commit is found +``` + +- This can even be automatized with `git bisect run +{% endmacro %} diff --git a/branch/sphinx-book-theme-old-copybutton/_static/scripts/pydata-sphinx-theme.js b/branch/sphinx-book-theme-old-copybutton/_static/scripts/pydata-sphinx-theme.js new file mode 100644 index 00000000..0e00c4ca --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_static/scripts/pydata-sphinx-theme.js @@ -0,0 +1,32 @@ +!function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=2)}([function(t,e){t.exports=jQuery},function(t,e,n){"use strict";n.r(e),function(t){ +/**! + * @fileOverview Kickass library to create and place poppers near their reference elements. + * @version 1.16.1 + * @license + * Copyright (c) 2016 Federico Zivolo and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +var n="undefined"!=typeof window&&"undefined"!=typeof document&&"undefined"!=typeof navigator,i=function(){for(var t=["Edge","Trident","Firefox"],e=0;e=0)return 1;return 0}();var o=n&&window.Promise?function(t){var e=!1;return function(){e||(e=!0,window.Promise.resolve().then((function(){e=!1,t()})))}}:function(t){var e=!1;return function(){e||(e=!0,setTimeout((function(){e=!1,t()}),i))}};function r(t){return t&&"[object Function]"==={}.toString.call(t)}function a(t,e){if(1!==t.nodeType)return[];var n=t.ownerDocument.defaultView.getComputedStyle(t,null);return e?n[e]:n}function s(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function l(t){if(!t)return document.body;switch(t.nodeName){case"HTML":case"BODY":return t.ownerDocument.body;case"#document":return t.body}var e=a(t),n=e.overflow,i=e.overflowX,o=e.overflowY;return/(auto|scroll|overlay)/.test(n+o+i)?t:l(s(t))}function u(t){return t&&t.referenceNode?t.referenceNode:t}var f=n&&!(!window.MSInputMethodContext||!document.documentMode),d=n&&/MSIE 10/.test(navigator.userAgent);function c(t){return 11===t?f:10===t?d:f||d}function h(t){if(!t)return document.documentElement;for(var e=c(10)?document.body:null,n=t.offsetParent||null;n===e&&t.nextElementSibling;)n=(t=t.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&"BODY"!==i&&"HTML"!==i?-1!==["TH","TD","TABLE"].indexOf(n.nodeName)&&"static"===a(n,"position")?h(n):n:t?t.ownerDocument.documentElement:document.documentElement}function p(t){return null!==t.parentNode?p(t.parentNode):t}function m(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,o=n?e:t,r=document.createRange();r.setStart(i,0),r.setEnd(o,0);var a,s,l=r.commonAncestorContainer;if(t!==l&&e!==l||i.contains(o))return"BODY"===(s=(a=l).nodeName)||"HTML"!==s&&h(a.firstElementChild)!==a?h(l):l;var u=p(t);return u.host?m(u.host,e):m(t,p(e).host)}function g(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===e?"scrollTop":"scrollLeft",i=t.nodeName;if("BODY"===i||"HTML"===i){var o=t.ownerDocument.documentElement,r=t.ownerDocument.scrollingElement||o;return r[n]}return t[n]}function v(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=g(e,"top"),o=g(e,"left"),r=n?-1:1;return t.top+=i*r,t.bottom+=i*r,t.left+=o*r,t.right+=o*r,t}function _(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return parseFloat(t["border"+n+"Width"])+parseFloat(t["border"+i+"Width"])}function b(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],c(10)?parseInt(n["offset"+t])+parseInt(i["margin"+("Height"===t?"Top":"Left")])+parseInt(i["margin"+("Height"===t?"Bottom":"Right")]):0)}function y(t){var e=t.body,n=t.documentElement,i=c(10)&&getComputedStyle(n);return{height:b("Height",e,n,i),width:b("Width",e,n,i)}}var w=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},E=function(){function t(t,e){for(var n=0;n2&&void 0!==arguments[2]&&arguments[2],i=c(10),o="HTML"===e.nodeName,r=N(t),s=N(e),u=l(t),f=a(e),d=parseFloat(f.borderTopWidth),h=parseFloat(f.borderLeftWidth);n&&o&&(s.top=Math.max(s.top,0),s.left=Math.max(s.left,0));var p=S({top:r.top-s.top-d,left:r.left-s.left-h,width:r.width,height:r.height});if(p.marginTop=0,p.marginLeft=0,!i&&o){var m=parseFloat(f.marginTop),g=parseFloat(f.marginLeft);p.top-=d-m,p.bottom-=d-m,p.left-=h-g,p.right-=h-g,p.marginTop=m,p.marginLeft=g}return(i&&!n?e.contains(u):e===u&&"BODY"!==u.nodeName)&&(p=v(p,e)),p}function k(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=t.ownerDocument.documentElement,i=D(t,n),o=Math.max(n.clientWidth,window.innerWidth||0),r=Math.max(n.clientHeight,window.innerHeight||0),a=e?0:g(n),s=e?0:g(n,"left"),l={top:a-i.top+i.marginTop,left:s-i.left+i.marginLeft,width:o,height:r};return S(l)}function A(t){var e=t.nodeName;if("BODY"===e||"HTML"===e)return!1;if("fixed"===a(t,"position"))return!0;var n=s(t);return!!n&&A(n)}function I(t){if(!t||!t.parentElement||c())return document.documentElement;for(var e=t.parentElement;e&&"none"===a(e,"transform");)e=e.parentElement;return e||document.documentElement}function O(t,e,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4],r={top:0,left:0},a=o?I(t):m(t,u(e));if("viewport"===i)r=k(a,o);else{var f=void 0;"scrollParent"===i?"BODY"===(f=l(s(e))).nodeName&&(f=t.ownerDocument.documentElement):f="window"===i?t.ownerDocument.documentElement:i;var d=D(f,a,o);if("HTML"!==f.nodeName||A(a))r=d;else{var c=y(t.ownerDocument),h=c.height,p=c.width;r.top+=d.top-d.marginTop,r.bottom=h+d.top,r.left+=d.left-d.marginLeft,r.right=p+d.left}}var g="number"==typeof(n=n||0);return r.left+=g?n:n.left||0,r.top+=g?n:n.top||0,r.right-=g?n:n.right||0,r.bottom-=g?n:n.bottom||0,r}function x(t){return t.width*t.height}function j(t,e,n,i,o){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var a=O(n,i,r,o),s={top:{width:a.width,height:e.top-a.top},right:{width:a.right-e.right,height:a.height},bottom:{width:a.width,height:a.bottom-e.bottom},left:{width:e.left-a.left,height:a.height}},l=Object.keys(s).map((function(t){return C({key:t},s[t],{area:x(s[t])})})).sort((function(t,e){return e.area-t.area})),u=l.filter((function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight})),f=u.length>0?u[0].key:l[0].key,d=t.split("-")[1];return f+(d?"-"+d:"")}function L(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o=i?I(e):m(e,u(n));return D(n,o,i)}function P(t){var e=t.ownerDocument.defaultView.getComputedStyle(t),n=parseFloat(e.marginTop||0)+parseFloat(e.marginBottom||0),i=parseFloat(e.marginLeft||0)+parseFloat(e.marginRight||0);return{width:t.offsetWidth+i,height:t.offsetHeight+n}}function F(t){var e={left:"right",right:"left",bottom:"top",top:"bottom"};return t.replace(/left|right|bottom|top/g,(function(t){return e[t]}))}function R(t,e,n){n=n.split("-")[0];var i=P(t),o={width:i.width,height:i.height},r=-1!==["right","left"].indexOf(n),a=r?"top":"left",s=r?"left":"top",l=r?"height":"width",u=r?"width":"height";return o[a]=e[a]+e[l]/2-i[l]/2,o[s]=n===s?e[s]-i[u]:e[F(s)],o}function M(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function B(t,e,n){return(void 0===n?t:t.slice(0,function(t,e,n){if(Array.prototype.findIndex)return t.findIndex((function(t){return t[e]===n}));var i=M(t,(function(t){return t[e]===n}));return t.indexOf(i)}(t,"name",n))).forEach((function(t){t.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=t.function||t.fn;t.enabled&&r(n)&&(e.offsets.popper=S(e.offsets.popper),e.offsets.reference=S(e.offsets.reference),e=n(e,t))})),e}function H(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=L(this.state,this.popper,this.reference,this.options.positionFixed),t.placement=j(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.positionFixed=this.options.positionFixed,t.offsets.popper=R(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position=this.options.positionFixed?"fixed":"absolute",t=B(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function q(t,e){return t.some((function(t){var n=t.name;return t.enabled&&n===e}))}function Q(t){for(var e=[!1,"ms","Webkit","Moz","O"],n=t.charAt(0).toUpperCase()+t.slice(1),i=0;i1&&void 0!==arguments[1]&&arguments[1],n=Z.indexOf(t),i=Z.slice(n+1).concat(Z.slice(0,n));return e?i.reverse():i}var et="flip",nt="clockwise",it="counterclockwise";function ot(t,e,n,i){var o=[0,0],r=-1!==["right","left"].indexOf(i),a=t.split(/(\+|\-)/).map((function(t){return t.trim()})),s=a.indexOf(M(a,(function(t){return-1!==t.search(/,|\s/)})));a[s]&&-1===a[s].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var l=/\s*,\s*|\s+/,u=-1!==s?[a.slice(0,s).concat([a[s].split(l)[0]]),[a[s].split(l)[1]].concat(a.slice(s+1))]:[a];return(u=u.map((function(t,i){var o=(1===i?!r:r)?"height":"width",a=!1;return t.reduce((function(t,e){return""===t[t.length-1]&&-1!==["+","-"].indexOf(e)?(t[t.length-1]=e,a=!0,t):a?(t[t.length-1]+=e,a=!1,t):t.concat(e)}),[]).map((function(t){return function(t,e,n,i){var o=t.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+o[1],a=o[2];if(!r)return t;if(0===a.indexOf("%")){var s=void 0;switch(a){case"%p":s=n;break;case"%":case"%r":default:s=i}return S(s)[e]/100*r}if("vh"===a||"vw"===a){return("vh"===a?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*r}return r}(t,o,e,n)}))}))).forEach((function(t,e){t.forEach((function(n,i){K(n)&&(o[e]+=n*("-"===t[i-1]?-1:1))}))})),o}var rt={placement:"bottom",positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(t){var e=t.placement,n=e.split("-")[0],i=e.split("-")[1];if(i){var o=t.offsets,r=o.reference,a=o.popper,s=-1!==["bottom","top"].indexOf(n),l=s?"left":"top",u=s?"width":"height",f={start:T({},l,r[l]),end:T({},l,r[l]+r[u]-a[u])};t.offsets.popper=C({},a,f[i])}return t}},offset:{order:200,enabled:!0,fn:function(t,e){var n=e.offset,i=t.placement,o=t.offsets,r=o.popper,a=o.reference,s=i.split("-")[0],l=void 0;return l=K(+n)?[+n,0]:ot(n,r,a,s),"left"===s?(r.top+=l[0],r.left-=l[1]):"right"===s?(r.top+=l[0],r.left+=l[1]):"top"===s?(r.left+=l[0],r.top-=l[1]):"bottom"===s&&(r.left+=l[0],r.top+=l[1]),t.popper=r,t},offset:0},preventOverflow:{order:300,enabled:!0,fn:function(t,e){var n=e.boundariesElement||h(t.instance.popper);t.instance.reference===n&&(n=h(n));var i=Q("transform"),o=t.instance.popper.style,r=o.top,a=o.left,s=o[i];o.top="",o.left="",o[i]="";var l=O(t.instance.popper,t.instance.reference,e.padding,n,t.positionFixed);o.top=r,o.left=a,o[i]=s,e.boundaries=l;var u=e.priority,f=t.offsets.popper,d={primary:function(t){var n=f[t];return f[t]l[t]&&!e.escapeWithReference&&(i=Math.min(f[n],l[t]-("right"===t?f.width:f.height))),T({},n,i)}};return u.forEach((function(t){var e=-1!==["left","top"].indexOf(t)?"primary":"secondary";f=C({},f,d[e](t))})),t.offsets.popper=f,t},priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:function(t){var e=t.offsets,n=e.popper,i=e.reference,o=t.placement.split("-")[0],r=Math.floor,a=-1!==["top","bottom"].indexOf(o),s=a?"right":"bottom",l=a?"left":"top",u=a?"width":"height";return n[s]r(i[s])&&(t.offsets.popper[l]=r(i[s])),t}},arrow:{order:500,enabled:!0,fn:function(t,e){var n;if(!G(t.instance.modifiers,"arrow","keepTogether"))return t;var i=e.element;if("string"==typeof i){if(!(i=t.instance.popper.querySelector(i)))return t}else if(!t.instance.popper.contains(i))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),t;var o=t.placement.split("-")[0],r=t.offsets,s=r.popper,l=r.reference,u=-1!==["left","right"].indexOf(o),f=u?"height":"width",d=u?"Top":"Left",c=d.toLowerCase(),h=u?"left":"top",p=u?"bottom":"right",m=P(i)[f];l[p]-ms[p]&&(t.offsets.popper[c]+=l[c]+m-s[p]),t.offsets.popper=S(t.offsets.popper);var g=l[c]+l[f]/2-m/2,v=a(t.instance.popper),_=parseFloat(v["margin"+d]),b=parseFloat(v["border"+d+"Width"]),y=g-t.offsets.popper[c]-_-b;return y=Math.max(Math.min(s[f]-m,y),0),t.arrowElement=i,t.offsets.arrow=(T(n={},c,Math.round(y)),T(n,h,""),n),t},element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:function(t,e){if(q(t.instance.modifiers,"inner"))return t;if(t.flipped&&t.placement===t.originalPlacement)return t;var n=O(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement,t.positionFixed),i=t.placement.split("-")[0],o=F(i),r=t.placement.split("-")[1]||"",a=[];switch(e.behavior){case et:a=[i,o];break;case nt:a=tt(i);break;case it:a=tt(i,!0);break;default:a=e.behavior}return a.forEach((function(s,l){if(i!==s||a.length===l+1)return t;i=t.placement.split("-")[0],o=F(i);var u=t.offsets.popper,f=t.offsets.reference,d=Math.floor,c="left"===i&&d(u.right)>d(f.left)||"right"===i&&d(u.left)d(f.top)||"bottom"===i&&d(u.top)d(n.right),m=d(u.top)d(n.bottom),v="left"===i&&h||"right"===i&&p||"top"===i&&m||"bottom"===i&&g,_=-1!==["top","bottom"].indexOf(i),b=!!e.flipVariations&&(_&&"start"===r&&h||_&&"end"===r&&p||!_&&"start"===r&&m||!_&&"end"===r&&g),y=!!e.flipVariationsByContent&&(_&&"start"===r&&p||_&&"end"===r&&h||!_&&"start"===r&&g||!_&&"end"===r&&m),w=b||y;(c||v||w)&&(t.flipped=!0,(c||v)&&(i=a[l+1]),w&&(r=function(t){return"end"===t?"start":"start"===t?"end":t}(r)),t.placement=i+(r?"-"+r:""),t.offsets.popper=C({},t.offsets.popper,R(t.instance.popper,t.offsets.reference,t.placement)),t=B(t.instance.modifiers,t,"flip"))})),t},behavior:"flip",padding:5,boundariesElement:"viewport",flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(t){var e=t.placement,n=e.split("-")[0],i=t.offsets,o=i.popper,r=i.reference,a=-1!==["left","right"].indexOf(n),s=-1===["top","left"].indexOf(n);return o[a?"left":"top"]=r[n]-(s?o[a?"width":"height"]:0),t.placement=F(e),t.offsets.popper=S(o),t}},hide:{order:800,enabled:!0,fn:function(t){if(!G(t.instance.modifiers,"hide","preventOverflow"))return t;var e=t.offsets.reference,n=M(t.instance.modifiers,(function(t){return"preventOverflow"===t.name})).boundaries;if(e.bottomn.right||e.top>n.bottom||e.right2&&void 0!==arguments[2]?arguments[2]:{};w(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=o(this.update.bind(this)),this.options=C({},t.Defaults,a),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e&&e.jquery?e[0]:e,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(C({},t.Defaults.modifiers,a.modifiers)).forEach((function(e){i.options.modifiers[e]=C({},t.Defaults.modifiers[e]||{},a.modifiers?a.modifiers[e]:{})})),this.modifiers=Object.keys(this.options.modifiers).map((function(t){return C({name:t},i.options.modifiers[t])})).sort((function(t,e){return t.order-e.order})),this.modifiers.forEach((function(t){t.enabled&&r(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)})),this.update();var s=this.options.eventsEnabled;s&&this.enableEventListeners(),this.state.eventsEnabled=s}return E(t,[{key:"update",value:function(){return H.call(this)}},{key:"destroy",value:function(){return W.call(this)}},{key:"enableEventListeners",value:function(){return Y.call(this)}},{key:"disableEventListeners",value:function(){return z.call(this)}}]),t}();at.Utils=("undefined"!=typeof window?window:t).PopperUtils,at.placements=J,at.Defaults=rt,e.default=at}.call(this,n(4))},function(t,e,n){t.exports=n(5)},function(t,e,n){ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),r=i(n);function a(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=f,o.default.event.special[d.TRANSITION_END]={bindType:"transitionend",delegateType:"transitionend",handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c=o.default.fn.alert,h=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,"bs.alert"),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.alert");i||(i=new t(this),n.data("bs.alert",i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',h._handleDismiss(new h)),o.default.fn.alert=h._jQueryInterface,o.default.fn.alert.Constructor=h,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=c,h._jQueryInterface};var p=o.default.fn.button,m=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector('input:not([type="hidden"])');if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains("active"))t=!1;else{var r=n.querySelector(".active");r&&o.default(r).removeClass("active")}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains("active")),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains("active")),t&&o.default(this._element).toggleClass("active"))},e.dispose=function(){o.default.removeData(this._element,"bs.button"),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),r=i.data("bs.button");r||(r=new t(this),i.data("bs.button",r)),r.shouldAvoidTriggerChange=n,"toggle"===e&&r[e]()}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(".btn")[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector('input:not([type="hidden"])');if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||m._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=o.default(t.target).closest(".btn")[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide("next")},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide("prev")},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(".active.carousel-item");var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one("slid.bs.carousel",(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?"next":"prev";this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(v),o.default.removeData(this._element,"bs.carousel"),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=l({},b,t),d.typeCheckConfig(g,t,y),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n="next"===t,i="prev"===t,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var a=(o+("prev"===t?-1:1))%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(".active.carousel-item")),r=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(r),r},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass("active");var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass("active")}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(".active.carousel-item");if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,r,a=this,s=this._element.querySelector(".active.carousel-item"),l=this._getItemIndex(s),u=e||s&&this._getItemByDirection(t,s),f=this._getItemIndex(u),c=Boolean(this._interval);if("next"===t?(n="carousel-item-left",i="carousel-item-next",r="left"):(n="carousel-item-right",i="carousel-item-prev",r="right"),u&&o.default(u).hasClass("active"))this._isSliding=!1;else if(!this._triggerSlideEvent(u,r).isDefaultPrevented()&&s&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event("slid.bs.carousel",{relatedTarget:u,direction:r,from:l,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(s).addClass(n),o.default(u).addClass(n);var p=d.getTransitionDurationFromElement(s);o.default(s).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass("active"),o.default(s).removeClass("active "+i+" "+n),a._isSliding=!1,setTimeout((function(){return o.default(a._element).trigger(h)}),0)})).emulateTransitionEnd(p)}else o.default(s).removeClass("active"),o.default(u).addClass("active"),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data("bs.carousel"),i=l({},b,o.default(this).data());"object"==typeof e&&(i=l({},i,e));var r="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data("bs.carousel",n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new TypeError('No method named "'+r+'"');n[r]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var r=l({},o.default(i).data(),o.default(this).data()),a=this.getAttribute("data-slide-to");a&&(r.interval=!1),t._jQueryInterface.call(o.default(i),r),a&&o.default(i).data("bs.carousel").to(a),e.preventDefault()}}},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return b}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",E._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=a,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass("show")?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass("show")||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains("collapse")}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data("bs.collapse"))&&n._isTransitioning))){var r=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(r),!r.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data("bs.collapse",null));var a=this._getDimension();o.default(this._element).removeClass("collapse").addClass("collapsing"),this._element.style[a]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass("collapsed").attr("aria-expanded",!0),this.setTransitioning(!0);var s="scroll"+(a[0].toUpperCase()+a.slice(1)),l=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass("collapsing").addClass("collapse show"),i._element.style[a]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(l),this._element.style[a]=this._element[s]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass("show")){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass("collapsing").removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var r=0;r0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=l({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),l({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data("bs.dropdown");if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data("bs.dropdown",n)),"string"==typeof e){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll('[data-toggle="dropdown"]')),i=0,r=n.length;i0&&a--,40===e.which&&adocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add("modal-static");var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove("modal-static"),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass("fade"),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass("show"),this._config.focus&&this._enforceFocus();var r=o.default.Event("shown.bs.modal",{relatedTarget:t}),a=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(r)};if(n){var s=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()},e._enforceFocus=function(){var t=this;o.default(document).off("focusin.bs.modal").on("focusin.bs.modal",(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on("keydown.dismiss.bs.modal",(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off("keydown.dismiss.bs.modal")},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on("resize.bs.modal",(function(e){return t.handleUpdate(e)})):o.default(window).off("resize.bs.modal")},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass("modal-open"),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger("hidden.bs.modal")}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass("fade")?"fade":"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on("click.dismiss.bs.modal",(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass("show"),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass("show");var r=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass("fade")){var a=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,r).emulateTransitionEnd(a)}else r()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:B,popperConfig:null},X={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},$={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},G=function(){function t(t,e){if(void 0===r.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass("show"))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var a=this.getTipElement(),s=d.getUID(this.constructor.NAME);a.setAttribute("id",s),this.element.setAttribute("aria-describedby",s),this.setContent(),this.config.animation&&o.default(a).addClass("fade");var l="function"==typeof this.config.placement?this.config.placement.call(this,a,this.element):this.config.placement,u=this._getAttachment(l);this.addAttachmentClass(u);var f=this._getContainer();o.default(a).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(a).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new r.default(this.element,a,this._getPopperConfig(u)),o.default(a).addClass("show"),o.default(a).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),"out"===e&&t._leave(null,t)};if(o.default(this.tip).hasClass("fade")){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),r=function(){"show"!==e._hoverState&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass("show"),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass("fade")){var a=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,r).emulateTransitionEnd(a)}else r();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Q(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return l({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=l({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return z[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n="hover"===e?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i="hover"===e?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),o.default(e.getTipElement()).hasClass("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){"show"===e._hoverState&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){"out"===e._hoverState&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Y.indexOf(t)&&delete e[t]})),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(W,t,this.constructor.DefaultType),t.sanitize&&(t.template=Q(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(V);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass("fade"),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.tooltip"),r="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,r),n.data("bs.tooltip",i)),"string"==typeof e)){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return K}},{key:"NAME",get:function(){return W}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return $}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return X}}]),t}();o.default.fn[W]=G._jQueryInterface,o.default.fn[W].Constructor=G,o.default.fn[W].noConflict=function(){return o.default.fn[W]=U,G._jQueryInterface};var J="popover",Z=o.default.fn[J],tt=new RegExp("(^|\\s)bs-popover\\S+","g"),et=l({},G.Default,{placement:"right",trigger:"click",content:"",template:''}),nt=l({},G.DefaultType,{content:"(string|element|function)"}),it={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},ot=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},r.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},r.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(tt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data("bs.popover"),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data("bs.popover",e)),"string"==typeof t)){if(void 0===e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},s(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return et}},{key:"NAME",get:function(){return J}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return it}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return nt}}]),i}(G);o.default.fn[J]=ot._jQueryInterface,o.default.fn[J].Constructor=ot,o.default.fn[J].noConflict=function(){return o.default.fn[J]=Z,ot._jQueryInterface};var rt="scrollspy",at=o.default.fn[rt],st={offset:10,method:"auto",target:""},lt={offset:"number",method:"string",target:"(string|element)"},ut=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":"position",n="auto"===this._config.method?e:this._config.method,i="position"===n?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,r=d.getSelectorFromElement(t);if(r&&(e=document.querySelector(r)),e){var a=e.getBoundingClientRect();if(a.width||a.height)return[o.default(e)[n]().top+i,r]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,"bs.scrollspy"),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=l({},st,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(rt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(rt,t,lt),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t li > .active":".active";n=(n=o.default.makeArray(o.default(i).find(a)))[n.length-1]}var s=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),l=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(s),o.default(this._element).trigger(l),!l.isDefaultPrevented()&&!s.isDefaultPrevented()){r&&(e=document.querySelector(r)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,"bs.tab"),this._element=null},e._activate=function(t,e,n){var i=this,r=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(".active"):o.default(e).find("> li > .active"))[0],a=n&&r&&o.default(r).hasClass("fade"),s=function(){return i._transitionComplete(t,r,n)};if(r&&a){var l=d.getTransitionDurationFromElement(r);o.default(r).removeClass("show").one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass("active");var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains("fade")&&t.classList.add("show");var r=t.parentNode;if(r&&"LI"===r.nodeName&&(r=r.parentNode),r&&o.default(r).hasClass("dropdown-menu")){var a=o.default(t).closest(".dropdown")[0];if(a){var s=[].slice.call(a.querySelectorAll(".dropdown-toggle"));o.default(s).addClass("active")}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.tab");if(i||(i=new t(this),n.data("bs.tab",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),dt._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=dt._jQueryInterface,o.default.fn.tab.Constructor=dt,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=ft,dt._jQueryInterface};var ct="toast",ht=o.default.fn[ct],pt={animation:!0,autohide:!0,delay:500},mt={animation:"boolean",autohide:"boolean",delay:"number"},gt=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove("showing"),t._element.classList.add("show"),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove("hide"),d.reflow(this._element),this._element.classList.add("showing"),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains("show")){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),o.default(this._element).off("click.dismiss.bs.toast"),o.default.removeData(this._element,"bs.toast"),this._element=null,this._config=null},e._getConfig=function(t){return t=l({},pt,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig(ct,t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on("click.dismiss.bs.toast",'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add("hide"),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove("show"),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.toast");if(i||(i=new t(this,"object"==typeof e&&e),n.data("bs.toast",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return mt}},{key:"Default",get:function(){return pt}}]),t}();o.default.fn[ct]=gt._jQueryInterface,o.default.fn[ct].Constructor=gt,o.default.fn[ct].noConflict=function(){return o.default.fn[ct]=ht,gt._jQueryInterface},t.Alert=h,t.Button=m,t.Carousel=E,t.Collapse=D,t.Dropdown=j,t.Modal=R,t.Popover=ot,t.Scrollspy=ut,t.Tab=dt,t.Toast=gt,t.Tooltip=G,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})}(e,n(0),n(1))},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){"use strict";n.r(e);n(0),n(3),n.p;$((function(){var t=document.querySelector("div.bd-sidebar");let e=parseInt(sessionStorage.getItem("sidebar-scroll-top"),10);if(isNaN(e)){var n=document.getElementById("bd-docs-nav").querySelectorAll(".active");if(n.length>0){var i=n[n.length-1],o=i.getBoundingClientRect().y-t.getBoundingClientRect().y;if(i.getBoundingClientRect().y>.5*window.innerHeight){let e=.25;t.scrollTop=o-t.clientHeight*e,console.log("[PST]: Scrolled sidebar using last active link...")}}}else t.scrollTop=e,console.log("[PST]: Scrolled sidebar using stored browser position...");window.addEventListener("beforeunload",()=>{sessionStorage.setItem("sidebar-scroll-top",t.scrollTop)})})),$((function(){$(window).on("activate.bs.scrollspy",(function(){document.querySelectorAll("#bd-toc-nav a").forEach(t=>{t.parentElement.classList.remove("active")});document.querySelectorAll("#bd-toc-nav a.active").forEach(t=>{t.parentElement.classList.add("active")})}))}))}]); \ No newline at end of file diff --git a/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js b/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js new file mode 100644 index 00000000..a8a305eb --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js @@ -0,0 +1,2 @@ +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";n.r(t);n.p;var o=e=>{"loading"!=document.readyState?e():document.addEventListener?document.addEventListener("DOMContentLoaded",e):document.attachEvent("onreadystatechange",(function(){"complete"==document.readyState&&e()}))};window.initThebeSBT=()=>{var e=$("div.section h1")[0];$(e).next().hasClass("thebe-launch-button")||$("").insertAfter($(e)),initThebe()},window.printPdf=e=>{let t=$(e).attr("aria-describedby"),n=$("#"+t).detach();window.print(),$("body").append(n)},window.toggleFullScreen=()=>{var e=document.fullscreenElement&&null!==document.fullscreenElement||document.webkitFullscreenElement&&null!==document.webkitFullscreenElement;let t=document.documentElement;e?(console.log("[SBT]: Exiting full screen"),document.exitFullscreen?document.exitFullscreen():document.webkitExitFullscreen&&document.webkitExitFullscreen()):(console.log("[SBT]: Entering full screen"),t.requestFullscreen?t.requestFullscreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen())},o(()=>{$(document).ready((function(){$('[data-toggle="tooltip"]').tooltip({trigger:"hover",delay:{show:500,hide:100}})}))}),o(()=>{var e=document.getElementById("site-navigation"),t=e.querySelectorAll(".active"),n=t[t.length-1];void 0!==n&&n.offsetTop>.5*$(window).height()&&(e.scrollTop=n.offsetTop-.2*$(window).height())}),o(()=>{var e=[];let t=new IntersectionObserver((t,n)=>{t.forEach(t=>{if(t.isIntersecting)e.push(t.target);else for(let n=0;n0?$("div.bd-toc").removeClass("show"):$("div.bd-toc").addClass("show")});let n=[];["marginnote","sidenote","margin","margin-caption","full-width","sidebar","popout"].forEach(e=>{n.push("."+e,".tag_"+e,"."+e.replace("-","_"),".tag_"+e.replace("-","_"))}),document.querySelectorAll(n.join(", ")).forEach(e=>{t.observe(e)}),new IntersectionObserver((e,t)=>{e[0].boundingClientRect.y<0?document.body.classList.add("scrolled"):document.body.classList.remove("scrolled")}).observe(document.querySelector(".sbt-scroll-pixel-helper"))}),o((function(){new MutationObserver((e,t)=>{e.forEach(e=>{0!==e.addedNodes.length&&void 0!==e.addedNodes[0].data&&-1!=e.addedNodes[0].data.search("Inserted RTD Footer")&&e.addedNodes.forEach(e=>{document.getElementById("rtd-footer-container").append(e)})})}).observe(document.body,{childList:!0})}))}]); +//# sourceMappingURL=sphinx-book-theme.js.map \ No newline at end of file diff --git a/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js.map b/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js.map new file mode 100644 index 00000000..dccd768e --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_static/scripts/sphinx-book-theme.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/sphinx_book_theme/assets/styles/index.scss","webpack:///./src/sphinx_book_theme/assets/scripts/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","sbRunWhenDOMLoaded","cb","document","readyState","addEventListener","attachEvent","window","initThebeSBT","title","$","next","hasClass","insertAfter","initThebe","printPdf","el","tooltipID","attr","tooltipTextDiv","detach","print","append","toggleFullScreen","isInFullScreen","fullscreenElement","webkitFullscreenElement","docElm","documentElement","console","log","exitFullscreen","webkitExitFullscreen","requestFullscreen","webkitRequestFullscreen","ready","tooltip","trigger","delay","show","hide","navbar","getElementById","active_pages","querySelectorAll","active_page","length","undefined","offsetTop","height","scrollTop","onScreenItems","tocObserver","IntersectionObserver","entries","observer","forEach","entry","isIntersecting","push","target","ii","splice","removeClass","addClass","marginSelector","replace","join","observe","boundingClientRect","y","body","classList","add","remove","querySelector","MutationObserver","mutationList","mutation","addedNodes","data","search","node","childList"],"mappings":"aACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QAKfF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,GAIjBlC,EAAoBA,EAAoBmC,EAAI,G,sEClFtC,QCSXC,EAAsBC,IACG,WAAvBC,SAASC,WACXF,IACSC,SAASE,iBAClBF,SAASE,iBAAiB,mBAAoBH,GAE9CC,SAASG,YAAY,sBAAsB,WACd,YAAvBH,SAASC,YAA0BF,QAyM7CK,OAAOC,aAjDY,KACjB,IAAIC,EAAQC,EAAE,kBAAkB,GAC3BA,EAAED,GAAOE,OAAOC,SAAS,wBAC5BF,EAAE,iDAAiDG,YAAYH,EAAED,IAEnEK,aA6CFP,OAAOQ,SAhJSC,IAGd,IAAIC,EAAYP,EAAEM,GAAIE,KAAK,oBACvBC,EAAiBT,EAAE,IAAMO,GAAWG,SACxCb,OAAOc,QACPX,EAAE,QAAQY,OAAOH,IA2InBZ,OAAOgB,iBA/LgB,KACrB,IAAIC,EACDrB,SAASsB,mBAAoD,OAA/BtB,SAASsB,mBACvCtB,SAASuB,yBAC6B,OAArCvB,SAASuB,wBACb,IAAIC,EAASxB,SAASyB,gBACjBJ,GAQHK,QAAQC,IAAI,8BACR3B,SAAS4B,eACX5B,SAAS4B,iBACA5B,SAAS6B,sBAClB7B,SAAS6B,yBAXXH,QAAQC,IAAI,+BACRH,EAAOM,kBACTN,EAAOM,oBACEN,EAAOO,yBAChBP,EAAOO,4BAyLbjC,EA7CmB,KACjBS,EAAEP,UAAUgC,OAAM,WAChBzB,EAAE,2BAA2B0B,QAAQ,CACnCC,QAAS,QACTC,MAAO,CAAEC,KAAM,IAAKC,KAAM,YA0ChCvC,EAxKqB,KACnB,IAAIwC,EAAStC,SAASuC,eAAe,mBACjCC,EAAeF,EAAOG,iBAAiB,WACvCC,EAAcF,EAAaA,EAAaG,OAAS,QAGnCC,IAAhBF,GACAA,EAAYG,UAAiC,GAArBtC,EAAEH,QAAQ0C,WAElCR,EAAOS,UAAYL,EAAYG,UAAiC,GAArBtC,EAAEH,QAAQ0C,YAgKzDhD,EAjIkB,KAChB,IAAIkD,EAAgB,GACpB,IAkCIC,EAAc,IAAIC,qBAlCA,CAACC,EAASC,KAE9BD,EAAQE,QAASC,IACf,GAAIA,EAAMC,eAERP,EAAcQ,KAAKF,EAAMG,aAGzB,IAAK,IAAIC,EAAK,EAAGA,EAAKV,EAAcL,OAAQe,IAC1C,GAAIV,EAAcU,KAAQJ,EAAMG,OAAQ,CACtCT,EAAcW,OAAOD,EAAI,GACzB,SAOJV,EAAcL,OAAS,EACzBpC,EAAE,cAAcqD,YAAY,QAE5BrD,EAAE,cAAcsD,SAAS,UAwB7B,IAAIC,EAAiB,GATG,CACtB,aACA,WACA,SACA,iBACA,aACA,UACA,UAGcT,QAASK,IAEvBI,EAAeN,KAEX,IAAIE,EACJ,QAAQA,EACR,IAAIA,EAAGK,QAAQ,IAAK,KACpB,QAAQL,EAAGK,QAAQ,IAAK,QAI9B/D,SAASyC,iBAAiBqB,EAAeE,KAAK,OAAOX,QAASK,IAC5DT,EAAYgB,QAAQP,KAID,IAAIR,qBAtCO,CAACC,EAASC,KAEpCD,EAAQ,GAAGe,mBAAmBC,EAAI,EACpCnE,SAASoE,KAAKC,UAAUC,IAAI,YAE5BtE,SAASoE,KAAKC,UAAUE,OAAO,cAkCpBN,QAAQjE,SAASwE,cAAc,+BAiEhD1E,GApCA,WAkBmB,IAAI2E,iBAjBG,CAACC,EAActB,KACrCsB,EAAarB,QAASsB,IAEe,IAA/BA,EAASC,WAAWjC,aAGYC,IAAhC+B,EAASC,WAAW,GAAGC,OAGuC,GAA9DF,EAASC,WAAW,GAAGC,KAAKC,OAAO,wBACrCH,EAASC,WAAWvB,QAAS0B,IAC3B/E,SAASuC,eAAe,wBAAwBpB,OAAO4D,SAQtDd,QAAQjE,SAASoE,KADX,CAAEY,WAAW","file":"scripts/sphinx-book-theme.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","export default __webpack_public_path__ + \"styles/sphinx-book-theme.css\";","// Import CSS variables\n// ref: https://css-tricks.com/getting-javascript-to-talk-to-css-and-sass/\nimport \"../styles/index.scss\";\n\n/**\n * A helper function to load scripts when the DOM is loaded.\n * This waits for everything to be on the page first before running, since\n * some functionality doesn't behave properly until everything is ready.\n */\nvar sbRunWhenDOMLoaded = (cb) => {\n if (document.readyState != \"loading\") {\n cb();\n } else if (document.addEventListener) {\n document.addEventListener(\"DOMContentLoaded\", cb);\n } else {\n document.attachEvent(\"onreadystatechange\", function () {\n if (document.readyState == \"complete\") cb();\n });\n }\n};\n\n/**\n * Toggle full-screen with button\n *\n * There are some browser-specific hacks in here:\n * - Safari requires a `webkit` prefix, so this uses conditionals to check for that\n * ref: https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n */\nvar toggleFullScreen = () => {\n var isInFullScreen =\n (document.fullscreenElement && document.fullscreenElement !== null) ||\n (document.webkitFullscreenElement &&\n document.webkitFullscreenElement !== null);\n let docElm = document.documentElement;\n if (!isInFullScreen) {\n console.log(\"[SBT]: Entering full screen\");\n if (docElm.requestFullscreen) {\n docElm.requestFullscreen();\n } else if (docElm.webkitRequestFullscreen) {\n docElm.webkitRequestFullscreen();\n }\n } else {\n console.log(\"[SBT]: Exiting full screen\");\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n }\n }\n};\n\n/**\n * Sidebar scroll on load.\n *\n * Detect the active page in the sidebar, and scroll so that it is centered on\n * the screen.\n */\nvar scrollToActive = () => {\n var navbar = document.getElementById(\"site-navigation\");\n var active_pages = navbar.querySelectorAll(\".active\");\n var active_page = active_pages[active_pages.length - 1];\n // Only scroll the navbar if the active link is lower than 50% of the page\n if (\n active_page !== undefined &&\n active_page.offsetTop > $(window).height() * 0.5\n ) {\n navbar.scrollTop = active_page.offsetTop - $(window).height() * 0.2;\n }\n};\n\n/**\n * Called when the \"print to PDF\" button is clicked.\n * This is a hack to prevent tooltips from showing up in the printed PDF.\n */\nvar printPdf = (el) => {\n // Detach the tooltip text from DOM to hide in PDF\n // and then reattach it for HTML\n let tooltipID = $(el).attr(\"aria-describedby\");\n let tooltipTextDiv = $(\"#\" + tooltipID).detach();\n window.print();\n $(\"body\").append(tooltipTextDiv);\n};\n\n/**\n * Manage scrolling behavior. This is primarily two things:\n *\n * 1. Hide the Table of Contents any time sidebar content is on the screen.\n *\n * This will be triggered any time a sidebar item enters or exits the screen.\n * It adds/removes items from an array if they have entered the screen, and\n * removes them when they exit the screen. It hides the TOC if anything is\n * on-screen.\n *\n * ref: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API\n *\n * 2. Add a `scrolled` class to to trigger CSS changes.\n */\nvar initTocHide = () => {\n var onScreenItems = [];\n let hideTocCallback = (entries, observer) => {\n // Check whether any sidebar item is displayed\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n // If an element just came on screen, add it our list\n onScreenItems.push(entry.target);\n } else {\n // Otherwise, if it's in our list then remove it\n for (let ii = 0; ii < onScreenItems.length; ii++) {\n if (onScreenItems[ii] === entry.target) {\n onScreenItems.splice(ii, 1);\n break;\n }\n }\n }\n });\n\n // Hide the TOC if any margin content is displayed on the screen\n if (onScreenItems.length > 0) {\n $(\"div.bd-toc\").removeClass(\"show\");\n } else {\n $(\"div.bd-toc\").addClass(\"show\");\n }\n };\n let manageScrolledClassOnBody = (entries, observer) => {\n // The pixel is at the top, so if we're < 0 that it means we've scrolled\n if (entries[0].boundingClientRect.y < 0) {\n document.body.classList.add(\"scrolled\");\n } else {\n document.body.classList.remove(\"scrolled\");\n }\n };\n\n // Set up the intersection observer to watch all margin content\n let tocObserver = new IntersectionObserver(hideTocCallback);\n // TODO: deprecate popout after v0.5.0\n const selectorClasses = [\n \"marginnote\",\n \"sidenote\",\n \"margin\",\n \"margin-caption\",\n \"full-width\",\n \"sidebar\",\n \"popout\",\n ];\n let marginSelector = [];\n selectorClasses.forEach((ii) => {\n // Use three permutations of each class name because `tag_` and `_` used to be supported\n marginSelector.push(\n ...[\n `.${ii}`,\n `.tag_${ii}`,\n `.${ii.replace(\"-\", \"_\")}`,\n `.tag_${ii.replace(\"-\", \"_\")}`,\n ]\n );\n });\n document.querySelectorAll(marginSelector.join(\", \")).forEach((ii) => {\n tocObserver.observe(ii);\n });\n\n // Set up the observer to check if we've scrolled from top of page\n let scrollObserver = new IntersectionObserver(manageScrolledClassOnBody);\n scrollObserver.observe(document.querySelector(\".sbt-scroll-pixel-helper\"));\n};\n\n/**\n * Activate Thebe with a custom button click.\n */\nvar initThebeSBT = () => {\n var title = $(\"div.section h1\")[0];\n if (!$(title).next().hasClass(\"thebe-launch-button\")) {\n $(\"\").insertAfter($(title));\n }\n initThebe();\n};\n\n/**\n * Use Bootstrap helper function to enable tooltips.\n */\nvar initTooltips = () => {\n $(document).ready(function () {\n $('[data-toggle=\"tooltip\"]').tooltip({\n trigger: \"hover\",\n delay: { show: 500, hide: 100 },\n });\n });\n};\n\n/**\n * MutationObserver to move the ReadTheDocs button\n */\nfunction initRTDObserver() {\n const mutatedCallback = (mutationList, observer) => {\n mutationList.forEach((mutation) => {\n // Check whether the mutation is for RTD, which will have a specific structure\n if (mutation.addedNodes.length === 0) {\n return;\n }\n if (mutation.addedNodes[0].data === undefined) {\n return;\n }\n if (mutation.addedNodes[0].data.search(\"Inserted RTD Footer\") != -1) {\n mutation.addedNodes.forEach((node) => {\n document.getElementById(\"rtd-footer-container\").append(node);\n });\n }\n });\n };\n\n const observer = new MutationObserver(mutatedCallback);\n const config = { childList: true };\n observer.observe(document.body, config);\n}\n\n/**\n * Set up callback functions for UI click actions\n */\nwindow.initThebeSBT = initThebeSBT;\nwindow.printPdf = printPdf;\nwindow.toggleFullScreen = toggleFullScreen;\n\n/**\n * Set up functions to load when the DOM is ready\n */\nsbRunWhenDOMLoaded(initTooltips);\nsbRunWhenDOMLoaded(scrollToActive);\nsbRunWhenDOMLoaded(initTocHide);\nsbRunWhenDOMLoaded(initRTDObserver);\n"],"sourceRoot":""} \ No newline at end of file diff --git a/branch/sphinx-book-theme-old-copybutton/_static/searchtools.js b/branch/sphinx-book-theme-old-copybutton/_static/searchtools.js new file mode 100644 index 00000000..0a44e858 --- /dev/null +++ b/branch/sphinx-book-theme-old-copybutton/_static/searchtools.js @@ -0,0 +1,525 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +if (!Scorer) { + /** + * Simple result scoring code. + */ + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2 + }; +} + +if (!splitQuery) { + function splitQuery(query) { + return query.split(/\s+/); + } +} + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + htmlToText : function(htmlString) { + var virtualDocument = document.implementation.createHTMLDocument('virtual'); + var htmlElement = $(htmlString, virtualDocument); + htmlElement.find('.headerlink').remove(); + docContent = htmlElement.find('[role=main]')[0]; + if(docContent === undefined) { + console.warn("Content block not found. Sphinx search tries to obtain it " + + "via '[role=main]'. Could you check your theme or template."); + return ""; + } + return docContent.textContent || docContent.innerText; + }, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

 

').appendTo(this.out); + this.output = $('