!
189 | > >docker@2a99ffabb512:~/data$
190 | > >~~~
191 | > >{: .output}
192 | > `$USER` is evaluated and then overrides the default `CMD` to be passed to `entrypoint.sh`
193 | > {: .solution}
194 | {: .challenge}
195 |
196 | [docker-docs-CMD]: https://docs.docker.com/engine/reference/builder/#cmd
197 | [docker-docs-ENTRYPOINT]: https://docs.docker.com/engine/reference/builder/#entrypoint
198 |
199 | {% include links.md %}
200 |
--------------------------------------------------------------------------------
/_episodes/10-challenge-examples.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Challenge Examples"
3 | teaching: 0
4 | exercises: 20
5 | questions:
6 | - "How to do a few more things?"
7 | objectives:
8 | - "How to run with SSH and not use `cp`"
9 | keypoints:
10 | - "Containers are extensive"
11 | ---
12 |
13 | > ## Get SSH credentials in a container without `cp`
14 | >
15 | > Get SSH credentials inside a container without using `cp`
16 | >
17 | > > ## Solution
18 | > >
19 | > > Mount multiple volumes
20 | > >~~~
21 | > >docker run --rm -it \
22 | > > -w /home/atlas/Bootcamp \
23 | > > -v $PWD:/home/atlas/Bootcamp \
24 | > > -v $HOME/.ssh:/home/atlas/.ssh \
25 | > > -v $HOME/.gitconfig:/home/atlas/.gitconfig \
26 | > > atlas/analysisbase:21.2.85-centos7
27 | > >~~~
28 | > >{: .source}
29 | > {: .solution}
30 | {: .challenge}
31 |
32 | {% include links.md %}
33 |
--------------------------------------------------------------------------------
/_episodes_rmd/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/_episodes_rmd/.gitkeep
--------------------------------------------------------------------------------
/_episodes_rmd/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/_episodes_rmd/data/.gitkeep
--------------------------------------------------------------------------------
/_extras/discuss.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Discussion
3 | ---
4 |
5 | Readers may be interested in:
6 |
7 | * The [official Docker docs](https://docs.docker.com/).
8 | * Pretty good YouTube videos on the basic concepts of containers: [Docker in 100 Seconds](https://youtu.be/Gjnup-PuquQ) and [Learn Docker in 7 Easy Steps - Full Beginner's Tutorial](https://youtu.be/gAkwW2tuIqE) by Fireship.
9 |
10 | {% include links.md %}
11 |
--------------------------------------------------------------------------------
/_extras/guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Instructor Notes"
3 | ---
4 |
5 | The instructor notes should provide additional discussion useful to instructors,
6 | but not appropriate for inclusion in the main lessons. The following structure
7 | provides a consistent way for instructors to both prepare for a workshop and
8 | quickly find necessary information during a workshop.
9 |
10 | Please remember not to overload on details, and to keep the comments here positive!
11 |
12 | ## Lesson motivation and learning objectives
13 |
14 | These concepts should be highlighted in the main lesson material, but ideas for
15 | explaining these concepts further can be placed here.
16 |
17 | ## Lesson design
18 |
19 | Most lessons contain more material than can be taught in a single workshop.
20 | Describe a general narrative (with time estimates) for teaching either a half day
21 | or full day with this lesson material. You may also choose to include multiple
22 | options for lesson design, or what material can be skipped while teaching.
23 | This section may also include recommendations for how this lesson fits into
24 | the overall workshop.
25 |
26 | ## Technical tips and tricks
27 |
28 | Provide information on setting up your environment for learners to view your
29 | live coding (increasing text size, changing text color, etc), as well as
30 | general recommendations for working with coding tools to best suit the
31 | learning environment.
32 |
33 | ## Common problems
34 |
35 | This can include answers to common learner questions, as well as links to
36 | resources (blog posts, stack overflow answers, etc) that may solve problems that
37 | may occur during a workshop.
38 |
--------------------------------------------------------------------------------
/_includes/aio-script.md:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | As a maintainer, you don't need to edit this file.
3 | If you notice that something doesn't work, please
4 | open an issue: https://github.com/carpentries/styles/issues/new
5 | {% endcomment %}
6 |
7 | {% include manual_episode_order.html %}
8 |
9 | {% for lesson_episode in lesson_episodes %}
10 |
11 | {% if site.episode_order %}
12 | {% assign e = site.episodes | where: "slug", lesson_episode | first %}
13 | {% else %}
14 | {% assign e = lesson_episode %}
15 | {% endif %}
16 |
17 | {{ e.title }}
18 |
19 | {% include episode_overview.html teaching_time=e.teaching exercise_time=e.exercises episode_questions=e.questions episode_objectives=e.objectives %}
20 |
21 | {{ e.content }}
22 |
23 | {% include episode_keypoints.html episode_keypoints=e.keypoints %}
24 |
25 | {% endfor %}
26 |
--------------------------------------------------------------------------------
/_includes/all_keypoints.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display key points of all episodes for reference.
3 | {% endcomment %}
4 |
5 | {% include base_path.html %}
6 | {% include manual_episode_order.html %}
7 |
8 | Key Points
9 |
10 | {% for lesson_episode in lesson_episodes %}
11 | {% if site.episode_order %}
12 | {% assign episode = site.episodes | where: "slug", lesson_episode | first %}
13 | {% else %}
14 | {% assign episode = lesson_episode %}
15 | {% endif %}
16 | {% unless episode.break %}
17 |
18 |
19 | {{ episode.title }}
20 |
21 |
22 |
23 | {% for keypoint in episode.keypoints %}
24 | {{ keypoint|markdownify }}
25 | {% endfor %}
26 |
27 |
28 |
29 | {% endunless %}
30 | {% endfor %}
31 |
32 |
--------------------------------------------------------------------------------
/_includes/base_path.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | This is adapted from: https://ricostacruz.com/til/relative-paths-in-jekyll
3 |
4 | `page.url` gives the URL of the current page with a leading /:
5 |
6 | - when the URL ends with the extension (e.g., /foo/bar.html) then we can get
7 | the depth by counting the number of / and remove - 1
8 | - when the URL ends with a / (e.g. /foo/bar/) then the number / gives the depth
9 | directly
10 | {% endcomment %}
11 |
12 | {% assign relative_root_path = '' %}
13 |
14 | {% assign last_char = page.url | slice: -1 %}
15 |
16 | {% if last_char == "/"}
17 | {% assign offset = 0 %}
18 | {% else %}
19 | {% assign offset = 1 %}
20 | {% endif %}
21 |
22 | {% assign depth = page.url | split: '/' | size | minus: offset %}
23 | {% if depth <= 1 %}{% assign relative_root_path = '.' %}
24 | {% elsif depth == 2 %}{% assign relative_root_path = '..' %}
25 | {% elsif depth == 3 %}{% assign relative_root_path = '../..' %}
26 | {% elsif depth == 4 %}{% assign relative_root_path = '../../..' %}
27 | {% endif %}
28 |
--------------------------------------------------------------------------------
/_includes/carpentries.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | General description of Software, Data, and Library Carpentry.
3 | {% endcomment %}
4 |
5 | {% include base_path.html %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
The Carpentries comprises
13 | Software Carpentry, Data Carpentry, and Library Carpentry communities of Instructors, Trainers,
14 | Maintainers, helpers, and supporters who share a mission to teach
15 | foundational coding and data science skills to researchers and people
16 | working in library- and information-related roles. In January,
17 | 2018, The Carpentries was formed by the merger of Software Carpentry and
18 | Data Carpentry. Library Carpentry became an official Carpentries Lesson Program in November 2018.
19 |
20 |
While individual lessons and workshops continue to be run under each
21 | lesson project, The Carpentries provide overall staffing and governance, as
22 | well as support for assessment, instructor training and mentoring.
23 | Memberships are joint, and the Carpentries project maintains a shared Code
24 | of Conduct. The Carpentries is a fiscally sponsored project of Community
25 | Initiatives, a registered 501(c)3 non-profit based in California, USA.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Since 1998, Software Carpentry has
34 | been teaching researchers across all disciplines the foundational coding
35 | skills they need to get more done in less time and with less pain. Its
36 | volunteer instructors have run hundreds of events for thousands of learners
37 | around the world. Now that all research involves some degree of
38 | computational work, whether with big data, cloud computing, or simple task
39 | automation, these skills are needed more than ever.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
Data Carpentry develops and teaches
49 | workshops on the fundamental data skills needed to conduct research. Its
50 | target audience is researchers who have little to no prior computational
51 | experience, and its lessons are domain specific, building on learners'
52 | existing knowledge to enable them to quickly apply skills learned to their
53 | own research. Data Carpentry workshops take researchers through the entire
54 | data life cycle.
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
Library Carpentry develops lessons and
64 | teaches workshops for and with people working in library- and
65 | information-related roles. Its goal is to create an on-ramp to empower this
66 | community to use software and data in their own work, as well as be
67 | advocates for and train others in efficient, effective and reproducible data
68 | and software practices.
69 |
70 |
71 |
--------------------------------------------------------------------------------
/_includes/dc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Data Carpentry
3 | aims to help researchers get their work done
4 | in less time and with less pain
5 | by teaching them basic research computing skills.
6 | This hands-on workshop will cover basic concepts and tools,
7 | including program design, version control, data management,
8 | and task automation.
9 | Participants will be encouraged to help one another
10 | and to apply what they have learned to their own research problems.
11 |
12 |
13 |
14 | For more information on what we teach and why,
15 | please see our paper
16 | "Best Practices for Scientific Computing ".
17 |
18 |
19 |
--------------------------------------------------------------------------------
/_includes/dc/schedule.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Day 1
4 |
5 | 09:00 Automating tasks with the Unix shell
6 | 10:30 Coffee
7 | 12:00 Lunch break
8 | 13:00 Building programs with Python
9 | 14:30 Coffee
10 | 16:00 Wrap-up
11 |
12 |
13 |
14 |
Day 2
15 |
16 | 09:00 Version control with Git
17 | 10:30 Coffee
18 | 12:00 Lunch break
19 | 13:00 Managing data with SQL
20 | 14:30 Coffee
21 | 16:00 Wrap-up
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/_includes/dc/syllabus.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
The Unix Shell
4 |
5 | Files and directories
6 | History and tab completion
7 | Pipes and redirection
8 | Looping over files
9 | Creating and running shell scripts
10 | Finding things
11 | Reference...
12 |
13 |
14 |
15 |
Programming in Python
16 |
17 | Using libraries
18 | Working with arrays
19 | Reading and plotting data
20 | Creating and using functions
21 | Loops and conditionals
22 | Defensive programming
23 | Using Python from the command line
24 | Reference...
25 |
26 |
27 |
40 |
53 |
54 |
55 |
56 |
57 |
Version Control with Git
58 |
59 | Creating a repository
60 | Recording changes to files: add
, commit
, ...
61 | Viewing changes: status
, diff
, ...
62 | Ignoring files
63 | Working on the web: clone
, pull
, push
, ...
64 | Resolving conflicts
65 | Open licenses
66 | Where to host work, and why
67 | Reference...
68 |
69 |
70 |
86 |
87 |
Open Refine
88 |
89 | Introduction to OpenRefine
90 | Importing data
91 | Basic functions
92 | Advanced Functions
93 | Reference...
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/_includes/dc/who.html:
--------------------------------------------------------------------------------
1 |
2 | Who:
3 | The course is aimed at graduate students and other researchers.
4 |
5 | You don't need to have any previous knowledge of the tools
6 | that will be presented at the workshop.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/_includes/episode_break.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display a break's timings in a box similar to a learning episode's.
3 | {% endcomment %}
4 |
5 | Overview
6 |
7 |
8 |
9 | Break: {{ page.break }} min
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/_includes/episode_keypoints.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display key points for an episode.
3 | {% endcomment %}
4 |
5 | {% if page.keypoints == nil %}
6 | {% assign episode_keypoints = include.episode_keypoints %}
7 | {% else %}
8 | {% assign episode_keypoints = page.keypoints %}
9 | {% endif %}
10 |
11 |
12 | Key Points
13 |
14 | {% for keypoint in episode_keypoints %}
15 | {{ keypoint|markdownify }}
16 | {% endfor %}
17 |
18 |
19 |
--------------------------------------------------------------------------------
/_includes/episode_navbar.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | For some reason, the relative_root_path seems out of scope in this file, so we
3 | need to re-assign it here
4 | {% endcomment %}
5 |
6 | {% include base_path.html %}
7 |
8 | {% comment %}
9 | Navigation bar for an episode.
10 | {% endcomment %}
11 |
12 | {% include manual_episode_order.html %}
13 | {% comment %}
14 | 'previous_episode' and 'next_episodes' are defined in 'manual_episode_order.html'.
15 | These replace 'page.previous' and 'page.next' objects, correspondingly.
16 | {% endcomment %}
17 |
18 |
19 |
28 |
29 | {% if include.episode_navbar_title %}
30 |
31 | {% endif %}
32 |
33 |
42 |
43 |
--------------------------------------------------------------------------------
/_includes/episode_overview.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display episode's timings and learning objectives.
3 |
4 | Regarding the `if page.*** == nil` below:
5 | all-in-one page combines all episodes into one.
6 | It, therefore, does not define its own objectives, exercises,
7 | and questions, which 'normal' episodes define in the front matter.
8 |
9 | To display episodes' teaching and exercise times, as well as episode
10 | questions and objectives, we pass them as parameters to the Liquid's
11 | `include` statement when we generate the page:
12 |
13 | include episode_overview.html teaching_time=e.teaching ...
14 |
15 | Here we obtain the information we need either from the episode itself or
16 | from the parameters passed in.
17 | {% endcomment %}
18 |
19 | {% if page.teaching == nil %}
20 | {% assign teaching_time = include.teaching_time %}
21 | {% else %}
22 | {% assign teaching_time = page.teaching %}
23 | {% endif %}
24 |
25 | {% if page.exercises == nil %}
26 | {% assign exercise_time = include.exercise_time %}
27 | {% else %}
28 | {% assign exercise_time = page.exercises %}
29 | {% endif %}
30 |
31 | {% if page.questions == nil %}
32 | {% assign episode_questions = include.episode_questions %}
33 | {% else %}
34 | {% assign episode_questions = page.questions %}
35 | {% endif %}
36 |
37 | {% if page.objectives == nil %}
38 | {% assign episode_objectives = include.episode_objectives %}
39 | {% else %}
40 | {% assign episode_objectives = page.objectives %}
41 | {% endif %}
42 |
43 |
44 |
45 | Overview
46 |
47 |
48 |
49 | Teaching: {{ teaching_time }} min
50 |
51 | Exercises: {{ exercise_time }} min
52 |
53 |
54 |
Questions
55 |
56 | {% for question in episode_questions %}
57 | {{ question|markdownify }}
58 | {% endfor %}
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Objectives
68 |
69 | {% for objective in episode_objectives %}
70 | {{ objective|markdownify }}
71 | {% endfor %}
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/_includes/episode_title.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ page.title }}
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/_includes/favicons.html:
--------------------------------------------------------------------------------
1 | {% assign favicon_url = relative_root_path | append: '/assets/favicons/' | append: site.carpentry %}
2 |
3 | {% if site.carpentry == 'swc' %}
4 | {% assign carpentry = 'Software Carpentry' %}
5 | {% elsif site.carpentry == 'dc' %}
6 | {% assign carpentry = 'Data Carpentry' %}
7 | {% elsif site.carpentry == 'lc' %}
8 | {% assign carpentry = 'Library Carpentry' %}
9 | {% elsif site.carpentry == 'cp' %}
10 | {% assign carpentry = 'The Carpentries' %}
11 | {% endif %}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/_includes/gh_variables.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | When rendering websites locally, `site.github.url` doesn't get resolved properly
3 | unless a GitHub Personal Access Token is set up and available in the
4 | environment. This leads to warnings and errors when trying to serve the site
5 | locally. To work around this, we use the `jekyll.environment` variable which is
6 | set to `development` when rendering the site locally, and set to `production` on
7 | GitHub where `site.github.url` is defined.
8 | {% endcomment %}
9 |
10 | {% if jekyll.environment == "production" %}
11 |
12 | {% comment %}
13 | First, get the name of the repository
14 | {% endcomment %}
15 | {% assign repo_name = site.github.repository_name %}
16 |
17 | {% comment %}
18 | `site.github.public_repositories` contains comprehensive information for all public repositories for the organization. We use `where` to extract the part
19 | of the metadata that is relevant to the present repository.
20 | {% endcomment %}
21 | {% assign repo_info = site.github.public_repositories | where: "name", repo_name %}
22 |
23 | {% comment %}
24 | Now, we can extract the default branch for the repo
25 | {% endcomment %}
26 | {% assign default_branch = repo_info[0].default_branch %}
27 |
28 | {% comment %}
29 | Other variables requested by the template
30 | {% endcomment %}
31 | {% assign repo_url = site.github.repository_url %}
32 | {% assign search_domain_url = site.github.url %}
33 | {% assign project_title = site.github.project_title %}
34 | {% assign source_branch = site.github.source.branch %}
35 |
36 | {% elsif jekyll.environment == "development" %}
37 |
38 | {% assign repo_name = "" %}
39 | {% assign repo_url = "" %}
40 | {% assign default_branch = "" %}
41 | {% assign search_domain_url = "" %}
42 | {% assign project_title = "" %}
43 | {% assign source_branch = "" %}
44 |
45 | {% endif %}
46 |
--------------------------------------------------------------------------------
/_includes/javascript.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | JavaScript used in lesson and workshop pages.
3 | {% endcomment %}
4 |
5 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/_includes/lc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Library Carpentry
3 | is made by people working in library- and information-related roles to help you:
4 |
5 |
6 | automate repetitive, boring, error-prone tasks
7 | create, maintain and analyze sustainable and reusable data
8 | work effectively with IT and systems colleagues
9 | better understand the use of software in research
10 | and much more...
11 |
12 |
13 |
14 | Library Carpentry introduces you to the fundamentals of computing
15 | and provides you with a platform for further self-directed learning.
16 | For more information on what we teach and why, please see our paper
17 | "Library Carpentry: software skills training for library professionals ".
18 |
19 |
20 |
--------------------------------------------------------------------------------
/_includes/lc/schedule.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Day 1
4 |
5 | 09:00 Data Intro for Librarians
6 | 10:30 Coffee
7 | 12:00 Lunch break
8 | 13:00 Shell Lessons for Libraries
9 | 14:30 Coffee
10 | 16:00 Wrap-up
11 |
12 |
13 |
14 |
Day 2
15 |
16 | 09:00 Git Intro for Librarians
17 | 10:30 Coffee
18 | 12:00 Lunch break
19 | 13:00 OpenRefine for Librarians
20 | 14:30 Coffee
21 | 16:00 Wrap-up
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/_includes/lc/syllabus.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Data Intro
4 |
5 | Intro to data
6 | Jargon busting
7 | Keyboard shortcuts
8 | Plain text formats
9 | Naming files
10 | Regular expressions
11 | Reference...
12 |
13 |
14 |
15 |
The Unix Shell
16 |
17 | Files and directories
18 | History and tab completion
19 | Counting and sorting contents in files
20 | Pipes and redirection
21 | Mining or searching in files
22 | Reference...
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
Version Control with Git
31 |
32 | Creating a repository
33 | Configuring git
34 | Recording changes to files: add
, commit
, ...
35 | Viewing state changes with status
36 | Working on the web: clone
, pull
, push
, ...
37 | Where to host work, and why
38 | Reference...
39 |
40 |
41 |
42 |
43 |
Open Refine
44 |
45 | Introduction to OpenRefine
46 | Importing data
47 | Basic functions
48 | Advanced Functions
49 | Reference...
50 |
51 |
52 |
53 |
54 |
70 |
--------------------------------------------------------------------------------
/_includes/lc/who.html:
--------------------------------------------------------------------------------
1 |
2 | Who:
3 | The course is for people working in library- and information-related roles.
4 |
5 | You don't need to have any previous knowledge of the tools that
6 | will be presented at the workshop.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/_includes/lesson_footer.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Footer for lesson pages.
3 | {% endcomment %}
4 |
5 | {% include gh_variables.html %}
6 |
7 |
55 |
--------------------------------------------------------------------------------
/_includes/life_cycle.html:
--------------------------------------------------------------------------------
1 |
2 | {% if site.life_cycle == "pre-alpha" %}
3 |
4 |
5 |
6 | This lesson is still being designed and assembled (Pre-Alpha version)
7 |
8 |
9 |
10 |
11 | {% elsif site.life_cycle == "alpha" %}
12 |
13 |
14 |
15 | This lesson is in the early stages of development (Alpha version)
16 |
17 |
18 |
19 |
20 | {% elsif site.life_cycle == "beta" %}
21 |
22 |
23 |
24 | This lesson is being piloted (Beta version)
25 |
26 |
27 |
28 | {% elsif site.life_cycle == "stable" %}
29 |
30 | {% comment %}
31 | We don't do anything special for now
32 | {% endcomment %}
33 |
34 | {% endif %}
35 |
--------------------------------------------------------------------------------
/_includes/links.md:
--------------------------------------------------------------------------------
1 | {% include base_path.html %}
2 | [cc-by-human]: https://creativecommons.org/licenses/by/4.0/
3 | [cc-by-legal]: https://creativecommons.org/licenses/by/4.0/legalcode
4 | [ci]: http://communityin.org/
5 | [coc-reporting]: https://docs.carpentries.org/topic_folders/policies/incident-reporting.html
6 | [coc]: https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html
7 | [concept-maps]: https://carpentries.github.io/instructor-training/05-memory/
8 | [contrib-covenant]: https://contributor-covenant.org/
9 | [contributing]: {{ repo_url }}/blob/{{ source_branch }}/CONTRIBUTING.md
10 | [cran-checkpoint]: https://cran.r-project.org/package=checkpoint
11 | [cran-knitr]: https://cran.r-project.org/package=knitr
12 | [cran-stringr]: https://cran.r-project.org/package=stringr
13 | [dc-lessons]: http://www.datacarpentry.org/lessons/
14 | [email]: mailto:team@carpentries.org
15 | [github-importer]: https://import.github.com/
16 | [importer]: https://github.com/new/import
17 | [jekyll-collection]: https://jekyllrb.com/docs/collections/
18 | [jekyll-install]: https://jekyllrb.com/docs/installation/
19 | [jekyll-windows]: http://jekyll-windows.juthilo.com/
20 | [jekyll]: https://jekyllrb.com/
21 | [jupyter]: https://jupyter.org/
22 | [kramdown]: https://kramdown.gettalong.org/
23 | [lc-lessons]: https://librarycarpentry.org/lessons/
24 | [lesson-aio]: {{ relative_root_path }}{% link aio.md %}
25 | [lesson-coc]: {{ relative_root_path }}{% link CODE_OF_CONDUCT.md %}
26 | [lesson-example]: https://carpentries.github.io/lesson-example/
27 | [lesson-license]: {{ relative_root_path }}{% link LICENSE.md %}
28 | [lesson-mainpage]: {{ relative_root_path }}{% link index.md %}
29 | [lesson-reference]: {{ relative_root_path }}{% link reference.md %}
30 | [lesson-setup]: {{ relative_root_path }}{% link setup.md %}
31 | [mit-license]: https://opensource.org/licenses/mit-license.html
32 | [morea]: https://morea-framework.github.io/
33 | [numfocus]: https://numfocus.org/
34 | [osi]: https://opensource.org
35 | [pandoc]: https://pandoc.org/
36 | [paper-now]: https://github.com/PeerJ/paper-now
37 | [python-gapminder]: https://swcarpentry.github.io/python-novice-gapminder/
38 | [pyyaml]: https://pypi.org/project/PyYAML/
39 | [r-markdown]: https://rmarkdown.rstudio.com/
40 | [rstudio]: https://www.rstudio.com/
41 | [ruby-install-guide]: https://www.ruby-lang.org/en/downloads/
42 | [ruby-installer]: https://rubyinstaller.org/
43 | [rubygems]: https://rubygems.org/pages/download/
44 | [styles]: https://github.com/carpentries/styles/
45 | [swc-lessons]: https://software-carpentry.org/lessons/
46 | [swc-releases]: https://github.com/swcarpentry/swc-releases
47 | [training]: https://carpentries.github.io/instructor-training/
48 | [workshop-repo]: {{ site.workshop_repo }}
49 | [yaml]: http://yaml.org/
50 |
--------------------------------------------------------------------------------
/_includes/main_title.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Main title for lesson pages.
3 | {% endcomment %}
4 |
5 | {% include base_path.html %}
6 |
7 | {% if site.kind == "lesson" %}
8 | {{ site.title }} {% if page.title %}: {{ page.title }}{% endif %}
9 |
10 | {% else %}
11 |
12 | {{ page.title }}
13 |
14 | {% endif %}
15 |
--------------------------------------------------------------------------------
/_includes/manual_episode_order.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | This file enables manual episode ordering until
3 | GitHub Pages switches to Jekyll that supports it
4 | without any major hackery. Note, some logic will
5 | be required even when this transition happens
6 | but it won't be as involved as what we have to do
7 | in this file.
8 |
9 | To order lesson episodes or extras manually
10 | (instead of the default alpha-numerical order),
11 | create array variables 'episode_order' and
12 | 'extras_order' in `_config.yml` like so:
13 |
14 | episode_order:
15 | - episodeA
16 | - episodeB
17 |
18 | extras_order:
19 | - extraA
20 | - extraB
21 |
22 | Note that "Reference" page is currently always
23 | added to "Extras" as the first item.
24 |
25 | The main outcomes of the code in this file are:
26 | - 'lesson_episodes' variable that replaces
27 | 'site.episodes' variable when manual episode
28 | order is defined.
29 | - 'lesson_extras' variable that replaces
30 | 'site.extras' variable when manual ordering of
31 | files in '_extras' is used
32 | - 'previous_episode' and 'next_episode' objects
33 | that replace 'page.previous' and 'page.next' variables,
34 | correspondingly, and that have such properties
35 | as 'url' and 'title' and that are used in
36 | 'episode_navbar.html'.
37 |
38 | When episode order is specified manually, the 'lesson_episodes'
39 | variable contains a list of episode names ("slugs", to be precise;
40 | "slug" is the episode name without '.md'). Therefore, when we
41 | iterate over 'lesson_episodes' (in syllabus.html and navbar.html) ,
42 | we have to check whether we use manual episode ordering and, if so,
43 | find the corresponding episode object. This is what we do with the
44 | following code in every loop over 'lesson_episodes':
45 |
46 | {% if site.episode_order %}
47 | {% assign episode = site.episodes | where: "slug", lesson_episode | first %}
48 | {% else %}
49 | {% assign episode = lesson_episode %}
50 | {% endif %}
51 | {% endcomment %}
52 |
53 | {% comment %}
54 | Manual ordering of Episodes begins here
55 | {% endcomment %}
56 |
57 | {% if site.episode_order %}
58 | {% assign lesson_episodes = site.episode_order %}
59 | {% else %}
60 | {% assign lesson_episodes = site.episodes %}
61 | {% endif %}
62 |
63 |
64 | {% comment %}
65 | If 'episode_order' is defined, we need to determine
66 | - previous episode object ('previous_episode')
67 | - and next episode object ('next_episode')
68 | {% endcomment %}
69 |
70 |
71 | {% if site.episode_order %}
72 | {% for lesson_episode in lesson_episodes %}
73 |
74 | {% comment %}
75 | We iterate over the specified lesson episodes using
76 | a 'for' loop because we can use
77 | 'forloop.first', 'forloop.last', and 'forloop.index0'.
78 | {% endcomment %}
79 |
80 | {% unless lesson_episode == page.slug %} {% continue %} {% endunless %}
81 |
82 | {% if forloop.first %}
83 | {% assign previous_episode = nil %}
84 | {% else %}
85 | {% assign p_idx = forloop.index0 | minus: 1 %}
86 | {% assign p_name = lesson_episodes[p_idx] %}
87 | {% assign previous_episode = site.episodes | where: "slug", p_name | first %}
88 | {% endif %}
89 |
90 | {% if forloop.last == true %}
91 | {% assign next_episode = nil %}
92 | {% else %}
93 | {% assign n_idx = forloop.index0 | plus: 1 %}
94 | {% assign n_name = lesson_episodes[n_idx] %}
95 | {% assign next_episode = site.episodes | where: "slug", n_name | first %}
96 | {% endif %}
97 | {% endfor %}
98 | {% else %}
99 | {% assign previous_episode = page.previous %}
100 | {% assign next_episode = page.next %}
101 | {% endif %}
102 |
103 |
104 | {% comment %}
105 | Manual ordering of Extras begins here
106 | {% endcomment %}
107 |
108 | {% if site.extras_order %}
109 | {% assign lesson_extras = site.extras_order %}
110 | {% else %}
111 | {% assign lesson_extras = site.extras %}
112 | {% endif %}
113 |
114 | {% comment %}
115 | We do not need to determine "previous" or "next" extra.
116 | {% endcomment %}
117 |
--------------------------------------------------------------------------------
/_includes/navbar.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Lesson navigation bar.
3 | {% endcomment %}
4 |
5 | {% include gh_variables.html %}
6 | {% include manual_episode_order.html %}
7 |
8 |
9 |
10 |
41 |
42 |
43 |
44 | {% comment %} Always show code of conduct. {% endcomment %}
45 | Code of Conduct
46 |
47 | {% if site.kind == "lesson" %}
48 | {% comment %} Show setup instructions. {% endcomment %}
49 | Setup
50 |
51 | {% comment %} Show lesson episodes for lessons. {% endcomment %}
52 | {% if lesson_episodes.size > 0 %}
53 |
54 | Episodes
55 |
67 |
68 | {% endif %}
69 | {% endif %}
70 |
71 | {% comment %} Show extras for lessons or if this is the main workshop-template repo (where they contain documentation). {% endcomment %}
72 | {% if site.kind == "lesson" %}
73 |
74 | Extras
75 |
86 |
87 | {% endif %}
88 |
89 | {% comment %} Always show license. {% endcomment %}
90 | License
91 | {% if page.source %}
92 | {% if page.source == "Rmd" %}
93 | Improve this page
94 | {% endif %}
95 | {% else %}
96 | Improve this page
97 | {% endif %}
98 |
99 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/_includes/sc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Software Carpentry
3 | aims to help researchers get their work done
4 | in less time and with less pain
5 | by teaching them basic research computing skills.
6 | This hands-on workshop will cover basic concepts and tools,
7 | including program design, version control, data management,
8 | and task automation.
9 | Participants will be encouraged to help one another
10 | and to apply what they have learned to their own research problems.
11 |
12 |
13 |
14 | For more information on what we teach and why,
15 | please see our paper
16 | "Best Practices for Scientific Computing ".
17 |
18 |
19 |
--------------------------------------------------------------------------------
/_includes/sc/schedule.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Day 1
4 |
5 | 09:00 Automating tasks with the Unix shell
6 | 10:30 Coffee
7 | 12:00 Lunch break
8 | 13:00 Building programs with Python
9 | 14:30 Coffee
10 | 16:00 Wrap-up
11 |
12 |
13 |
14 |
Day 2
15 |
16 | 09:00 Version control with Git
17 | 10:30 Coffee
18 | 12:00 Lunch break
19 | 13:00 Managing data with SQL
20 | 14:30 Coffee
21 | 16:00 Wrap-up
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/_includes/sc/syllabus.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
The Unix Shell
4 |
5 | Files and directories
6 | History and tab completion
7 | Pipes and redirection
8 | Looping over files
9 | Creating and running shell scripts
10 | Finding things
11 | Reference...
12 |
13 |
14 |
15 |
Programming in Python
16 |
17 | Using libraries
18 | Working with arrays
19 | Reading and plotting data
20 | Creating and using functions
21 | Loops and conditionals
22 | Defensive programming
23 | Using Python from the command line
24 | Reference...
25 |
26 |
27 |
40 |
53 |
54 |
55 |
56 |
57 |
Version Control with Git
58 |
59 | Creating a repository
60 | Recording changes to files: add
, commit
, ...
61 | Viewing changes: status
, diff
, ...
62 | Ignoring files
63 | Working on the web: clone
, pull
, push
, ...
64 | Resolving conflicts
65 | Open licenses
66 | Where to host work, and why
67 | Reference...
68 |
69 |
70 |
86 |
87 |
Open Refine
88 |
89 | Introduction to OpenRefine
90 | Importing data
91 | Basic functions
92 | Advanced Functions
93 | Reference...
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/_includes/sc/who.html:
--------------------------------------------------------------------------------
1 |
2 | Who:
3 | The course is aimed at graduate students and other researchers.
4 |
5 | You don't need to have any previous knowledge of the tools
6 | that will be presented at the workshop.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/_includes/syllabus.html:
--------------------------------------------------------------------------------
1 | {% include base_path.html %}
2 |
3 | {% comment %}
4 | Display syllabus in tabular form.
5 | Days are displayed if at least one episode has 'start = true'.
6 | {% endcomment %}
7 |
8 | {% include manual_episode_order.html %}
9 |
10 |
11 |
Schedule
12 |
13 | {% assign lesson_number = 0 %}
14 | {% assign day = 0 %}
15 | {% assign multiday = false %}
16 | {% for lesson_episode in lesson_episodes %}
17 | {% if site.episode_order %}
18 | {% assign episode = site.episodes | where: "slug", lesson_episode | first %}
19 | {% else %}
20 | {% assign episode = lesson_episode %}
21 | {% endif %}
22 | {% if episode.start %}{% assign multiday = true %}{% break %}{% endif %}
23 | {% endfor %}
24 | {% assign current = site.start_time %}
25 |
26 |
27 |
28 | {% if multiday %} {% endif %}
29 |
30 | Setup
31 | Download files required for the lesson
32 |
33 | {% for lesson_episode in lesson_episodes %}
34 | {% if site.episode_order %}
35 | {% assign episode = site.episodes | where: "slug", lesson_episode | first %}
36 | {% else %}
37 | {% assign episode = lesson_episode %}
38 | {% endif %}
39 | {% if episode.start %} {% comment %} Starting a new day? {% endcomment %}
40 | {% assign day = day | plus: 1 %}
41 | {% if day > 1 %} {% comment %} If about to start day 2 or later, show finishing time for previous day {% endcomment %}
42 | {% assign hours = current | divided_by: 60 %}
43 | {% assign minutes = current | modulo: 60 %}
44 |
45 | {% if multiday %} {% endif %}
46 | {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}
47 | Finish
48 |
49 |
50 | {% endif %}
51 | {% assign current = site.start_time %} {% comment %}Re-set start time of this episode to general daily start time {% endcomment %}
52 | {% endif %}
53 | {% assign hours = current | divided_by: 60 %}
54 | {% assign minutes = current | modulo: 60 %}
55 |
56 | {% if multiday %}{% if episode.start %}Day {{ day }}{% endif %} {% endif %}
57 | {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}
58 |
59 | {% assign lesson_number = lesson_number | plus: 1 %}
60 | {{ lesson_number }}. {{ episode.title }}
61 |
62 |
63 | {% if episode.break %}
64 | Break
65 | {% else %}
66 | {% if episode.questions %}
67 | {% for question in episode.questions %}
68 | {{question|markdownify|strip_html}}
69 | {% unless forloop.last %}
70 |
71 | {% endunless %}
72 | {% endfor %}
73 | {% endif %}
74 | {% endif %}
75 |
76 |
77 | {% assign current = current | plus: episode.teaching | plus: episode.exercises | plus: episode.break %}
78 | {% endfor %}
79 | {% assign hours = current | divided_by: 60 %}
80 | {% assign minutes = current | modulo: 60 %}
81 |
82 | {% if multiday %} {% endif %}
83 | {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}
84 | Finish
85 |
86 |
87 |
88 |
89 |
90 | The actual schedule may vary slightly depending on the topics and exercises chosen by the instructor.
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/_includes/workshop_ad.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Advertising box at the top of a workshop website home page.
3 | {% endcomment %}
4 |
5 |
6 |
7 |
{{page.venue}}
8 |
9 |
10 |
{{page.humandate}}
11 |
{% if page.humantime %}{{page.humantime}}{% endif %}
12 |
13 |
14 |
15 | Instructors:
16 | {% if page.instructor %}
17 | {{page.instructor | join: ', ' %}}
18 | {% else %}
19 | to be announced.
20 | {% endif %}
21 |
22 | {% if page.helper %}
23 |
24 | Helpers:
25 | {{page.helper | join: ', ' %}}
26 |
27 | {% endif %}
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/_includes/workshop_calendar.html:
--------------------------------------------------------------------------------
1 | Add to your Google Calendar.
2 |
--------------------------------------------------------------------------------
/_includes/workshop_footer.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Footer for a standard workshop.
3 | {% endcomment %}
4 |
5 |
6 |
7 |
8 | Copyright © 2016–{{ 'now' | date: "%Y" }}
9 | {% if site.carpentry == "swc" %}
10 | Software Carpentry
11 | {% elsif site.carpentry == "dc" %}
12 | Data Carpentry
13 | {% elsif site.carpentry == "lc" %}
14 | Library Carpentry
15 | {% elsif site.carpentry == "cp" %}
16 | The Carpentries
17 | {% endif %}
18 |
19 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/_layouts/base.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {% include base_path.html %}
4 | {% include gh_variables.html %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {% include favicons.html %}
22 |
23 |
24 |
25 |
29 |
30 |
31 | {% if page.title %}{{ page.title }}{% endif %}{% if page.title and site.title %} – {% endif %}{% if site.title %}{{ site.title }}{% endif %}
32 |
33 |
34 |
35 |
36 |
37 | {% include life_cycle.html %}
38 |
39 |
40 | {% include navbar.html %}
41 | {{ content }}
42 | {% if site.kind == "workshop" %}
43 | {% include workshop_footer.html %}
44 | {% else %}
45 | {% include lesson_footer.html %}
46 | {% endif %}
47 |
48 | {% include javascript.html %}
49 |
50 |
51 |
--------------------------------------------------------------------------------
/_layouts/break.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include episode_navbar.html episode_navbar_title=true %}
5 |
6 | {% include episode_title.html %}
7 | {% include episode_break.html %}
8 | {{content}}
9 |
10 | {% include episode_navbar.html episode_navbar_title=false %}
11 |
--------------------------------------------------------------------------------
/_layouts/episode.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include episode_navbar.html episode_navbar_title=true %}
5 |
6 | {% include episode_title.html %}
7 | {% include episode_overview.html %}
8 | {{content}}
9 | {% include episode_keypoints.html %}
10 |
11 | {% include episode_navbar.html episode_navbar_title=false %}
12 |
--------------------------------------------------------------------------------
/_layouts/lesson.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include main_title.html %}
5 |
6 | {{ content }}
7 |
8 | {% include syllabus.html %}
9 |
--------------------------------------------------------------------------------
/_layouts/page.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include main_title.html %}
5 |
6 | {{content}}
7 |
8 |
--------------------------------------------------------------------------------
/_layouts/reference.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: "Reference"
4 | ---
5 | {% include all_keypoints.html %}
6 | {{content}}
7 |
--------------------------------------------------------------------------------
/_layouts/workshop.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {% include base_path.html %}
4 | {% include gh_variables.html %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 | {% endif %}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | {% include favicons.html %}
38 |
39 |
40 |
41 |
45 | {{ page.venue }}: {{ page.humandate }}
46 |
47 |
48 |
49 | {% include navbar.html %}
50 | {% include workshop_ad.html %}
51 | {{ content }}
52 | {% include workshop_footer.html %}
53 |
54 | {% include javascript.html %}
55 |
56 |
57 |
--------------------------------------------------------------------------------
/aio.md:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: /aio/index.html
3 | ---
4 |
5 | {% comment %}
6 | As a maintainer, you don't need to edit this file.
7 | If you notice that something doesn't work, please
8 | open an issue: https://github.com/carpentries/styles/issues/new
9 | {% endcomment %}
10 |
11 | {% include base_path.html %}
12 |
13 | {% include aio-script.md %}
14 |
--------------------------------------------------------------------------------
/assets/css/syntax.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #f8f8f8; }
3 | .highlight .c { color: #387d7d; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .ch { color: #387d7d; font-style: italic } /* Comment.Hashbang */
8 | .highlight .cm { color: #387d7d; font-style: italic } /* Comment.Multiline */
9 | .highlight .cp { color: #BC7A00 } /* Comment.Preproc */
10 | .highlight .cpf { color: #387d7d; font-style: italic } /* Comment.PreprocFile */
11 | .highlight .c1 { color: #387d7d; font-style: italic } /* Comment.Single */
12 | .highlight .cs { color: #387d7d; font-style: italic } /* Comment.Special */
13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
14 | .highlight .ge { font-style: italic } /* Generic.Emph */
15 | .highlight .gr { color: #FF0000 } /* Generic.Error */
16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
18 | .highlight .go { color: #888888 } /* Generic.Output */
19 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
20 | .highlight .gs { font-weight: bold } /* Generic.Strong */
21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
23 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
24 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
25 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
26 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */
27 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
28 | .highlight .kt { color: #B00040 } /* Keyword.Type */
29 | .highlight .m { color: #666666 } /* Literal.Number */
30 | .highlight .s { color: #BA2121 } /* Literal.String */
31 | .highlight .na { color: #7D9029 } /* Name.Attribute */
32 | .highlight .nb { color: #008000 } /* Name.Builtin */
33 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
34 | .highlight .no { color: #880000 } /* Name.Constant */
35 | .highlight .nd { color: #AA22FF } /* Name.Decorator */
36 | .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
37 | .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
38 | .highlight .nf { color: #0000FF } /* Name.Function */
39 | .highlight .nl { color: #A0A000 } /* Name.Label */
40 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
41 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
42 | .highlight .nv { color: #19177C } /* Name.Variable */
43 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
45 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */
46 | .highlight .mf { color: #666666 } /* Literal.Number.Float */
47 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */
48 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */
49 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */
50 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
51 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
52 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */
53 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
54 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
55 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
56 | .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
57 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
58 | .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
59 | .highlight .sx { color: #008000 } /* Literal.String.Other */
60 | .highlight .sr { color: #BB6688 } /* Literal.String.Regex */
61 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
62 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */
63 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
64 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */
65 | .highlight .vc { color: #19177C } /* Name.Variable.Class */
66 | .highlight .vg { color: #19177C } /* Name.Variable.Global */
67 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */
68 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */
69 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
70 |
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/assets/favicons/cp/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon-128.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon-16x16.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon-196x196.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon-32x32.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon-96x96.png
--------------------------------------------------------------------------------
/assets/favicons/cp/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/favicon.ico
--------------------------------------------------------------------------------
/assets/favicons/cp/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/mstile-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/cp/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/mstile-150x150.png
--------------------------------------------------------------------------------
/assets/favicons/cp/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/mstile-310x150.png
--------------------------------------------------------------------------------
/assets/favicons/cp/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/mstile-310x310.png
--------------------------------------------------------------------------------
/assets/favicons/cp/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/cp/mstile-70x70.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/assets/favicons/dc/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon-128.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon-16x16.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon-196x196.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon-32x32.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon-96x96.png
--------------------------------------------------------------------------------
/assets/favicons/dc/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/favicon.ico
--------------------------------------------------------------------------------
/assets/favicons/dc/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/mstile-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/dc/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/mstile-150x150.png
--------------------------------------------------------------------------------
/assets/favicons/dc/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/mstile-310x150.png
--------------------------------------------------------------------------------
/assets/favicons/dc/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/mstile-310x310.png
--------------------------------------------------------------------------------
/assets/favicons/dc/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/dc/mstile-70x70.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/assets/favicons/lc/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon-128.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon-16x16.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon-196x196.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon-32x32.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon-96x96.png
--------------------------------------------------------------------------------
/assets/favicons/lc/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/favicon.ico
--------------------------------------------------------------------------------
/assets/favicons/lc/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/mstile-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/lc/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/mstile-150x150.png
--------------------------------------------------------------------------------
/assets/favicons/lc/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/mstile-310x150.png
--------------------------------------------------------------------------------
/assets/favicons/lc/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/mstile-310x310.png
--------------------------------------------------------------------------------
/assets/favicons/lc/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/lc/mstile-70x70.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/assets/favicons/swc/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon-128.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon-16x16.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon-196x196.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon-32x32.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon-96x96.png
--------------------------------------------------------------------------------
/assets/favicons/swc/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/favicon.ico
--------------------------------------------------------------------------------
/assets/favicons/swc/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/mstile-144x144.png
--------------------------------------------------------------------------------
/assets/favicons/swc/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/mstile-150x150.png
--------------------------------------------------------------------------------
/assets/favicons/swc/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/mstile-310x150.png
--------------------------------------------------------------------------------
/assets/favicons/swc/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/mstile-310x310.png
--------------------------------------------------------------------------------
/assets/favicons/swc/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/favicons/swc/mstile-70x70.png
--------------------------------------------------------------------------------
/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/assets/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/assets/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/assets/img/cp-logo-blue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/assets/img/dc-icon-black.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
18 |
19 |
21 | image/svg+xml
22 |
24 |
25 |
26 |
27 |
28 |
30 |
54 |
59 |
64 |
69 |
74 |
75 |
--------------------------------------------------------------------------------
/assets/img/dc-logo-black.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
18 |
19 |
21 | image/svg+xml
22 |
24 |
25 |
26 |
27 |
28 |
30 |
54 |
59 |
64 |
69 |
74 |
75 |
--------------------------------------------------------------------------------
/assets/img/lc-icon-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/img/lc-icon-black.png
--------------------------------------------------------------------------------
/assets/img/lc-logo-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/img/lc-logo-black.png
--------------------------------------------------------------------------------
/assets/img/swc-icon-blue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/assets/img/swc-logo-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/img/swc-logo-blue.png
--------------------------------------------------------------------------------
/assets/img/swc-logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/assets/img/swc-logo-white.png
--------------------------------------------------------------------------------
/assets/js/lesson.js:
--------------------------------------------------------------------------------
1 | // Make all tables striped by default.
2 | $("table").addClass("table table-striped");
3 |
4 |
5 | // Handle foldable challenges and solutions (on click and at start).
6 | $(".solution").click(function(event) {
7 | var trigger = $(event.target).has(".fold-unfold").length > 0
8 | || $(event.target).filter(".fold-unfold").length > 0;
9 | if (trigger) {
10 | $(">*:not(h2)", this).toggle(400);
11 | $(">h2>span.fold-unfold", this).toggleClass("glyphicon-collapse-down glyphicon-collapse-up");
12 | event.stopPropagation();
13 | }
14 | });
15 | $(".solution").each(function() {
16 | $(">*:not(h2)", this).toggle();
17 | var h2 = $("h2:first", this);
18 | h2.append(" ");
19 | });
20 |
21 |
22 | // Handle searches.
23 | // Relies on document having 'meta' element with name 'search-domain'.
24 | function google_search() {
25 | var query = document.getElementById("google-search").value;
26 | var domain = $("meta[name=search-domain]").attr("value");
27 | window.open("https://www.google.com/search?q=" + query + "+site:" + domain);
28 | }
29 |
30 | // function to shrink the life cycle bar when scrolling
31 | $(function(){
32 | $('#life-cycle').data('size','big');
33 | });
34 |
35 | $(window).scroll(function(){
36 | if($(document).scrollTop() > 0)
37 | {
38 | if($('#life-cycle').data('size') == 'big')
39 | {
40 | $('#life-cycle').data('size','small');
41 | $('#life-cycle').stop().animate({
42 | padding: '5px'
43 | },100);
44 | }
45 | }
46 | else
47 | {
48 | if($('#life-cycle').data('size') == 'small')
49 | {
50 | $('#life-cycle').data('size','big');
51 | $('#life-cycle').stop().animate({
52 | padding: '15px'
53 | },100);
54 | }
55 | }
56 | });
57 |
--------------------------------------------------------------------------------
/bin/boilerplate/.travis.yml:
--------------------------------------------------------------------------------
1 | # Travis CI is only used to check the lesson and is not involved in its deployment
2 | dist: bionic
3 | language: ruby
4 | rvm:
5 | - 2.7.1
6 |
7 | branches:
8 | only:
9 | - gh-pages
10 | - /.*/
11 |
12 | cache:
13 | apt: true
14 | bundler: true
15 | directories:
16 | - /home/travis/.rvm/
17 | - $R_LIBS_USER
18 | - $HOME/.cache/pip
19 |
20 | env:
21 | global:
22 | - NOKOGIRI_USE_SYSTEM_LIBRARIES=true # speeds up installation of html-proofer
23 | - R_LIBS_USER=~/R/Library
24 | - R_LIBS_SITE=/usr/local/lib/R/site-library:/usr/lib/R/site-library
25 | - R_VERSION=4.0.2
26 |
27 | before_install:
28 | ## Install R + pandoc + dependencies
29 | - sudo add-apt-repository -y "ppa:marutter/rrutter4.0"
30 | - sudo add-apt-repository -y "ppa:c2d4u.team/c2d4u4.0+"
31 | - sudo add-apt-repository -y "ppa:ubuntugis/ppa"
32 | - sudo add-apt-repository -y "ppa:cran/travis"
33 | - travis_apt_get_update
34 | - sudo apt-get install -y --no-install-recommends build-essential gcc g++ libblas-dev liblapack-dev libncurses5-dev libreadline-dev libjpeg-dev libpcre3-dev libpng-dev zlib1g-dev libbz2-dev liblzma-dev libicu-dev cdbs qpdf texinfo libssh2-1-dev gfortran jq python3.5 python3-pip r-base
35 | - export PATH=${TRAVIS_HOME}/R-bin/bin:$PATH
36 | - export LD_LIBRARY_PATH=${TRAVIS_HOME}/R-bin/lib:$LD_LIBRARY_PATH
37 | - sudo mkdir -p /usr/local/lib/R/site-library $R_LIBS_USER
38 | - sudo chmod 2777 /usr/local/lib/R /usr/local/lib/R/site-library $R_LIBS_USER
39 | - echo 'options(repos = c(CRAN = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest"))' > ~/.Rprofile.site
40 | - export R_PROFILE=~/.Rprofile.site
41 | - curl -fLo /tmp/texlive.tar.gz https://github.com/jimhester/ubuntu-bin/releases/download/latest/texlive.tar.gz
42 | - tar xzf /tmp/texlive.tar.gz -C ~
43 | - export PATH=${TRAVIS_HOME}/texlive/bin/x86_64-linux:$PATH
44 | - tlmgr update --self
45 | - curl -fLo /tmp/pandoc-2.2-1-amd64.deb https://github.com/jgm/pandoc/releases/download/2.2/pandoc-2.2-1-amd64.deb
46 | - sudo dpkg -i /tmp/pandoc-2.2-1-amd64.deb
47 | - sudo apt-get install -f
48 | - rm /tmp/pandoc-2.2-1-amd64.deb
49 | - Rscript -e "install.packages(setdiff(c('renv', 'rprojroot'), installed.packages()), loc = Sys.getenv('R_LIBS_USER')); update.packages(lib.loc = Sys.getenv('R_LIBS_USER'), ask = FALSE, checkBuilt = TRUE)"
50 | - Rscript -e 'sessionInfo()'
51 | ## Install python and dependencies
52 | - python3 -m pip install --upgrade pip setuptools wheel
53 | - python3 -m pip install pyyaml
54 |
55 | script:
56 | - make lesson-check-all
57 | - make --always-make site
58 |
--------------------------------------------------------------------------------
/bin/boilerplate/AUTHORS:
--------------------------------------------------------------------------------
1 | FIXME: list authors' names and email addresses.
--------------------------------------------------------------------------------
/bin/boilerplate/CITATION:
--------------------------------------------------------------------------------
1 | FIXME: describe how to cite this lesson.
--------------------------------------------------------------------------------
/bin/boilerplate/README.md:
--------------------------------------------------------------------------------
1 | # FIXME Lesson title
2 |
3 | [](https://swc-slack-invite.herokuapp.com/)
4 |
5 | This repository generates the corresponding lesson website from [The Carpentries](https://carpentries.org/) repertoire of lessons.
6 |
7 | ## Contributing
8 |
9 | We welcome all contributions to improve the lesson! Maintainers will do their best to help you if you have any
10 | questions, concerns, or experience any difficulties along the way.
11 |
12 | We'd like to ask you to familiarize yourself with our [Contribution Guide](CONTRIBUTING.md) and have a look at
13 | the [more detailed guidelines][lesson-example] on proper formatting, ways to render the lesson locally, and even
14 | how to write new episodes.
15 |
16 | Please see the current list of [issues][FIXME] for ideas for contributing to this
17 | repository. For making your contribution, we use the GitHub flow, which is
18 | nicely explained in the chapter [Contributing to a Project](http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project) in Pro Git
19 | by Scott Chacon.
20 | Look for the tag . This indicates that the maintainers will welcome a pull request fixing this issue.
21 |
22 |
23 | ## Maintainer(s)
24 |
25 | Current maintainers of this lesson are
26 |
27 | * FIXME
28 | * FIXME
29 | * FIXME
30 |
31 |
32 | ## Authors
33 |
34 | A list of contributors to the lesson can be found in [AUTHORS](AUTHORS)
35 |
36 | ## Citation
37 |
38 | To cite this lesson, please consult with [CITATION](CITATION)
39 |
40 | [lesson-example]: https://carpentries.github.io/lesson-example
41 |
--------------------------------------------------------------------------------
/bin/boilerplate/_config.yml:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------
2 | # Values for this lesson.
3 | #------------------------------------------------------------
4 |
5 | # Which carpentry is this ("swc", "dc", "lc", or "cp")?
6 | # swc: Software Carpentry
7 | # dc: Data Carpentry
8 | # lc: Library Carpentry
9 | # cp: Carpentries (to use for instructor traning for instance)
10 | carpentry: "swc"
11 |
12 | # Overall title for pages.
13 | title: "Lesson Title"
14 |
15 | # Life cycle stage of the lesson
16 | # See this page for more details: https://cdh.carpentries.org/the-lesson-life-cycle.html
17 | # Possible values: "pre-alpha", "alpha", "beta", "stable"
18 | life_cycle: "pre-alpha"
19 |
20 | #------------------------------------------------------------
21 | # Generic settings (should not need to change).
22 | #------------------------------------------------------------
23 |
24 | # What kind of thing is this ("workshop" or "lesson")?
25 | kind: "lesson"
26 |
27 | # Magic to make URLs resolve both locally and on GitHub.
28 | # See https://help.github.com/articles/repository-metadata-on-github-pages/.
29 | # Please don't change it: / is correct.
30 | repository: /
31 |
32 | # Email address, no mailto:
33 | email: "team@carpentries.org"
34 |
35 | # Sites.
36 | amy_site: "https://amy.carpentries.org/"
37 | carpentries_github: "https://github.com/carpentries"
38 | carpentries_pages: "https://carpentries.github.io"
39 | carpentries_site: "https://carpentries.org/"
40 | dc_site: "https://datacarpentry.org"
41 | example_repo: "https://github.com/carpentries/lesson-example"
42 | example_site: "https://carpentries.github.io/lesson-example"
43 | lc_site: "https://librarycarpentry.org/"
44 | swc_github: "https://github.com/swcarpentry"
45 | swc_pages: "https://swcarpentry.github.io"
46 | swc_site: "https://software-carpentry.org"
47 | template_repo: "https://github.com/carpentries/styles"
48 | training_site: "https://carpentries.github.io/instructor-training"
49 | workshop_repo: "https://github.com/carpentries/workshop-template"
50 | workshop_site: "https://carpentries.github.io/workshop-template"
51 | cc_by_human: "https://creativecommons.org/licenses/by/4.0/"
52 |
53 | # Surveys.
54 | pre_survey: "https://carpentries.typeform.com/to/wi32rS?slug="
55 | post_survey: "https://carpentries.typeform.com/to/UgVdRQ?slug="
56 | instructor_pre_survey: "https://www.surveymonkey.com/r/instructor_training_pre_survey?workshop_id="
57 | instructor_post_survey: "https://www.surveymonkey.com/r/instructor_training_post_survey?workshop_id="
58 |
59 |
60 | # Start time in minutes (0 to be clock-independent, 540 to show a start at 09:00 am).
61 | start_time: 0
62 |
63 | # Specify that things in the episodes collection should be output.
64 | collections:
65 | episodes:
66 | output: true
67 | permalink: /:path/index.html
68 | extras:
69 | output: true
70 | permalink: /:path/index.html
71 |
72 | # Set the default layout for things in the episodes collection.
73 | defaults:
74 | - values:
75 | root: .
76 | layout: page
77 | - scope:
78 | path: ""
79 | type: episodes
80 | values:
81 | root: ..
82 | layout: episode
83 | - scope:
84 | path: ""
85 | type: extras
86 | values:
87 | root: ..
88 | layout: page
89 |
90 | # Files and directories that are not to be copied.
91 | exclude:
92 | - Makefile
93 | - bin/
94 | - .Rproj.user/
95 | - .vendor/
96 | - vendor/
97 | - .docker-vendor/
98 |
99 | # Turn on built-in syntax highlighting.
100 | highlighter: rouge
101 |
--------------------------------------------------------------------------------
/bin/boilerplate/_episodes/01-introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Introduction"
3 | teaching: 0
4 | exercises: 0
5 | questions:
6 | - "Key question (FIXME)"
7 | objectives:
8 | - "First learning objective. (FIXME)"
9 | keypoints:
10 | - "First key point. Brief Answer to questions. (FIXME)"
11 | ---
12 | FIXME
13 |
14 | {% include links.md %}
15 |
16 |
--------------------------------------------------------------------------------
/bin/boilerplate/_extras/about.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About
3 | ---
4 | {% include carpentries.html %}
5 | {% include links.md %}
6 |
--------------------------------------------------------------------------------
/bin/boilerplate/_extras/discuss.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Discussion
3 | ---
4 | FIXME
5 |
6 | {% include links.md %}
7 |
--------------------------------------------------------------------------------
/bin/boilerplate/_extras/figures.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Figures
3 | ---
4 |
5 | {% include base_path.html %}
6 | {% include manual_episode_order.html %}
7 |
8 |
67 |
68 | {% comment %} Create anchor for each one of the episodes. {% endcomment %}
69 |
70 | {% for lesson_episode in lesson_episodes %}
71 | {% if site.episode_order %}
72 | {% assign episode = site.episodes | where: "slug", lesson_episode | first %}
73 | {% else %}
74 | {% assign episode = lesson_episode %}
75 | {% endif %}
76 |
77 | {% endfor %}
78 |
79 | {% include links.md %}
80 |
--------------------------------------------------------------------------------
/bin/boilerplate/_extras/guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Instructor Notes"
3 | ---
4 | FIXME
5 |
6 | {% include links.md %}
7 |
--------------------------------------------------------------------------------
/bin/boilerplate/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: lesson
3 | root: . # Is the only page that doesn't follow the pattern /:path/index.html
4 | permalink: index.html # Is the only page that doesn't follow the pattern /:path/index.html
5 | ---
6 | FIXME: home page introduction
7 |
8 |
9 |
10 | {% comment %} This is a comment in Liquid {% endcomment %}
11 |
12 | > ## Prerequisites
13 | >
14 | > FIXME
15 | {: .prereq}
16 |
17 | {% include links.md %}
18 |
--------------------------------------------------------------------------------
/bin/boilerplate/reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: reference
3 | ---
4 |
5 | ## Glossary
6 |
7 | FIXME
8 |
9 | {% include links.md %}
10 |
--------------------------------------------------------------------------------
/bin/boilerplate/setup.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Setup
3 | ---
4 | FIXME
5 |
6 |
7 | {% include links.md %}
8 |
--------------------------------------------------------------------------------
/bin/chunk-options.R:
--------------------------------------------------------------------------------
1 | # These settings control the behavior of all chunks in the novice R materials.
2 | # For example, to generate the lessons with all the output hidden, simply change
3 | # `results` from "markup" to "hide".
4 | # For more information on available chunk options, see
5 | # http://yihui.name/knitr/options#chunk_options
6 |
7 | library("knitr")
8 |
9 | fix_fig_path <- function(pth) file.path("..", pth)
10 |
11 |
12 | ## We set the path for the figures globally below, so if we want to
13 | ## customize it for individual episodes, we can append a prefix to the
14 | ## global path. For instance, if we call knitr_fig_path("01-") in the
15 | ## first episode of the lesson, it will generate the figures in
16 | ## `fig/rmd-01-`
17 | knitr_fig_path <- function(prefix) {
18 | new_path <- paste0(opts_chunk$get("fig.path"),
19 | prefix)
20 | opts_chunk$set(fig.path = new_path)
21 | }
22 |
23 | ## We use the rmd- prefix for the figures generated by the lessons so
24 | ## they can be easily identified and deleted by `make clean-rmd`. The
25 | ## working directory when the lessons are generated is the root so the
26 | ## figures need to be saved in fig/, but when the site is generated,
27 | ## the episodes will be one level down. We fix the path using the
28 | ## `fig.process` option.
29 |
30 | opts_chunk$set(tidy = FALSE, results = "markup", comment = NA,
31 | fig.align = "center", fig.path = "fig/rmd-",
32 | fig.process = fix_fig_path,
33 | fig.width = 8.5, fig.height = 8.5,
34 | fig.retina = 2)
35 |
36 | # The hooks below add html tags to the code chunks and their output so that they
37 | # are properly formatted when the site is built.
38 |
39 | hook_in <- function(x, options) {
40 | lg <- tolower(options$engine)
41 | style <- paste0(".language-", lg)
42 |
43 | stringr::str_c("\n\n~~~\n",
44 | paste0(x, collapse="\n"),
45 | "\n~~~\n{: ", style, "}\n\n")
46 | }
47 |
48 | hook_out <- function(x, options) {
49 | x <- gsub("\n$", "", x)
50 | stringr::str_c("\n\n~~~\n",
51 | paste0(x, collapse="\n"),
52 | "\n~~~\n{: .output}\n\n")
53 | }
54 |
55 | hook_error <- function(x, options) {
56 | x <- gsub("\n$", "", x)
57 | stringr::str_c("\n\n~~~\n",
58 | paste0(x, collapse="\n"),
59 | "\n~~~\n{: .error}\n\n")
60 | }
61 |
62 | hook_warning <- function(x, options) {
63 | x <- gsub("\n$", "", x)
64 | stringr::str_c("\n\n~~~\n",
65 | paste0(x, collapse = "\n"),
66 | "\n~~~\n{: .warning}\n\n")
67 | }
68 |
69 | knit_hooks$set(source = hook_in, output = hook_out, warning = hook_warning,
70 | error = hook_error, message = hook_out)
71 |
--------------------------------------------------------------------------------
/bin/dependencies.R:
--------------------------------------------------------------------------------
1 | install_required_packages <- function(lib = NULL, repos = getOption("repos")) {
2 |
3 | if (is.null(lib)) {
4 | lib <- .libPaths()
5 | }
6 |
7 | message("lib paths: ", paste(lib, collapse = ", "))
8 | missing_pkgs <- setdiff(
9 | c("rprojroot", "desc", "remotes", "renv"),
10 | rownames(installed.packages(lib.loc = lib))
11 | )
12 |
13 | install.packages(missing_pkgs, lib = lib, repos = repos)
14 |
15 | }
16 |
17 | find_root <- function() {
18 |
19 | cfg <- rprojroot::has_file_pattern("^_config.y*ml$")
20 | root <- rprojroot::find_root(cfg)
21 |
22 | root
23 | }
24 |
25 | identify_dependencies <- function() {
26 |
27 | root <- find_root()
28 |
29 | required_pkgs <- unique(c(
30 | ## Packages for episodes
31 | renv::dependencies(file.path(root, "_episodes_rmd"), progress = FALSE, error = "ignore")$Package,
32 | ## Packages for tools
33 | renv::dependencies(file.path(root, "bin"), progress = FALSE, error = "ignore")$Package
34 | ))
35 |
36 | required_pkgs
37 | }
38 |
39 | create_description <- function(required_pkgs) {
40 | d <- desc::description$new("!new")
41 | lapply(required_pkgs, function(x) d$set_dep(x))
42 | d$write("DESCRIPTION")
43 | }
44 |
45 | install_dependencies <- function(required_pkgs, ...) {
46 |
47 | create_description(required_pkgs)
48 | on.exit(file.remove("DESCRIPTION"))
49 | remotes::install_deps(dependencies = TRUE, ...)
50 |
51 | if (require("knitr") && packageVersion("knitr") < '1.9.19') {
52 | stop("knitr must be version 1.9.20 or higher")
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/bin/generate_md_episodes.R:
--------------------------------------------------------------------------------
1 | generate_md_episodes <- function() {
2 |
3 | ## get the Rmd file to process from the command line, and generate the path
4 | ## for their respective outputs
5 | args <- commandArgs(trailingOnly = TRUE)
6 | if (!identical(length(args), 2L)) {
7 | stop("input and output file must be passed to the script")
8 | }
9 |
10 | src_rmd <- args[1]
11 | dest_md <- args[2]
12 |
13 | ## knit the Rmd into markdown
14 | knitr::knit(src_rmd, output = dest_md)
15 |
16 | # Read the generated md files and add comments advising not to edit them
17 | add_no_edit_comment <- function(y) {
18 | con <- file(y)
19 | mdfile <- readLines(con)
20 | if (mdfile[1] != "---")
21 | stop("Input file does not have a valid header")
22 | mdfile <- append(
23 | mdfile,
24 | "# Please do not edit this file directly; it is auto generated.",
25 | after = 1
26 | )
27 | mdfile <- append(
28 | mdfile,
29 | paste("# Instead, please edit", basename(y), "in _episodes_rmd/"),
30 | after = 2
31 | )
32 | writeLines(mdfile, con)
33 | close(con)
34 | return(paste("Warning added to YAML header of", y))
35 | }
36 |
37 | vapply(dest_md, add_no_edit_comment, character(1))
38 | }
39 |
40 | generate_md_episodes()
41 |
--------------------------------------------------------------------------------
/bin/install_r_deps.sh:
--------------------------------------------------------------------------------
1 | Rscript -e "source(file.path('bin', 'dependencies.R')); install_required_packages(); install_dependencies(identify_dependencies())"
2 |
--------------------------------------------------------------------------------
/bin/knit_lessons.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Only try running R to translate files if there are some files present.
4 | # The Makefile passes in the names of files.
5 |
6 | if [ $# -eq 2 ] ; then
7 | Rscript -e "source('bin/generate_md_episodes.R')" "$@"
8 | fi
9 |
--------------------------------------------------------------------------------
/bin/lesson_initialize.py:
--------------------------------------------------------------------------------
1 | """Initialize a newly-created repository."""
2 |
3 |
4 | import sys
5 | import os
6 | import shutil
7 |
8 | BOILERPLATE = (
9 | '.travis.yml',
10 | 'AUTHORS',
11 | 'CITATION',
12 | 'CONTRIBUTING.md',
13 | 'README.md',
14 | '_config.yml',
15 | os.path.join('_episodes', '01-introduction.md'),
16 | os.path.join('_extras', 'about.md'),
17 | os.path.join('_extras', 'discuss.md'),
18 | os.path.join('_extras', 'figures.md'),
19 | os.path.join('_extras', 'guide.md'),
20 | 'index.md',
21 | 'reference.md',
22 | 'setup.md',
23 | )
24 |
25 |
26 | def main():
27 | """Check for collisions, then create."""
28 |
29 | # Check.
30 | errors = False
31 | for path in BOILERPLATE:
32 | if os.path.exists(path):
33 | print('Warning: {0} already exists.'.format(path), file=sys.stderr)
34 | errors = True
35 | if errors:
36 | print('**Exiting without creating files.**', file=sys.stderr)
37 | sys.exit(1)
38 |
39 | # Create.
40 | for path in BOILERPLATE:
41 | shutil.copyfile(
42 | os.path.join('bin', 'boilerplate', path),
43 | path
44 | )
45 |
46 |
47 | if __name__ == '__main__':
48 | main()
49 |
--------------------------------------------------------------------------------
/bin/markdown_ast.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Use Kramdown parser to produce AST for Markdown document.
4 |
5 | require "kramdown"
6 | require "json"
7 |
8 | markdown = STDIN.read()
9 | doc = Kramdown::Document.new(markdown)
10 | tree = doc.to_hash_a_s_t
11 | puts JSON.pretty_generate(tree)
12 |
--------------------------------------------------------------------------------
/bin/repo_check.py:
--------------------------------------------------------------------------------
1 | """
2 | Check repository settings.
3 | """
4 |
5 |
6 | import sys
7 | import os
8 | from subprocess import Popen, PIPE
9 | import re
10 | from argparse import ArgumentParser
11 |
12 | from util import Reporter, require
13 |
14 | # Import this way to produce a more useful error message.
15 | try:
16 | import requests
17 | except ImportError:
18 | print('Unable to import requests module: please install requests', file=sys.stderr)
19 | sys.exit(1)
20 |
21 |
22 | # Pattern to match Git command-line output for remotes => (user name, project name).
23 | P_GIT_REMOTE = re.compile(r'upstream\s+(?:https://|git@)github.com[:/]([^/]+)/([^.]+)(\.git)?\s+\(fetch\)')
24 |
25 | # Repository URL format string.
26 | F_REPO_URL = 'https://github.com/{0}/{1}/'
27 |
28 | # Pattern to match repository URLs => (user name, project name)
29 | P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
30 |
31 | # API URL format string.
32 | F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
33 |
34 | # Expected labels and colors.
35 | EXPECTED = {
36 | 'help wanted': 'dcecc7',
37 | 'status:in progress': '9bcc65',
38 | 'status:changes requested': '679f38',
39 | 'status:wait': 'fff2df',
40 | 'status:refer to cac': 'ffdfb2',
41 | 'status:need more info': 'ee6c00',
42 | 'status:blocked': 'e55100',
43 | 'status:out of scope': 'eeeeee',
44 | 'status:duplicate': 'bdbdbd',
45 | 'type:typo text': 'f8bad0',
46 | 'type:bug': 'eb3f79',
47 | 'type:formatting': 'ac1357',
48 | 'type:template and tools': '7985cb',
49 | 'type:instructor guide': '00887a',
50 | 'type:discussion': 'b2e5fc',
51 | 'type:enhancement': '7fdeea',
52 | 'type:clarification': '00acc0',
53 | 'type:teaching example': 'ced8dc',
54 | 'good first issue': 'ffeb3a',
55 | 'high priority': 'd22e2e'
56 | }
57 |
58 |
59 | def main():
60 | """
61 | Main driver.
62 | """
63 |
64 | args = parse_args()
65 | reporter = Reporter()
66 | repo_url = get_repo_url(args.repo_url)
67 | check_labels(reporter, repo_url)
68 | reporter.report()
69 |
70 |
71 | def parse_args():
72 | """
73 | Parse command-line arguments.
74 | """
75 |
76 | parser = ArgumentParser(description="""Check repository settings.""")
77 | parser.add_argument('-r', '--repo',
78 | default=None,
79 | dest='repo_url',
80 | help='repository URL')
81 | parser.add_argument('-s', '--source',
82 | default=os.curdir,
83 | dest='source_dir',
84 | help='source directory')
85 |
86 | args, extras = parser.parse_known_args()
87 | require(not extras,
88 | 'Unexpected trailing command-line arguments "{0}"'.format(extras))
89 |
90 | return args
91 |
92 |
93 | def get_repo_url(repo_url):
94 | """
95 | Figure out which repository to query.
96 | """
97 |
98 | # Explicitly specified.
99 | if repo_url is not None:
100 | return repo_url
101 |
102 | # Guess.
103 | cmd = 'git remote -v'
104 | p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE,
105 | close_fds=True, universal_newlines=True, encoding='utf-8')
106 | stdout_data, stderr_data = p.communicate()
107 | stdout_data = stdout_data.split('\n')
108 | matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
109 | matches = [m for m in matches if m is not None]
110 | require(len(matches) == 1,
111 | 'Unexpected output from git remote command: "{0}"'.format(matches))
112 |
113 | username = matches[0].group(1)
114 | require(
115 | username, 'empty username in git remote output {0}'.format(matches[0]))
116 |
117 | project_name = matches[0].group(2)
118 | require(
119 | username, 'empty project name in git remote output {0}'.format(matches[0]))
120 |
121 | url = F_REPO_URL.format(username, project_name)
122 | return url
123 |
124 |
125 | def check_labels(reporter, repo_url):
126 | """
127 | Check labels in repository.
128 | """
129 |
130 | actual = get_labels(repo_url)
131 | extra = set(actual.keys()) - set(EXPECTED.keys())
132 |
133 | reporter.check(not extra,
134 | None,
135 | 'Extra label(s) in repository {0}: {1}',
136 | repo_url, ', '.join(sorted(extra)))
137 |
138 | missing = set(EXPECTED.keys()) - set(actual.keys())
139 | reporter.check(not missing,
140 | None,
141 | 'Missing label(s) in repository {0}: {1}',
142 | repo_url, ', '.join(sorted(missing)))
143 |
144 | overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
145 | for name in sorted(overlap):
146 | reporter.check(EXPECTED[name].lower() == actual[name].lower(),
147 | None,
148 | 'Color mis-match for label {0} in {1}: expected {2}, found {3}',
149 | name, repo_url, EXPECTED[name], actual[name])
150 |
151 |
152 | def get_labels(repo_url):
153 | """
154 | Get actual labels from repository.
155 | """
156 |
157 | m = P_REPO_URL.match(repo_url)
158 | require(
159 | m, 'repository URL {0} does not match expected pattern'.format(repo_url))
160 |
161 | username = m.group(1)
162 | require(username, 'empty username in repository URL {0}'.format(repo_url))
163 |
164 | project_name = m.group(2)
165 | require(
166 | username, 'empty project name in repository URL {0}'.format(repo_url))
167 |
168 | url = F_API_URL.format(username, project_name)
169 | r = requests.get(url)
170 | require(r.status_code == 200,
171 | 'Request for {0} failed with {1}'.format(url, r.status_code))
172 |
173 | result = {}
174 | for entry in r.json():
175 | result[entry['name']] = entry['color']
176 | return result
177 |
178 |
179 | if __name__ == '__main__':
180 | main()
181 |
--------------------------------------------------------------------------------
/bin/run-make-docker-serve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o errexit
4 | set -o pipefail
5 | set -o nounset
6 |
7 |
8 | bundle install
9 | bundle update
10 | exec bundle exec jekyll serve --host 0.0.0.0
11 |
--------------------------------------------------------------------------------
/bin/test_lesson_check.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | import lesson_check
4 | import util
5 |
6 |
7 | class TestFileList(unittest.TestCase):
8 | def setUp(self):
9 | self.reporter = util.Reporter() # TODO: refactor reporter class.
10 |
11 | def test_file_list_has_expected_entries(self):
12 | # For first pass, simply assume that all required files are present
13 |
14 | lesson_check.check_fileset('', self.reporter, lesson_check.REQUIRED_FILES)
15 | self.assertEqual(len(self.reporter.messages), 0)
16 |
17 |
18 | if __name__ == "__main__":
19 | unittest.main()
20 |
--------------------------------------------------------------------------------
/bin/util.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import json
4 | from subprocess import Popen, PIPE
5 |
6 | # Import this way to produce a more useful error message.
7 | try:
8 | import yaml
9 | except ImportError:
10 | print('Unable to import YAML module: please install PyYAML', file=sys.stderr)
11 | sys.exit(1)
12 |
13 |
14 | # Things an image file's name can end with.
15 | IMAGE_FILE_SUFFIX = {
16 | '.gif',
17 | '.jpg',
18 | '.png',
19 | '.svg'
20 | }
21 |
22 | # Files that shouldn't be present.
23 | UNWANTED_FILES = [
24 | '.nojekyll'
25 | ]
26 |
27 | # Marker to show that an expected value hasn't been provided.
28 | # (Can't use 'None' because that might be a legitimate value.)
29 | REPORTER_NOT_SET = []
30 |
31 |
32 | class Reporter:
33 | """Collect and report errors."""
34 |
35 | def __init__(self):
36 | """Constructor."""
37 | self.messages = []
38 |
39 | def check_field(self, filename, name, values, key, expected=REPORTER_NOT_SET):
40 | """Check that a dictionary has an expected value."""
41 |
42 | if key not in values:
43 | self.add(filename, '{0} does not contain {1}', name, key)
44 | elif expected is REPORTER_NOT_SET:
45 | pass
46 | elif type(expected) in (tuple, set, list):
47 | if values[key] not in expected:
48 | self.add(
49 | filename, '{0} {1} value {2} is not in {3}', name, key, values[key], expected)
50 | elif values[key] != expected:
51 | self.add(filename, '{0} {1} is {2} not {3}',
52 | name, key, values[key], expected)
53 |
54 | def check(self, condition, location, fmt, *args):
55 | """Append error if condition not met."""
56 |
57 | if not condition:
58 | self.add(location, fmt, *args)
59 |
60 | def add(self, location, fmt, *args):
61 | """Append error unilaterally."""
62 |
63 | self.messages.append((location, fmt.format(*args)))
64 |
65 | @staticmethod
66 | def pretty(item):
67 | location, message = item
68 | if isinstance(location, type(None)):
69 | return message
70 | elif isinstance(location, str):
71 | return location + ': ' + message
72 | elif isinstance(location, tuple):
73 | return '{0}:{1}: '.format(*location) + message
74 |
75 | print('Unknown item "{0}"'.format(item), file=sys.stderr)
76 | return NotImplemented
77 |
78 | @staticmethod
79 | def key(item):
80 | location, message = item
81 | if isinstance(location, type(None)):
82 | return ('', -1, message)
83 | elif isinstance(location, str):
84 | return (location, -1, message)
85 | elif isinstance(location, tuple):
86 | return (location[0], location[1], message)
87 |
88 | print('Unknown item "{0}"'.format(item), file=sys.stderr)
89 | return NotImplemented
90 |
91 | def report(self, stream=sys.stdout):
92 | """Report all messages in order."""
93 |
94 | if not self.messages:
95 | return
96 |
97 | for m in sorted(self.messages, key=self.key):
98 | print(self.pretty(m), file=stream)
99 |
100 |
101 | def read_markdown(parser, path):
102 | """
103 | Get YAML and AST for Markdown file, returning
104 | {'metadata':yaml, 'metadata_len':N, 'text':text, 'lines':[(i, line, len)], 'doc':doc}.
105 | """
106 |
107 | # Split and extract YAML (if present).
108 | with open(path, 'r', encoding='utf-8') as reader:
109 | body = reader.read()
110 | metadata_raw, metadata_yaml, body = split_metadata(path, body)
111 |
112 | # Split into lines.
113 | metadata_len = 0 if metadata_raw is None else metadata_raw.count('\n')
114 | lines = [(metadata_len+i+1, line, len(line))
115 | for (i, line) in enumerate(body.split('\n'))]
116 |
117 | # Parse Markdown.
118 | cmd = 'ruby {0}'.format(parser)
119 | p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE,
120 | close_fds=True, universal_newlines=True, encoding='utf-8')
121 | stdout_data, stderr_data = p.communicate(body)
122 | doc = json.loads(stdout_data)
123 |
124 | return {
125 | 'metadata': metadata_yaml,
126 | 'metadata_len': metadata_len,
127 | 'text': body,
128 | 'lines': lines,
129 | 'doc': doc
130 | }
131 |
132 |
133 | def split_metadata(path, text):
134 | """
135 | Get raw (text) metadata, metadata as YAML, and rest of body.
136 | If no metadata, return (None, None, body).
137 | """
138 |
139 | metadata_raw = None
140 | metadata_yaml = None
141 |
142 | pieces = text.split('---', 2)
143 | if len(pieces) == 3:
144 | metadata_raw = pieces[1]
145 | text = pieces[2]
146 | try:
147 | metadata_yaml = yaml.load(metadata_raw, Loader=yaml.SafeLoader)
148 | except yaml.YAMLError as e:
149 | print('Unable to parse YAML header in {0}:\n{1}'.format(
150 | path, e), file=sys.stderr)
151 | sys.exit(1)
152 |
153 | return metadata_raw, metadata_yaml, text
154 |
155 |
156 | def load_yaml(filename):
157 | """
158 | Wrapper around YAML loading so that 'import yaml' is only needed
159 | in one file.
160 | """
161 |
162 | try:
163 | with open(filename, 'r', encoding='utf-8') as reader:
164 | return yaml.load(reader, Loader=yaml.SafeLoader)
165 | except (yaml.YAMLError, IOError) as e:
166 | print('Unable to load YAML file {0}:\n{1}'.format(
167 | filename, e), file=sys.stderr)
168 | sys.exit(1)
169 |
170 |
171 | def check_unwanted_files(dir_path, reporter):
172 | """
173 | Check that unwanted files are not present.
174 | """
175 |
176 | for filename in UNWANTED_FILES:
177 | path = os.path.join(dir_path, filename)
178 | reporter.check(not os.path.exists(path),
179 | path,
180 | "Unwanted file found")
181 |
182 |
183 | def require(condition, message):
184 | """Fail if condition not met."""
185 |
186 | if not condition:
187 | print(message, file=sys.stderr)
188 | sys.exit(1)
189 |
--------------------------------------------------------------------------------
/code/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/code/.gitkeep
--------------------------------------------------------------------------------
/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/data/.gitkeep
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8
2 |
3 | WORKDIR /root
4 |
5 | SHELL [ "/bin/bash", "-c" ]
6 |
7 | # Install general dependencies
8 | RUN apt-get -qq -y update && \
9 | apt-get -qq -y install apt-utils && \
10 | apt-get -qq -y update && \
11 | apt-get -qq -y install --no-install-recommends \
12 | sudo \
13 | curl \
14 | wget \
15 | vim \
16 | emacs && \
17 | apt-get -y autoclean && \
18 | apt-get -y autoremove && \
19 | rm -rf /var/lib/apt/lists/*
20 |
21 | RUN pip install --upgrade --no-cache-dir pip setuptools wheel && \
22 | pip install --no-cache-dir -q \
23 | scipy \
24 | matplotlib \
25 | jupyter \
26 | jupyterlab
27 |
28 | # Have Jupyter notebooks launch without additional command line options
29 | RUN jupyter notebook --generate-config && \
30 | sed -i -e "/allow_root/ a c.NotebookApp.allow_root = True" ~/.jupyter/jupyter_notebook_config.py && \
31 | sed -i -e "/custom_display_url/ a c.NotebookApp.custom_display_url = \'http://localhost:8888\'" ~/.jupyter/jupyter_notebook_config.py && \
32 | sed -i -e "/c.NotebookApp.ip/ a c.NotebookApp.ip = '0.0.0.0'" ~/.jupyter/jupyter_notebook_config.py && \
33 | sed -i -e "/open_browser/ a c.NotebookApp.open_browser = False" ~/.jupyter/jupyter_notebook_config.py
34 |
35 | # Enable tab completion by uncommenting it from /etc/bash.bashrc
36 | # The relevant lines are those below the phrase "enable bash completion in interactive shells"
37 | RUN export SED_RANGE="$(($(sed -n '\|enable bash completion in interactive shells|=' /etc/bash.bashrc)+1)),$(($(sed -n '\|enable bash completion in interactive shells|=' /etc/bash.bashrc)+7))" && \
38 | sed -i -e "${SED_RANGE}"' s/^#//' /etc/bash.bashrc && \
39 | unset SED_RANGE
40 |
41 | # Create user "docker" with sudo powers
42 | RUN useradd -m docker && \
43 | usermod -aG sudo docker && \
44 | echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers && \
45 | cp /root/.bashrc /home/docker/ && \
46 | cp -r /root/.jupyter /home/docker/ && \
47 | mkdir /home/docker/data && \
48 | chown -R --from=root docker /home/docker
49 |
50 | # Use C.UTF-8 locale to avoid issues with ASCII encoding
51 | ENV LC_ALL=C.UTF-8
52 | ENV LANG=C.UTF-8
53 |
54 | WORKDIR /home/docker/data
55 | ENV HOME /home/docker
56 | ENV USER docker
57 | USER docker
58 | ENV PATH /home/docker/.local/bin:$PATH
59 | # Avoid first use of sudo warning. c.f. https://askubuntu.com/a/22614/781671
60 | RUN touch $HOME/.sudo_as_admin_successful
61 |
62 | CMD [ "/bin/bash" ]
63 |
--------------------------------------------------------------------------------
/fig/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/fig/.gitkeep
--------------------------------------------------------------------------------
/files/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matthewfeickert/intro-to-docker/34f8f6436860e83f6f9e09da7c4a763520c46947/files/.gitkeep
--------------------------------------------------------------------------------
/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: lesson
3 | root: . # Is the only page that doesn't follow the pattern /:path/index.html
4 | permalink: index.html # Is the only page that doesn't follow the pattern /:path/index.html
5 | ---
6 | An opinionated introduction to using [Docker](https://www.docker.com/) as a software
7 | development tool.
8 |
9 |
10 |
11 | Taught at the 2020 US-ATLAS Computing Bootcamp
12 |
13 |
14 |
15 |
16 |
17 |
18 | {% comment %} This is a comment in Liquid {% endcomment %}
19 |
20 | > ## Prerequisites
21 | >
22 | > A computer with Docker installed on it
23 | {: .prereq}
24 |
25 | {% include links.md %}
26 |
--------------------------------------------------------------------------------
/reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: reference
3 | ---
4 |
5 | ## Glossary
6 |
7 | {% include links.md %}
8 |
--------------------------------------------------------------------------------
/setup.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Setup
3 | ---
4 | To install Docker Community Edition on your Linux, Mac, or Windows machine follow the [instructions in the Docker docs](https://docs.docker.com/install/).
5 |
6 |
7 | {% include links.md %}
8 |
--------------------------------------------------------------------------------