├── .gitattributes ├── .gitignore ├── .reuse └── dep5 ├── 0-prereqs └── README.md ├── 1-basics └── README.md ├── 2-dockerfiles └── README.md ├── 3-dynamics └── README.md ├── 4-multi-stage-builds └── README.md ├── 5-security └── README.md ├── CHANGELOG.md ├── CONTRIBUTORS.txt ├── LICENSE ├── LICENSES ├── Apache-2.0.txt ├── CC-BY-SA-4.0.txt └── CC0-1.0.txt ├── README.md ├── docs ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md └── example-app ├── Dockerfile ├── README.md ├── _book ├── animals │ ├── birds.html │ ├── cats.html │ ├── dogs.html │ └── img │ │ ├── black-cat.jpg │ │ ├── good-boy.jpg │ │ ├── tabby-cat.jpg │ │ └── yellow-bird.jpg ├── foods │ ├── fries.html │ ├── pasta.html │ └── tofu.html ├── gitbook │ ├── fonts │ │ └── fontawesome │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ ├── gitbook-plugin-anchorjs │ │ ├── anchor-style.js │ │ └── anchor.min.js │ ├── gitbook-plugin-fontsettings │ │ ├── fontsettings.js │ │ └── website.css │ ├── gitbook-plugin-highlight │ │ ├── ebook.css │ │ └── website.css │ ├── gitbook-plugin-livereload │ │ └── plugin.js │ ├── gitbook-plugin-lunr │ │ ├── lunr.min.js │ │ └── search-lunr.js │ ├── gitbook-plugin-search │ │ ├── lunr.min.js │ │ ├── search-engine.js │ │ ├── search.css │ │ └── search.js │ ├── gitbook-plugin-sharing │ │ └── buttons.js │ ├── gitbook.js │ ├── images │ │ ├── apple-touch-icon-precomposed-152.png │ │ └── favicon.ico │ ├── style.css │ └── theme.js ├── index.html └── search_index.json ├── book.json ├── content ├── README.md ├── SUMMARY.md ├── animals │ ├── birds.md │ ├── cats.md │ ├── dogs.md │ └── img │ │ ├── black-cat.jpg │ │ ├── good-boy.jpg │ │ ├── tabby-cat.jpg │ │ └── yellow-bird.jpg └── foods │ ├── fries.md │ ├── pasta.md │ └── tofu.md ├── package-lock.json └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | /CHANGELOG.md merge=union 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | _site/ 10 | 11 | # Packages # 12 | ############ 13 | # it's better to unpack these files and commit the raw source 14 | # git has its own built in compression methods 15 | *.7z 16 | *.dmg 17 | *.gz 18 | *.iso 19 | *.jar 20 | *.rar 21 | *.tar 22 | *.zip 23 | 24 | # Logs and databases # 25 | ###################### 26 | *.log 27 | *.sql 28 | *.sqlite 29 | 30 | # OS generated files # 31 | ###################### 32 | .DS_Store 33 | .DS_Store? 34 | .Spotlight-V100 35 | .Trashes 36 | Icon? 37 | ehthumbs.db 38 | Thumbs.db 39 | 40 | # Vim swap files # 41 | ################## 42 | *.swp 43 | 44 | # Python # 45 | ################# 46 | *.pyc 47 | *.egg-info/ 48 | __pycache__/ 49 | *.py[cod] 50 | .env 51 | 52 | # Django # 53 | ################# 54 | *.egg-info 55 | .installed.cfg 56 | 57 | # Unit test / coverage reports 58 | ################# 59 | htmlcov/ 60 | .tox/ 61 | .coverage 62 | .cache 63 | nosetests.xml 64 | coverage.xml 65 | 66 | # vim 67 | ###### 68 | .un~ 69 | 70 | # Front-End # 71 | ############# 72 | node_modules/ 73 | bower_components/ 74 | .grunt/ 75 | src/vendor/ 76 | dist/ 77 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: Docker For All 3 | Upstream-Contact: Frida Hjelm 4 | Source: https://github.com/svt/docker-workshop 5 | 6 | Files: .gitignore 7 | Copyright: 2020 Sveriges Television AB 8 | License: CC0-1.0 9 | 10 | Files: .gitattributes 11 | Copyright: 2020 Sveriges Television AB 12 | License: CC0-1.0 13 | 14 | Files: docs/CONTRIBUTING.md 15 | Copyright: 2020 HERE Europe B.V. 16 | 2020 CFPB Consumer Finanical Protection Bureau. 17 | 2020 Sveriges Television AB 18 | License: CC0-1.0 and Apache-2.0 19 | 20 | Files: docs/CODE_OF_CONDUCT.md 21 | Copyright: 2020 Sveriges Television AB 22 | 2020 CFPB Consumer Finanical Protection Bureau. 23 | License: CC0-1.0 24 | 25 | Files: CONTRIBUTORS.txt 26 | Copyright: 2020 Sveriges Television AB 27 | License: CC0-1.0 28 | 29 | Files: *.md 30 | Copyright: 2020 Sveriges Television AB 31 | 2020 CFPB Consumer Finanical Protection Bureau. 32 | License: CC-BY-SA-4.0 33 | 34 | Files: example-app/* 35 | Copyright: 2020 Sveriges Television AB 36 | License: CC-BY-SA-4.0 -------------------------------------------------------------------------------- /0-prereqs/README.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | Before getting started, you need to ensure that you have the required tools installed on your computer. You will need: 4 | 5 | ## 1. A working internet connection 6 | 7 | Docker needs to download container images from Docker Hub, which is a public repository for...right, Docker images. Ensure that you have a working connection before beginning the exercises. 8 | 9 | ## 2. The text editor of your choice 10 | 11 | We recommend VSCode, which is available for most platforms: 12 | 13 | You may also want to install the Docker extension for VSCode, which adds syntax highlighting and a few other nice tools. You can read more about installing extensions [here](https://code.visualstudio.com/docs/editor/extension-gallery). 14 | 15 | ## 3. Install docker 16 | 17 | Official install guides are available for [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu), [Mac](https://docs.docker.com/docker-for-mac/install) and [Windows](https://docs.docker.com/docker-for-windows/install). 18 | 19 | When your installation has completed, try running the following command in a terminal: 20 | 21 | ```sh 22 | docker run hello-world 23 | ``` 24 | 25 | If you see the following lines in your output your docker installation is working correctly! 26 | 27 | ```sh 28 | Hello from Docker! 29 | This message shows that your installation appears to be working correctly. 30 | ``` 31 | 32 | You are now ready to start with [Chapter 1](../1-basics/)! 33 | -------------------------------------------------------------------------------- /3-dynamics/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # Chapter 3: Dynamics 6 | 7 | In this chapter you will try building Docker images dynamically with ARGs and control them with ENV variables. You can use our prepared example in the `example-app` directory in this repository to try out the different methods. 8 | 9 | ## Contents 10 | 11 | 1. [Building with ARG and --build-arg](#arg) 12 | 2. [Controlling with ENV](#env) 13 | 3. [Combining ARG and ENV](#combining) 14 | 4. [Using the host filesystem](#volumes) 15 | 16 | --- 17 | 18 | ## 3.1 Building with `ARG` and `--build-arg` 19 | 20 | The `ARG` instruction lets you define variables that exist in the scope of the docker build process. The resulting variable can have a default value defined and can also be overridden from the `docker build` command using the flag `--build-arg`. An example: 21 | 22 | ```Dockerfile 23 | FROM ubuntu 24 | ARG packages=curl 25 | RUN apt-get update && apt-get install $packages 26 | ``` 27 | 28 | By default, this Dockerfile installs the `curl` package. But if we want to install something else instead, we can override the default when building the image using `--build-arg`: 29 | 30 | ```bash 31 | docker build --build-arg packages=cowsay 32 | ``` 33 | 34 | The official documentation for the `ARG` instruction can be found [here](https://docs.docker.com/engine/reference/builder/#arg), we recommend that you have a look at it before continuing. 35 | 36 | ### Try: Use an ARG instruction to specify a directory to copy files from 37 | 38 | Our example-app is a Gitbook containing info on a number of interesting things. We have pre-built it for you, so the subfolder `_book` contains static html content that you can copy and use in a container image. The example-app folder also contains a Dockerfile that starts a basic web server - the default nginx image, to be specific. 39 | 40 | Use an `ARG` to let you specify a source directory for content to be copied to the web server image at build time. Then use `--build-arg` to put the static example site in your image, so that it is served when you start the container. 41 | 42 |
43 | 44 | Hint1 45 | 46 | If you don't know where to start, try modifying the Dockerfile to copy the files from a specific path first using `COPY`. Then consider how you can control the source path from the build command using an `ARG` instruction. 47 | 48 |
49 | 50 |
51 | 52 | Hint2 53 | 54 | You need to copy everything in the `_book` folder to the path `/usr/share/nginx/html/` in the image. One way to do this using `ARG` and `--build-arg` would be: 55 | 56 | ```Dockerfile 57 | # Dockerfile 58 | FROM nginx 59 | 60 | ARG content_path 61 | 62 | COPY $content_path /usr/share/nginx/html/ 63 | ``` 64 | 65 | ```bash 66 | # Build command 67 | docker build --build-arg content_path="_book" -t example-app:latest . 68 | ``` 69 | 70 |
71 | 72 | #### How you'll know it worked 73 | 74 | When you start a new container based on the image you built, you should be able to browse the amazingly informative gitbook site. 75 | 76 | --- 77 | 78 | ## 3.2 Controlling with ENV 79 | 80 | Environment variables can be set in the Dockerfile using the `ENV` instruction (full documentation can be found [here](https://docs.docker.com/engine/reference/builder/#env)). These can have default values and/or be set on the command line in the `docker run` command (see the [complete command documentation](https://docs.docker.com/engine/reference/run/#env-environment-variables) for reference). 81 | 82 | ### Try: An example from the internet! 83 | 84 | [This tutorial](https://medium.com/create-code/docker-environment-variables-and-nginx-93d7173f19ec) describes a scenario where we want to control the behaviour of our container depending on the value of and environment variable. Try it out! 85 | 86 | *NB: The above example uses an environment variable called simply `ENV` to distinguish production and staging environments. Don't confuse the variable name with the instruction!* 87 | 88 | --- 89 | 90 | ## 3.3 Combining ARG with ENV 91 | 92 | In most scenarios we use a combination of `ENV` and `ARG` instructions to acheive flexibility in Dockerfiles. For example, one common practice is to use an `ARG` to provide the value for an `ENV`. Read the ["Using ARG variables" section of the Dockerfile ARG documentation](https://docs.docker.com/engine/reference/builder/#using-arg-variables) to learn more about how they interact. 93 | 94 | In short, an ARG will populate an ENV with the same name, but a value for the ENV explicitly set in the Dockerfile will override the value given by the ARG. ENV variables will be available to the processes in the resulting containers, while ARG variables may not be. [This blog post](https://dev.to/stevoperisic/dynamic-dockerfile-with-arg-2h62) describes the case very well. 95 | 96 | **Please also have a look at the Secrets leakage section of chapter 5 for some examples of how ARG and ENV values can be exposed unintentionally.** 97 | 98 | --- 99 | 100 | ## 3.4 Using the host file system 101 | 102 | There is an option available when running containers that allow the container to interact with the local filesystem, so you don't have to copy everything to the image at build time. Common use cases are for example when we need persistent storage, such as when running a database or similar service. 103 | 104 | **NB: This is not available on most microservice platforms, at least not in the default manner described here. Specifically it is not supported in SVT:s Molnet Apps. However, for local development purposes, it can be very useful.** 105 | 106 | Persistent storage can be set up in multiple ways, but we'll keep it simple here. In order to make `/folder/on/docker/host/` available inside the container at the path `/path/inside/container/`, we specify this in the `docker run` command using the `-v` option: 107 | 108 | ```bash 109 | docker run -v /folder/on/docker/host:/path/inside/container:ro image 110 | ``` 111 | 112 | The `:ro` part is optional and specifies that the access to the filesystem will be *read-only*. If it is omitted, the container will also be able to write to the path. There are other options available, you can find out more about them in the [documentation](https://docs.docker.com/engine/reference/run/#volume-shared-filesystems). 113 | 114 | ### Try: Serve content directly from the host filesystem 115 | 116 | Remember the example in the beginning of this chapter? What if we were to just run the standard nginx image and inserted the `_book` directory at the appropriate path instead? Try it out. 117 | 118 |
119 | Hint 120 | 121 | The command would be something like: 122 | 123 | ```bash 124 | docker run -v /home/myuser/docker-workshop/_book:/usr/share/nginx/html -p 80:8080 nginx 125 | ``` 126 | 127 | Note that the paths given in the command must be absolute. 128 |
129 | 130 | Now for some nice building practices in [Chapter 4](../4-multi-stage-builds/README.md)! 131 | -------------------------------------------------------------------------------- /4-multi-stage-builds/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # Chapter 4: Multi-stage builds 6 | 7 | Moving the actual building of your code into docker has several advantages - one of which is that you no longer need to have all build dependencies present on your computer in order to build. In this chapter you will try out multi-stage docker builds and create a Dockerfile that takes care of both building the code and running it. 8 | 9 | ## The problem 10 | 11 | We'll revisit our example-app for a bit. Let's say we've made a change to the content, and now we want to build a new image with the updated content. Assuming we just cloned the repo and have no dependencies installed, we would potentially have to do several things: 12 | 13 | 1. Install node.js. 14 | 2. Install the node dependencies with `npm install`. 15 | 3. Rebuild the static html content in `_book` using `npm run build`. 16 | 4. Rebuild the docker image. 17 | 18 | Feels like a lot of work to add another picture of a cute dog, right? And what if we don't want to install all those npm packages on our computer? Luckily, docker can do all the steps for us. 19 | 20 | ## The multi-stage build 21 | 22 | A not so well-known secret of the Dockerfile is that you can use as many `FROM` instructions as you like. When you provide a second `FROM` instruction, the build simply switches to using another base image and continues executing any subsequent instructions in that one instead. So basically, we could do the building in one image, and the web serving in another! 23 | 24 | Now would probably be a good time to read the [documentation on multi-stage Docker builds](https://docs.docker.com/develop/develop-images/multistage-build/). 25 | 26 | It looks like we can copy content from a previous stage using an instruction like 27 | 28 | ```Dockerfile 29 | COPY --from= /path/in/previous/stage /target/path/in/current/stage 30 | ``` 31 | 32 | ### Try it 33 | 34 | Modify the Dockerfile to a multi-stage build. The file should contain two stages: One that copies the relevant source files and runs the necessary build commands, and one the copies the generated static content to a web server image. Try using the `node:alpine`-image for the first stage, it is an image built specifically for node applications. Stick with the `nginx` image for the second part. Then update some of the content in the `content` folder, rebuild the app and run the new image to see your changes! 35 | 36 |
37 | 38 | Hint1 39 | 40 | Remember that in the build stage you need to copy all relevant files to the image before you can run the needed commands. 41 | 42 | Don't forget to switch to the new stage using a new `FROM` instruction after the build is completed. 43 | 44 | If you run into problems, try adding a single instruction at a time to the Dockerfile to ensure that you know what it soes before continuing to the next. Read all error messages carefully. 45 | 46 |
47 | 48 |
49 | 50 | Hint2 51 | 52 | A working example looks like this: 53 | 54 | ```Dockerfile 55 | FROM node:alpine AS build-stage 56 | 57 | COPY ./package.json /app/package.json 58 | COPY ./book.json /app/book.json 59 | COPY . /app 60 | WORKDIR /app 61 | 62 | RUN npm install 63 | RUN npm run build 64 | 65 | FROM nginx:alpine 66 | COPY --from=build-stage /app/_book /usr/share/nginx/html 67 | ``` 68 | 69 |
70 | 71 | ### Resources / Other things to try 72 | 73 | * Look up the `node:alpine` image in more details. What if you wanted to use a specific node version? How could you let the node version be selected dynamically? 74 | * [Advanced Multi-stage Build Patterns](https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae) by Tõnis Tiigi is a really good writeup of the possibilities available when using multi-stage builds. 75 | 76 | Don't stop yet! There are important security points in [Chapter 5](../5-security/README.md). -------------------------------------------------------------------------------- /5-security/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Chapter 5: Security 4 | 5 | In this chapter we will look at a few security caveats that are good to know about. 6 | 7 | ## Contents 8 | 9 | 1. [Keep your dependencies updated](#updated) 10 | 2. [Scrutinize your sources](#sources) 11 | 3. [Handle build secrets](#buildsecrets) 12 | 4. [Handle runtime secrets](#runtimesecrets) 13 | 14 | --- 15 | 16 | ## 5.1 Keep your dependencies updated 17 | 18 | Congratulations, you are running your micro services in containers and have thus been granted wide-ranging control over your application's runtime.
19 | In other words: Congratulations, you have been awarded with the trust to maintain the operating system (OS)-level dependencies of your applications. 20 | 21 | Keeping your OS-level dependencies updated important because just like your library dependencies, your OS-level dependencies can contain security bugs that need to be patched. 22 | 23 | Sounds scary? It doesn't have to be: 24 | 25 | * The principle of maintaining OS-level dependencies are largely the same as for maintaining library dependencies 26 | * You can rely on the work of the maintainers of your base image. You don't have to handle every package dependency separately, rather you work with readily-assembled collections of dependencies which are called base images, or distributions in more traditional Linux terms 27 | * The most important thing to remember is to update them as regularly, maybe at the same time, as your library dependencies 28 | * There are tools available to help you with the job 29 | 30 | In this workshop section we will look at some approaches to handle updates of your base images. 31 | 32 | ### Different approaches for handling base image dependencies 33 | 34 | As with library dependencies, you can go two orthogonal ways to achieve good dependency hygiene: 35 | 36 | 1. Depend on the most up-to-date version of your base image 37 | 1. Depend on a specific version of your base image 38 | 39 | #### Practice: Depend on the most up-to-date version of your base image 40 | 41 | How would you achieve this behaviour in your Dockerfile? 42 | 43 | How does the approach behave? What are the advantages and disadvantages? 44 | 45 |
46 | Hint 47 | 48 | 1. For depending on the most up-to-date version of your base image, you would specify a tag for your base image that is updated regularly, like `latest` in the example below: 49 | 50 | ```Dockerfile 51 | FROM node:latest 52 | ``` 53 | 54 | Usually images have a `latest` tag, but there can be more continuously updated tags. Generally, Docker does not distinguish between mutable branches and immutable tags the way git does. Often it is clear from the name, but make sure to read up in your base image's documentation on the Docker Hub if a tag is continuously updated or not. 55 | 56 | The image you build will be updated to the new version as soon as you build it again after the new version of the base image has been published. 57 | 58 | Advantages: 59 | 60 | * You will always get the latest fixes once you rebuild your image 61 | 62 | Disadvantages: 63 | 64 | * You don't get reproducible builds, which means that when you rebuild your image with based on the same git hash, it way not be the same as when you built it the last time. This can be problematic if changes or regressions are introduced upstream without you noticing 65 | 66 | --- 67 | 68 |
69 | 70 | #### Practice: Depend on a specific version of your base image 71 | 72 | How would you achieve this behaviour in your Dockerfile? 73 | 74 | How does the approach behave? What are the advantages and disadvantages? 75 | 76 |
77 | Hint 78 | 79 | For depending on a specific version of your base image, use a tag of your base image that is not updated, usually represented by a tag named with a specific version number: 80 | 81 | ```Dockerfile 82 | FROM node:13.10.1 83 | ``` 84 | 85 | Advantages: 86 | 87 | * You have full control over your images and thus produce reproducible builds: The code from one git hash does always produce the same image. No nasty surprises. 88 | * When you do big changes (major version updates) you can handle the risk with some extra testing. 89 | 90 | Disadvantages: 91 | 92 | * You have to have a process for explicitly updating base image versions regularly 93 | 94 | --- 95 | 96 |
97 | 98 | #### Recommendations 99 | 100 | ##### If you maintain rapidly-developed services with good automated test coverage 101 | 102 | Generally, **if you update your service regularly**, the approach of depending on the latest version might just work for you. In this case, the updates from your base image come in small increments, so the chances of you being caught off-guard by several regressions at the same time are relatively small. You are on top of the code of your service and if things break, you don't roll back, you just roll forward. 103 | 104 | Also **automated integration tests help a lot with handling the risk** here. 105 | 106 | **Watch out for changes in your product's life-cycle**: If you go from rapid development to more of a maintenance phase, you might need to re-evaluate your approach. 107 | 108 | ##### If you maintain mature services that need a way to minimize risk of upstream regressions 109 | 110 | Depending on a specific version of your base image can work for you even if you don't change your code very often. The process of **updating dependencies is very clearly tracked in the code** and you can choose a good time for handling more risky updates to newer major versions. 111 | 112 | Fundamentally, both approaches benefit very much from good automated integration test coverage. Depending on a specific version can however enable you to **handle the risk of upstream regressions with a more manual testing-based approach**. 113 | 114 | The big challenge is to create a working update process and getting an answer to the question: When do I need to update?
You can get help answering that question though: Integrate a security scanning tool, like Open Source tool [trivy](https://github.com/aquasecurity/trivy), into your [Continuous Delivery pipeline](https://github.com/aquasecurity/trivy#continuous-integration-ci).
115 | Especially if you only do sporadic development on your service, consider running security scans on schedule with notifications to where you see them. That way you get a ping when a security vulnerability has been discovered that might affect your service. Depending on the severity of the vulnerability and the probability of exploitation in your service, you can make an informed decision about when to update. 116 | 117 | ##### Real life use-cases 118 | 119 | The approaches described are consciously contrived. In reality you likely want to take an in-between approach. 120 | 121 | Many base images have tags that are updated only within a major or minor version. 122 | 123 |
124 | In our node example: 125 | 126 | ```Dockerfile 127 | FROM node:13.10 128 | ``` 129 | 130 | or: 131 | 132 | ```Dockerfile 133 | FROM node:13 134 | ``` 135 | 136 | --- 137 | 138 |
139 | 140 | In this way you can mix the two approaches: Continuous updates of patch/minor-versions but controlled updates for minor/major versions. 141 | 142 | #### Choose long-term support releases 143 | 144 | If you want **to minimize the maintenance burden, choose long-term support releases**. Use major versions that have a longer support cycle, if they are available. These major versions will get security and possibly bug fix updates for a longer time, while not otherwise changing the behaviour of the software. 145 | 146 | #### Choose lightweight base images 147 | 148 | Choosing more **lightweight base images can improve security** (like those built on the Linux distribution alpine). Since they contain fewer extras and optional packages, using them reduces the amount of exploitable security bugs. 149 | 150 | Sophisticated images like `node` have many different permutations of tags: Not only for language runtime versions, but also for variants that build on different base images. 151 | 152 | For example, when you specify, `FROM node:latest`, you get an image of the latest node version runtime based on the Linux distribution Debian in the version `stretch`. You can however also get a variant, the latest node based on alpine, by specifying `node:alpine`. The latest version within the major version 13 based on alpine would be `node:13-alpine`. 153 | 154 | Check out the images' documentation on Docker Hub (t.ex.: [node](https://hub.docker.com/_/node)) to see what tags there are. These pages can be quite dense. As a tip: To see what a tag like `latest` is currently based on, look for it on the page and see what version tags are listed on the same row, these are usually equivalent. 155 | 156 | --- 157 | 158 | ## 5.2 Scrutinize your sources 159 | 160 | As usual with software, you need to handle the risk of not knowing for sure if you can trust a source that you pull in software from. 161 | 162 | In the case of Docker images, you can do a few things to minimize that risk: 163 | 164 | * Always prefer [Docker Official Images](https://docs.docker.com/docker-hub/official_images/). These images are curated and evaluated by a Docker Inc. and get regular security updates. These images have the "official image" badge on the Docker Hub and lack a publisher name (i.e. just `node`, not `mytotallylegitcompany/node`). 165 | * Prefer images built by the relevant upstream open source projects. They should have a reputation that can be lost when not doing a good job. 166 | * Avoid images created by individuals. 167 | 168 | It is not always easy to verify if an image was created by the upstream open source project. Here is a list of aspects you should look for to verify (more convincing ones first): 169 | 170 | * Is the source code for the Dockerfile hosted in the same Github/Gitlab organization as the source code of the upstream open source project? 171 | * Is the Docker image linked to from the official open source project's website or the README file? 172 | * Have a look at the profile page of the image publisher (example for [selenium](https://hub.docker.com/u/selenium)). Does the information provided make sense? Things like wrong links to the project page or recent join dates should make you suspicious. 173 | 174 | --- 175 | 176 | ## 5.3 Handle build secrets 177 | 178 | To build a Docker container, you often need to supply secrets to your language build tool, for example to download private library dependencies from our own build artifact repository. 179 | 180 | These kinds of secrets are commonly called build secrets or build time secrets, since they are only needed at build time. 181 | 182 | You need to be careful with these to not leak the secret by using it in the container. 183 | 184 | ### Practice: Retrieve a BUILD_ARG 185 | 186 | Create a Dockerfile with the following content: 187 | 188 | ```Dockerfile 189 | FROM nginx:latest 190 | 191 | ARG BUILD_REPO_SECRET 192 | RUN echo "Running a build using $BUILD_REPO_SECRET" 193 | # Faking creation of build artifact 194 | RUN touch build_artifact 195 | ``` 196 | 197 | Build the Docker image by running: 198 | 199 | ``` 200 | docker build --build-arg BUILD_REPO_SECRET=secr3t -t buildargtest . 201 | ``` 202 | 203 | Is there a way to retrieve the secret that was only needed for building in the finished container? 204 | 205 |
206 | Hint 207 | 208 | Yes you can! Just run: 209 | 210 | ```bash 211 | docker image inspect buildargtest:latest | grep secr3t 212 | ``` 213 | 214 | Output: 215 | 216 | ```bash 217 | "BUILD_REPO_SECRET=secr3t", 218 | ``` 219 | 220 | So everyone who has access to this image also has access to the build secret. 221 | 222 | You can of course also do this with images pulled from Docker Hub. In fact, `docker inspect` is a great way to learn about the images you want to use. 223 | 224 | --- 225 | 226 |
227 | 228 | ### Practice: Avoid leaking build arguments 229 | 230 | To avoid the situation above, you can make use of something you already learned in Chapter 4: Multi-stage builds. 231 | 232 | Try this: 233 | 234 | 1. Prevent leaking of the build secret by building in a build stage and copy the build artifacts into the final container. 235 | 1. Verify by running the `docker image inspect` command from above that the build secret is not leaked. 236 | 237 |
238 | Hint 239 | 240 | This Dockerfile does not leak build secrets: 241 | 242 | ```Dockerfile 243 | FROM nginx:latest as build 244 | 245 | ARG BUILD_REPO_SECRET 246 | RUN echo "Running a build using $BUILD_REPO_SECRET" 247 | # Faking creation of build artifact 248 | RUN touch build_artifact 249 | 250 | # Clean image without the BUILD_REPO_SECRET that we copy the build artifacts into 251 | FROM nginx:latest 252 | 253 | COPY --from=build build_artifact build_artifact 254 | ``` 255 | 256 |
257 | 258 | --- 259 | 260 | ## 5.4 Handle runtime secrets 261 | 262 | Runtime secrets are secrets that are needed at the time a service actually runs. Examples are authorization credentials for accessing other networked services like databases. 263 | 264 | According to [12factor](https://12factor.net/) etiquette, runtime secrets should always be [saved in the runtime environment](https://12factor.net/config). This enables us to use the same code in several environments, which in turn enables us to test code in a test environment before deploying it to production. 265 | 266 | This also prevents leakage of secret information outside of runtime and build systems. 267 | 268 | --- 269 | 270 | This concludes the current version of our docker workshop! We hope you enjoyed it and that you learned something. If you want to get in touch with us, please open an issue in the main repo at . Thank's for playing! 271 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | All notable changes to this project will be documented in this file. 2 | We follow the [Semantic Versioning 2.0.0](http://semver.org/) format. 3 | 4 | ## 1.0.0 - 2020-05-26 5 | 6 | First open source release 7 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | Frida Hjelm 2 | Alexander Bethke 3 | Natalie Cyreus 4 | Johan Grimlund 5 | Mia Gruvman -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, 6 | AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | 11 | 12 | "License" shall mean the terms and conditions for use, reproduction, and distribution 13 | as defined by Sections 1 through 9 of this document. 14 | 15 | 16 | 17 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 18 | owner that is granting the License. 19 | 20 | 21 | 22 | "Legal Entity" shall mean the union of the acting entity and all other entities 23 | that control, are controlled by, or are under common control with that entity. 24 | For the purposes of this definition, "control" means (i) the power, direct 25 | or indirect, to cause the direction or management of such entity, whether 26 | by contract or otherwise, or (ii) ownership of fifty percent (50%) or more 27 | of the outstanding shares, or (iii) beneficial ownership of such entity. 28 | 29 | 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions 32 | granted by this License. 33 | 34 | 35 | 36 | "Source" form shall mean the preferred form for making modifications, including 37 | but not limited to software source code, documentation source, and configuration 38 | files. 39 | 40 | 41 | 42 | "Object" form shall mean any form resulting from mechanical transformation 43 | or translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, and conversions to other media types. 45 | 46 | 47 | 48 | "Work" shall mean the work of authorship, whether in Source or Object form, 49 | made available under the License, as indicated by a copyright notice that 50 | is included in or attached to the work (an example is provided in the Appendix 51 | below). 52 | 53 | 54 | 55 | "Derivative Works" shall mean any work, whether in Source or Object form, 56 | that is based on (or derived from) the Work and for which the editorial revisions, 57 | annotations, elaborations, or other modifications represent, as a whole, an 58 | original work of authorship. For the purposes of this License, Derivative 59 | Works shall not include works that remain separable from, or merely link (or 60 | bind by name) to the interfaces of, the Work and Derivative Works thereof. 61 | 62 | 63 | 64 | "Contribution" shall mean any work of authorship, including the original version 65 | of the Work and any modifications or additions to that Work or Derivative 66 | Works thereof, that is intentionally submitted to Licensor for inclusion in 67 | the Work by the copyright owner or by an individual or Legal Entity authorized 68 | to submit on behalf of the copyright owner. For the purposes of this definition, 69 | "submitted" means any form of electronic, verbal, or written communication 70 | sent to the Licensor or its representatives, including but not limited to 71 | communication on electronic mailing lists, source code control systems, and 72 | issue tracking systems that are managed by, or on behalf of, the Licensor 73 | for the purpose of discussing and improving the Work, but excluding communication 74 | that is conspicuously marked or otherwise designated in writing by the copyright 75 | owner as "Not a Contribution." 76 | 77 | 78 | 79 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 80 | of whom a Contribution has been received by Licensor and subsequently incorporated 81 | within the Work. 82 | 83 | 2. Grant of Copyright License. Subject to the terms and conditions of this 84 | License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 85 | no-charge, royalty-free, irrevocable copyright license to reproduce, prepare 86 | Derivative Works of, publicly display, publicly perform, sublicense, and distribute 87 | the Work and such Derivative Works in Source or Object form. 88 | 89 | 3. Grant of Patent License. Subject to the terms and conditions of this License, 90 | each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 91 | no-charge, royalty-free, irrevocable (except as stated in this section) patent 92 | license to make, have made, use, offer to sell, sell, import, and otherwise 93 | transfer the Work, where such license applies only to those patent claims 94 | licensable by such Contributor that are necessarily infringed by their Contribution(s) 95 | alone or by combination of their Contribution(s) with the Work to which such 96 | Contribution(s) was submitted. If You institute patent litigation against 97 | any entity (including a cross-claim or counterclaim in a lawsuit) alleging 98 | that the Work or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses granted to You 100 | under this License for that Work shall terminate as of the date such litigation 101 | is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the Work or 104 | Derivative Works thereof in any medium, with or without modifications, and 105 | in Source or Object form, provided that You meet the following conditions: 106 | 107 | (a) You must give any other recipients of the Work or Derivative Works a copy 108 | of this License; and 109 | 110 | (b) You must cause any modified files to carry prominent notices stating that 111 | You changed the files; and 112 | 113 | (c) You must retain, in the Source form of any Derivative Works that You distribute, 114 | all copyright, patent, trademark, and attribution notices from the Source 115 | form of the Work, excluding those notices that do not pertain to any part 116 | of the Derivative Works; and 117 | 118 | (d) If the Work includes a "NOTICE" text file as part of its distribution, 119 | then any Derivative Works that You distribute must include a readable copy 120 | of the attribution notices contained within such NOTICE file, excluding those 121 | notices that do not pertain to any part of the Derivative Works, in at least 122 | one of the following places: within a NOTICE text file distributed as part 123 | of the Derivative Works; within the Source form or documentation, if provided 124 | along with the Derivative Works; or, within a display generated by the Derivative 125 | Works, if and wherever such third-party notices normally appear. The contents 126 | of the NOTICE file are for informational purposes only and do not modify the 127 | License. You may add Your own attribution notices within Derivative Works 128 | that You distribute, alongside or as an addendum to the NOTICE text from the 129 | Work, provided that such additional attribution notices cannot be construed 130 | as modifying the License. 131 | 132 | You may add Your own copyright statement to Your modifications and may provide 133 | additional or different license terms and conditions for use, reproduction, 134 | or distribution of Your modifications, or for any such Derivative Works as 135 | a whole, provided Your use, reproduction, and distribution of the Work otherwise 136 | complies with the conditions stated in this License. 137 | 138 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 139 | Contribution intentionally submitted for inclusion in the Work by You to the 140 | Licensor shall be under the terms and conditions of this License, without 141 | any additional terms or conditions. Notwithstanding the above, nothing herein 142 | shall supersede or modify the terms of any separate license agreement you 143 | may have executed with Licensor regarding such Contributions. 144 | 145 | 6. Trademarks. This License does not grant permission to use the trade names, 146 | trademarks, service marks, or product names of the Licensor, except as required 147 | for reasonable and customary use in describing the origin of the Work and 148 | reproducing the content of the NOTICE file. 149 | 150 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to 151 | in writing, Licensor provides the Work (and each Contributor provides its 152 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 153 | KIND, either express or implied, including, without limitation, any warranties 154 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR 155 | A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness 156 | of using or redistributing the Work and assume any risks associated with Your 157 | exercise of permissions under this License. 158 | 159 | 8. Limitation of Liability. In no event and under no legal theory, whether 160 | in tort (including negligence), contract, or otherwise, unless required by 161 | applicable law (such as deliberate and grossly negligent acts) or agreed to 162 | in writing, shall any Contributor be liable to You for damages, including 163 | any direct, indirect, special, incidental, or consequential damages of any 164 | character arising as a result of this License or out of the use or inability 165 | to use the Work (including but not limited to damages for loss of goodwill, 166 | work stoppage, computer failure or malfunction, or any and all other commercial 167 | damages or losses), even if such Contributor has been advised of the possibility 168 | of such damages. 169 | 170 | 9. Accepting Warranty or Additional Liability. While redistributing the Work 171 | or Derivative Works thereof, You may choose to offer, and charge a fee for, 172 | acceptance of support, warranty, indemnity, or other liability obligations 173 | and/or rights consistent with this License. However, in accepting such obligations, 174 | You may act only on Your own behalf and on Your sole responsibility, not on 175 | behalf of any other Contributor, and only if You agree to indemnify, defend, 176 | and hold each Contributor harmless for any liability incurred by, or claims 177 | asserted against, such Contributor by reason of your accepting any such warranty 178 | or additional liability. END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following boilerplate 183 | notice, with the fields enclosed by brackets "[]" replaced with your own identifying 184 | information. (Don't include the brackets!) The text should be enclosed in 185 | the appropriate comment syntax for the file format. We also recommend that 186 | a file or class name and description of purpose be included on the same "printed 187 | page" as the copyright notice for easier identification within third-party 188 | archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | 194 | you may not use this file except in compliance with the License. 195 | 196 | You may obtain a copy of the License at 197 | 198 | http://www.apache.org/licenses/LICENSE-2.0 199 | 200 | Unless required by applicable law or agreed to in writing, software 201 | 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | 204 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 205 | 206 | See the License for the specific language governing permissions and 207 | 208 | limitations under the License. 209 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES 4 | NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE 5 | AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION 6 | ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE 7 | OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS 8 | LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION 9 | OR WORKS PROVIDED HEREUNDER. 10 | 11 | Statement of Purpose 12 | 13 | The laws of most jurisdictions throughout the world automatically confer exclusive 14 | Copyright and Related Rights (defined below) upon the creator and subsequent 15 | owner(s) (each and all, an "owner") of an original work of authorship and/or 16 | a database (each, a "Work"). 17 | 18 | Certain owners wish to permanently relinquish those rights to a Work for the 19 | purpose of contributing to a commons of creative, cultural and scientific 20 | works ("Commons") that the public can reliably and without fear of later claims 21 | of infringement build upon, modify, incorporate in other works, reuse and 22 | redistribute as freely as possible in any form whatsoever and for any purposes, 23 | including without limitation commercial purposes. These owners may contribute 24 | to the Commons to promote the ideal of a free culture and the further production 25 | of creative, cultural and scientific works, or to gain reputation or greater 26 | distribution for their Work in part through the use and efforts of others. 27 | 28 | For these and/or other purposes and motivations, and without any expectation 29 | of additional consideration or compensation, the person associating CC0 with 30 | a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 31 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 32 | and publicly distribute the Work under its terms, with knowledge of his or 33 | her Copyright and Related Rights in the Work and the meaning and intended 34 | legal effect of CC0 on those rights. 35 | 36 | 1. Copyright and Related Rights. A Work made available under CC0 may be protected 37 | by copyright and related or neighboring rights ("Copyright and Related Rights"). 38 | Copyright and Related Rights include, but are not limited to, the following: 39 | 40 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 41 | and translate a Work; 42 | 43 | ii. moral rights retained by the original author(s) and/or performer(s); 44 | 45 | iii. publicity and privacy rights pertaining to a person's image or likeness 46 | depicted in a Work; 47 | 48 | iv. rights protecting against unfair competition in regards to a Work, subject 49 | to the limitations in paragraph 4(a), below; 50 | 51 | v. rights protecting the extraction, dissemination, use and reuse of data 52 | in a Work; 53 | 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal protection 56 | of databases, and under any national implementation thereof, including any 57 | amended or successor version of such directive); and 58 | 59 | vii. other similar, equivalent or corresponding rights throughout the world 60 | based on applicable law or treaty, and any national implementations thereof. 61 | 62 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 63 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 64 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 65 | and Related Rights and associated claims and causes of action, whether now 66 | known or unknown (including existing as well as future claims and causes of 67 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 68 | duration provided by applicable law or treaty (including future time extensions), 69 | (iii) in any current or future medium and for any number of copies, and (iv) 70 | for any purpose whatsoever, including without limitation commercial, advertising 71 | or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the 72 | benefit of each member of the public at large and to the detriment of Affirmer's 73 | heirs and successors, fully intending that such Waiver shall not be subject 74 | to revocation, rescission, cancellation, termination, or any other legal or 75 | equitable action to disrupt the quiet enjoyment of the Work by the public 76 | as contemplated by Affirmer's express Statement of Purpose. 77 | 78 | 3. Public License Fallback. Should any part of the Waiver for any reason be 79 | judged legally invalid or ineffective under applicable law, then the Waiver 80 | shall be preserved to the maximum extent permitted taking into account Affirmer's 81 | express Statement of Purpose. In addition, to the extent the Waiver is so 82 | judged Affirmer hereby grants to each affected person a royalty-free, non 83 | transferable, non sublicensable, non exclusive, irrevocable and unconditional 84 | license to exercise Affirmer's Copyright and Related Rights in the Work (i) 85 | in all territories worldwide, (ii) for the maximum duration provided by applicable 86 | law or treaty (including future time extensions), (iii) in any current or 87 | future medium and for any number of copies, and (iv) for any purpose whatsoever, 88 | including without limitation commercial, advertising or promotional purposes 89 | (the "License"). The License shall be deemed effective as of the date CC0 90 | was applied by Affirmer to the Work. Should any part of the License for any 91 | reason be judged legally invalid or ineffective under applicable law, such 92 | partial invalidity or ineffectiveness shall not invalidate the remainder of 93 | the License, and in such case Affirmer hereby affirms that he or she will 94 | not (i) exercise any of his or her remaining Copyright and Related Rights 95 | in the Work or (ii) assert any associated claims and causes of action with 96 | respect to the Work, in either case contrary to Affirmer's express Statement 97 | of Purpose. 98 | 99 | 4. Limitations and Disclaimers. 100 | 101 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, 102 | licensed or otherwise affected by this document. 103 | 104 | b. Affirmer offers the Work as-is and makes no representations or warranties 105 | of any kind concerning the Work, express, implied, statutory or otherwise, 106 | including without limitation warranties of title, merchantability, fitness 107 | for a particular purpose, non infringement, or the absence of latent or other 108 | defects, accuracy, or the present or absence of errors, whether or not discoverable, 109 | all to the greatest extent permissible under applicable law. 110 | 111 | c. Affirmer disclaims responsibility for clearing rights of other persons 112 | that may apply to the Work or any use thereof, including without limitation 113 | any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims 114 | responsibility for obtaining any necessary consents, permissions or other 115 | rights required for any use of the Work. 116 | 117 | d. Affirmer understands and acknowledges that Creative Commons is not a party 118 | to this document and has no duty or obligation with respect to this CC0 or 119 | use of the Work. 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker für alle 2 | 3 | **A workshop in several chapters, originally held by the Developer Experience team at SVT.** 4 | 5 | This workshop is for anyone who wishes to learn about docker and container management beyond copying and pasting from a guide somewhere on the internet. It is divided into multiple parts, but feel free to start at any point you feel is right for you. Some of the practical examples may depend on information presented earlier, in these cases we have tried to link back to the relevant information. 6 | 7 | ## Prerequisites 8 | 9 | You need a personal computer and a working Docker installation, as outlined in the [prerequisites chapter](0-prereqs/README.md). This workshop is written primarily with Mac and Linux users in mind and tested on those systems, but most things *should* work the same on Windows. 10 | 11 | ## Where to start 12 | 13 | If you are unsure about your skill level, start from [the very beginning](1-basics/README.md). It will not take you long to work through Chapter 1 if you have some previous experience, and you may still learn something new if you're lucky! We hope you enjoy your new docker skills. 14 | 15 | Otherwise, if you feel very comfortable with the basics already, just dive in at any point that looks interesting in the overview. 16 | 17 | ### Chapter overview 18 | 19 | * [Prerequisites](0-prereqs/README.md) - contains information and links that should get you a working docker installation. 20 | 21 | 1. [Basics](1-basics/README.md) - this chapter provides an overview of the basics of getting hold of docker images and running them locally. Start here if you have no previous experience at all. 22 | 2. [Dockerfiles](2-dockerfiles/README.md) - this chapter takes you through the process of writing Dockerfiles and building custom container images. Start here if you are already familiar with images and running containers but wish to understand more about how they are built and customized. 23 | 3. [Dynamic building](/3-dynamics/README.md) - an introduction to dynamically building and running images 24 | 4. [Multi-stage builds](/4-multi-stage-builds/README.md) - an overview of how to use multiple stages in your Dockerfile. Wow, you can build miniature pipelines now! 25 | 5. [Security](/5-security/README.md) - a guide to some common security risks inherent in using Docker, and how to mitigate them. 26 | 27 | ## Getting involved 28 | 29 | We welcome contributions as well as questions, suggestions, reports of non-working examples, other feedback and success stories. Please feel free to open an issue in the main repo at to start the conversation. Please try to keep contributions: 30 | 31 | * Accessible at the level specified 32 | * Free from secondary requirements (more than basic knowledge of any particular programming language, for example) 33 | * Tested on at least two platforms 34 | 35 | ---- 36 | 37 | ## Open source licensing info 38 | 39 | Creative Commons License
Workshop assets released under the Creative Commons Attribution-ShareAlike 4.0 International License: [CC-BY-SA 4.0](LICENSE) 40 | 41 | ---- 42 | 43 | ## Maintainers 44 | 45 | - Frida Hjelm 46 | - Alexander Bethke 47 | - Johan Grimlund 48 | 49 | ## Credits and references 50 | 51 | The DX:ers want to thank: 52 | - Everyone who participated in the original workshop 53 | - [Martin Flodin](https://github.com/mflodin) for suggesting an open source release of the material. 54 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | We think the Greek fabulist Aesop, c. 620 – 564 BCE, nailed it pretty good. 'No act of kindness, no matter how small, is ever wasted'. 2 | 3 | In other words, be nice to each other. 4 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | We gratefully accepts contributions via 4 | [pull requests](https://help.github.com/articles/about-pull-requests/). 5 | 6 | Use the issue tracker to suggest new content, report errors, and ask questions. 7 | This is also a great way to connect with the maintainers of the project as well 8 | as others who are interested in this workshop. 9 | 10 | ## Changing the content 11 | 12 | Generally speaking, you should fork this repository, make changes in your 13 | own fork, and then submit a pull-request. This is often called the [Fork-and-Pull model](https://gist.github.com/Chaser324/ce0505fbed06b947d962) 14 | 15 | * All contributions to this project will be released under the LICENSE. 16 | * By submitting a pull request or filing a bug, issue, or 17 | feature request, you are agreeing to comply with this waiver of copyright interest. 18 | Details can be found in the [LICENSE](../LICENSE). 19 | * All new content should be tested on at least two platforms. 20 | * Additionally, the content should mimic the styles 21 | and patterns in the existing content. 22 | 23 | ## Git History 24 | 25 | In order to maintain a high software quality standard, we strongly prefer contributions to follow these rules: 26 | 27 | - We pay more attention to the quality of commit messages. In general, we share the view on how commit messages should be written with 28 | [the Git project itself](https://github.com/git/git/blob/master/Documentation/SubmittingPatches): 29 | 30 | - [Make separate commits for logically separate changes.](https://github.com/git/git/blob/e6932248fcb41fb94a0be484050881e03c7eb298/Documentation/SubmittingPatches#L43) 31 | For example, pure formatting changes that do not affect software behavior usually do not belong in the same commit as 32 | changes to program logic. 33 | - [Describe your changes well.](https://github.com/git/git/blob/e6932248fcb41fb94a0be484050881e03c7eb298/Documentation/SubmittingPatches#L101) 34 | Do not just repeat in prose what is "obvious" from the code, but provide a rationale explaining *why* you believe 35 | your change is necessary. 36 | - [Describe your changes in the imperative.](https://github.com/git/git/blob/e6932248fcb41fb94a0be484050881e03c7eb298/Documentation/SubmittingPatches#L133) 37 | Instead of writing "Fixes an issue with encoding" prefer "Fix an encoding issue". Think about it like the commit 38 | only does something *if* it is applied. This usually results in more concise commit messages. 39 | - [We are picky about whitespaces.](https://github.com/git/git/blob/e6932248fcb41fb94a0be484050881e03c7eb298/Documentation/SubmittingPatches#L95) 40 | Trailing whitespace and duplicate blank lines are simply a superfluous annoyance, and most Git tools flag them red 41 | in the diff anyway. 42 | 43 | If you have ever wondered how a "perfect" commit message is supposed to look like, just look at basically any of 44 | [Jeff King's commits](https://github.com/git/git/commits?author=peff) in the Git project. 45 | 46 | - When addressing review comments in a pull request, please fix the issue in the commit where it appears, not in a new 47 | commit on top of the pull request's history. While this requires force-pushing of the new iteration of your pull 48 | request's branch, it has several advantages: 49 | 50 | - Reviewers that go through (larger) pull requests commit by commit are always up-to-date with latest fixes, instead 51 | of coming across a commit that addresses their remarks only at the end. 52 | - It maintains a cleaner history without distracting commits like "Address review comments". 53 | - As a result, tools like [git-bisect](https://git-scm.com/docs/git-bisect) can operate in a more meaningful way. 54 | - Fixing up commits allows for making fixes to commit messages, which is not possible by only adding new commits. 55 | 56 | If you are unfamiliar with fixing up existing commits, please read about [rewriting history](https://git-scm.com/book/id/v2/Git-Tools-Rewriting-History) 57 | and `git rebase --interactive` in particular. 58 | 59 | - To resolve conflicts, rebase pull request branches onto their target branch instead of merging the target branch into 60 | the pull request branch. This again results in a cleaner history without "criss-cross" merges. 61 | 62 | 63 | Thank you for reading and happy contributing! 64 | -------------------------------------------------------------------------------- /example-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest -------------------------------------------------------------------------------- /example-app/README.md: -------------------------------------------------------------------------------- 1 | # Example Gitbook App 2 | 3 | This is a gitbook project. Check out the [official documentation](https://toolchain.gitbook.com/) for more detatis. 4 | 5 | The content of the book is in the `./content` folder in this project. 6 | 7 | ### To edit and add in the project 8 | 9 | - SUMMARY.md is the left-side menu. Add the link to new pages to add to the menu. 10 | - Create and edit in the `./content` folder. This will automatically add it to the `_book` folder. 11 | 12 | To install the dependencies: 13 | 14 | ```bash 15 | npm install 16 | ``` 17 | 18 | Run the gitbook server at `localhost:4000` 19 | 20 | ```bash 21 | npm run serve 22 | ``` 23 | 24 | Build a static copy of the book: 25 | 26 | ```bash 27 | npm run build 28 | ``` 29 | 30 | Run a local debug version of the server: 31 | 32 | ```bash 33 | npm run debug 34 | ``` 35 | -------------------------------------------------------------------------------- /example-app/_book/animals/birds.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Birds · My Example Site 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 | 74 | 75 | 76 | 233 | 234 | 235 |
236 | 237 |
238 | 239 |
240 | 241 | 242 | 243 | 252 | 253 | 254 | 255 | 256 |
257 |
258 | 259 |
260 |
261 | 262 |
263 | 264 |

Birds

265 |

Birds are just fantastic. Now in yellow:

266 |

267 |

Photo by David Clode on Unsplash

268 | 269 | 270 |
271 | 272 |
273 |
274 |
275 | 276 |

results matching ""

277 |
    278 | 279 |
    280 |
    281 | 282 |

    No results matching ""

    283 | 284 |
    285 |
    286 |
    287 | 288 |
    289 |
    290 | 291 |
    292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 |
    303 | 304 | 310 |
    311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /example-app/_book/animals/cats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cats · My Example Site 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 | 74 | 75 | 76 | 233 | 234 | 235 |
    236 | 237 |
    238 | 239 |
    240 | 241 | 242 | 243 | 252 | 253 | 254 | 255 | 256 |
    257 |
    258 | 259 |
    260 |
    261 | 262 |
    263 | 264 |

    Cats

    265 |

    Cats are amazing. They come in different colours.

    266 |

    267 |

    Photos by Loan and Artistiq Dude on Unsplash

    268 | 269 | 270 |
    271 | 272 |
    273 |
    274 |
    275 | 276 |

    results matching ""

    277 |
      278 | 279 |
      280 |
      281 | 282 |

      No results matching ""

      283 | 284 |
      285 |
      286 |
      287 | 288 |
      289 |
      290 | 291 |
      292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 |
      303 | 304 | 310 |
      311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /example-app/_book/animals/dogs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dogs · My Example Site 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
      70 |
      71 | 72 | 73 | 76 | 77 | 78 | 235 | 236 | 237 |
      238 | 239 |
      240 | 241 |
      242 | 243 | 244 | 245 | 254 | 255 | 256 | 257 | 258 |
      259 |
      260 | 261 |
      262 |
      263 | 264 |
      265 | 266 |

      Dogs

      267 |

      Dogs are perfect. Look at this good boy.

      268 |

      269 |

      Photo by Stephen Andrews on Unsplash

      270 | 271 | 272 |
      273 | 274 |
      275 |
      276 |
      277 | 278 |

      results matching ""

      279 |
        280 | 281 |
        282 |
        283 | 284 |

        No results matching ""

        285 | 286 |
        287 |
        288 |
        289 | 290 |
        291 |
        292 | 293 |
        294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 |
        309 | 310 | 316 |
        317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | -------------------------------------------------------------------------------- /example-app/_book/animals/img/black-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/animals/img/black-cat.jpg -------------------------------------------------------------------------------- /example-app/_book/animals/img/good-boy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/animals/img/good-boy.jpg -------------------------------------------------------------------------------- /example-app/_book/animals/img/tabby-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/animals/img/tabby-cat.jpg -------------------------------------------------------------------------------- /example-app/_book/animals/img/yellow-bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/animals/img/yellow-bird.jpg -------------------------------------------------------------------------------- /example-app/_book/foods/fries.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | French fries · My Example Site 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 | 74 | 75 | 76 | 233 | 234 | 235 |
        236 | 237 |
        238 | 239 |
        240 | 241 | 242 | 243 | 252 | 253 | 254 | 255 | 256 |
        257 |
        258 | 259 |
        260 |
        261 | 262 |
        263 | 264 |

        French fries

        265 |

        French fries are made from potatoes. Contrary to popular belief, not all potatoes are french.

        266 |
          267 |
        • Great with ketchup
        • 268 |
        • Golden
        • 269 |
        • Delicious
        • 270 |
        271 | 272 | 273 |
        274 | 275 |
        276 |
        277 |
        278 | 279 |

        results matching ""

        280 |
          281 | 282 |
          283 |
          284 | 285 |

          No results matching ""

          286 | 287 |
          288 |
          289 |
          290 | 291 |
          292 |
          293 | 294 |
          295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 |
          306 | 307 | 313 |
          314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | -------------------------------------------------------------------------------- /example-app/_book/foods/pasta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Pasta · My Example Site 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
          70 |
          71 | 72 | 73 | 76 | 77 | 78 | 235 | 236 | 237 |
          238 | 239 |
          240 | 241 |
          242 | 243 | 244 | 245 | 254 | 255 | 256 | 257 | 258 |
          259 |
          260 | 261 |
          262 |
          263 | 264 |
          265 | 266 |

          Pasta

          267 |

          Pasta is very easy to make, only boil it in water.

          268 |
            269 |
          • Get your sauce on
          • 270 |
          271 | 272 | 273 |
          274 | 275 |
          276 |
          277 |
          278 | 279 |

          results matching ""

          280 |
            281 | 282 |
            283 |
            284 | 285 |

            No results matching ""

            286 | 287 |
            288 |
            289 |
            290 | 291 |
            292 |
            293 | 294 |
            295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 |
            310 | 311 | 317 |
            318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /example-app/_book/foods/tofu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tofu · My Example Site 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 | 74 | 75 | 76 | 233 | 234 | 235 |
            236 | 237 |
            238 | 239 |
            240 | 241 | 242 | 243 | 252 | 253 | 254 | 255 | 256 |
            257 |
            258 | 259 |
            260 |
            261 | 262 |
            263 | 264 |

            Tofu

            265 |

            It comes in many different forms: silky, firm, fried, and dried.

            266 |
              267 |
            • Food of the future
            • 268 |
            • Protein cubes
            • 269 |
            • Very soy
            • 270 |
            271 | 272 | 273 |
            274 | 275 |
            276 |
            277 |
            278 | 279 |

            results matching ""

            280 |
              281 | 282 |
              283 |
              284 | 285 |

              No results matching ""

              286 | 287 |
              288 |
              289 |
              290 | 291 |
              292 |
              293 | 294 |
              295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 |
              306 | 307 | 313 |
              314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/fonts/fontawesome/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/fonts/fontawesome/FontAwesome.otf -------------------------------------------------------------------------------- /example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.eot -------------------------------------------------------------------------------- /example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff -------------------------------------------------------------------------------- /example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-anchorjs/anchor-style.js: -------------------------------------------------------------------------------- 1 | gitbook.events.bind('start', function(e, config) { 2 | anchors.options = config.anchorjs || {}; 3 | }); 4 | 5 | gitbook.events.bind('page.change', function() { 6 | anchors.add(anchors.options.selector || 'h2,h3,h4,h5'); 7 | }); 8 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-anchorjs/anchor.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AnchorJS - v4.1.1 - 2018-07-01 3 | * https://github.com/bryanbraun/anchorjs 4 | * Copyright (c) 2018 Bryan Braun; Licensed MIT 5 | */ 6 | !function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";return function(A){function d(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.ariaLabel=A.hasOwnProperty("ariaLabel")?A.ariaLabel:"Anchor",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function f(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],d(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var e,t,i,n,o,s,r,a,c,h,l,u=[];if(d(this.options),"touch"===(l=this.options.visible)&&(l=this.isTouchDevice()?"always":"hover"),A||(A="h2, h3, h4, h5, h6"),0===(e=f(A)).length)return this;for(function(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style");e.className="anchorjs",e.appendChild(document.createTextNode("")),void 0===(A=document.head.querySelector('[rel="stylesheet"], style'))?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",e.sheet.cssRules.length),e.sheet.insertRule(" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",e.sheet.cssRules.length),e.sheet.insertRule(" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }",e.sheet.cssRules.length),e.sheet.insertRule(' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',e.sheet.cssRules.length)}}(),t=document.querySelectorAll("[id]"),i=[].map.call(t,function(A){return A.id}),o=0;o\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),t=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||t||!1}}}); -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-fontsettings/fontsettings.js: -------------------------------------------------------------------------------- 1 | require(['gitbook', 'jquery'], function(gitbook, $) { 2 | // Configuration 3 | var MAX_SIZE = 4, 4 | MIN_SIZE = 0, 5 | BUTTON_ID; 6 | 7 | // Current fontsettings state 8 | var fontState; 9 | 10 | // Default themes 11 | var THEMES = [ 12 | { 13 | config: 'white', 14 | text: 'White', 15 | id: 0 16 | }, 17 | { 18 | config: 'sepia', 19 | text: 'Sepia', 20 | id: 1 21 | }, 22 | { 23 | config: 'night', 24 | text: 'Night', 25 | id: 2 26 | } 27 | ]; 28 | 29 | // Default font families 30 | var FAMILIES = [ 31 | { 32 | config: 'serif', 33 | text: 'Serif', 34 | id: 0 35 | }, 36 | { 37 | config: 'sans', 38 | text: 'Sans', 39 | id: 1 40 | } 41 | ]; 42 | 43 | // Return configured themes 44 | function getThemes() { 45 | return THEMES; 46 | } 47 | 48 | // Modify configured themes 49 | function setThemes(themes) { 50 | THEMES = themes; 51 | updateButtons(); 52 | } 53 | 54 | // Return configured font families 55 | function getFamilies() { 56 | return FAMILIES; 57 | } 58 | 59 | // Modify configured font families 60 | function setFamilies(families) { 61 | FAMILIES = families; 62 | updateButtons(); 63 | } 64 | 65 | // Save current font settings 66 | function saveFontSettings() { 67 | gitbook.storage.set('fontState', fontState); 68 | update(); 69 | } 70 | 71 | // Increase font size 72 | function enlargeFontSize(e) { 73 | e.preventDefault(); 74 | if (fontState.size >= MAX_SIZE) return; 75 | 76 | fontState.size++; 77 | saveFontSettings(); 78 | } 79 | 80 | // Decrease font size 81 | function reduceFontSize(e) { 82 | e.preventDefault(); 83 | if (fontState.size <= MIN_SIZE) return; 84 | 85 | fontState.size--; 86 | saveFontSettings(); 87 | } 88 | 89 | // Change font family 90 | function changeFontFamily(configName, e) { 91 | if (e && e instanceof Event) { 92 | e.preventDefault(); 93 | } 94 | 95 | var familyId = getFontFamilyId(configName); 96 | fontState.family = familyId; 97 | saveFontSettings(); 98 | } 99 | 100 | // Change type of color theme 101 | function changeColorTheme(configName, e) { 102 | if (e && e instanceof Event) { 103 | e.preventDefault(); 104 | } 105 | 106 | var $book = gitbook.state.$book; 107 | 108 | // Remove currently applied color theme 109 | if (fontState.theme !== 0) 110 | $book.removeClass('color-theme-'+fontState.theme); 111 | 112 | // Set new color theme 113 | var themeId = getThemeId(configName); 114 | fontState.theme = themeId; 115 | if (fontState.theme !== 0) 116 | $book.addClass('color-theme-'+fontState.theme); 117 | 118 | saveFontSettings(); 119 | } 120 | 121 | // Return the correct id for a font-family config key 122 | // Default to first font-family 123 | function getFontFamilyId(configName) { 124 | // Search for plugin configured font family 125 | var configFamily = $.grep(FAMILIES, function(family) { 126 | return family.config == configName; 127 | })[0]; 128 | // Fallback to default font family 129 | return (!!configFamily)? configFamily.id : 0; 130 | } 131 | 132 | // Return the correct id for a theme config key 133 | // Default to first theme 134 | function getThemeId(configName) { 135 | // Search for plugin configured theme 136 | var configTheme = $.grep(THEMES, function(theme) { 137 | return theme.config == configName; 138 | })[0]; 139 | // Fallback to default theme 140 | return (!!configTheme)? configTheme.id : 0; 141 | } 142 | 143 | function update() { 144 | var $book = gitbook.state.$book; 145 | 146 | $('.font-settings .font-family-list li').removeClass('active'); 147 | $('.font-settings .font-family-list li:nth-child('+(fontState.family+1)+')').addClass('active'); 148 | 149 | $book[0].className = $book[0].className.replace(/\bfont-\S+/g, ''); 150 | $book.addClass('font-size-'+fontState.size); 151 | $book.addClass('font-family-'+fontState.family); 152 | 153 | if(fontState.theme !== 0) { 154 | $book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, ''); 155 | $book.addClass('color-theme-'+fontState.theme); 156 | } 157 | } 158 | 159 | function init(config) { 160 | // Search for plugin configured font family 161 | var configFamily = getFontFamilyId(config.family), 162 | configTheme = getThemeId(config.theme); 163 | 164 | // Instantiate font state object 165 | fontState = gitbook.storage.get('fontState', { 166 | size: config.size || 2, 167 | family: configFamily, 168 | theme: configTheme 169 | }); 170 | 171 | update(); 172 | } 173 | 174 | function updateButtons() { 175 | // Remove existing fontsettings buttons 176 | if (!!BUTTON_ID) { 177 | gitbook.toolbar.removeButton(BUTTON_ID); 178 | } 179 | 180 | // Create buttons in toolbar 181 | BUTTON_ID = gitbook.toolbar.createButton({ 182 | icon: 'fa fa-font', 183 | label: 'Font Settings', 184 | className: 'font-settings', 185 | dropdown: [ 186 | [ 187 | { 188 | text: 'A', 189 | className: 'font-reduce', 190 | onClick: reduceFontSize 191 | }, 192 | { 193 | text: 'A', 194 | className: 'font-enlarge', 195 | onClick: enlargeFontSize 196 | } 197 | ], 198 | $.map(FAMILIES, function(family) { 199 | family.onClick = function(e) { 200 | return changeFontFamily(family.config, e); 201 | }; 202 | 203 | return family; 204 | }), 205 | $.map(THEMES, function(theme) { 206 | theme.onClick = function(e) { 207 | return changeColorTheme(theme.config, e); 208 | }; 209 | 210 | return theme; 211 | }) 212 | ] 213 | }); 214 | } 215 | 216 | // Init configuration at start 217 | gitbook.events.bind('start', function(e, config) { 218 | var opts = config.fontsettings; 219 | 220 | // Generate buttons at start 221 | updateButtons(); 222 | 223 | // Init current settings 224 | init(opts); 225 | }); 226 | 227 | // Expose API 228 | gitbook.fontsettings = { 229 | enlargeFontSize: enlargeFontSize, 230 | reduceFontSize: reduceFontSize, 231 | setTheme: changeColorTheme, 232 | setFamily: changeFontFamily, 233 | getThemes: getThemes, 234 | setThemes: setThemes, 235 | getFamilies: getFamilies, 236 | setFamilies: setFamilies 237 | }; 238 | }); 239 | 240 | 241 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-fontsettings/website.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Theme 1 3 | */ 4 | .color-theme-1 .dropdown-menu { 5 | background-color: #111111; 6 | border-color: #7e888b; 7 | } 8 | .color-theme-1 .dropdown-menu .dropdown-caret .caret-inner { 9 | border-bottom: 9px solid #111111; 10 | } 11 | .color-theme-1 .dropdown-menu .buttons { 12 | border-color: #7e888b; 13 | } 14 | .color-theme-1 .dropdown-menu .button { 15 | color: #afa790; 16 | } 17 | .color-theme-1 .dropdown-menu .button:hover { 18 | color: #73553c; 19 | } 20 | /* 21 | * Theme 2 22 | */ 23 | .color-theme-2 .dropdown-menu { 24 | background-color: #2d3143; 25 | border-color: #272a3a; 26 | } 27 | .color-theme-2 .dropdown-menu .dropdown-caret .caret-inner { 28 | border-bottom: 9px solid #2d3143; 29 | } 30 | .color-theme-2 .dropdown-menu .buttons { 31 | border-color: #272a3a; 32 | } 33 | .color-theme-2 .dropdown-menu .button { 34 | color: #62677f; 35 | } 36 | .color-theme-2 .dropdown-menu .button:hover { 37 | color: #f4f4f5; 38 | } 39 | .book .book-header .font-settings .font-enlarge { 40 | line-height: 30px; 41 | font-size: 1.4em; 42 | } 43 | .book .book-header .font-settings .font-reduce { 44 | line-height: 30px; 45 | font-size: 1em; 46 | } 47 | .book.color-theme-1 .book-body { 48 | color: #704214; 49 | background: #f3eacb; 50 | } 51 | .book.color-theme-1 .book-body .page-wrapper .page-inner section { 52 | background: #f3eacb; 53 | } 54 | .book.color-theme-2 .book-body { 55 | color: #bdcadb; 56 | background: #1c1f2b; 57 | } 58 | .book.color-theme-2 .book-body .page-wrapper .page-inner section { 59 | background: #1c1f2b; 60 | } 61 | .book.font-size-0 .book-body .page-inner section { 62 | font-size: 1.2rem; 63 | } 64 | .book.font-size-1 .book-body .page-inner section { 65 | font-size: 1.4rem; 66 | } 67 | .book.font-size-2 .book-body .page-inner section { 68 | font-size: 1.6rem; 69 | } 70 | .book.font-size-3 .book-body .page-inner section { 71 | font-size: 2.2rem; 72 | } 73 | .book.font-size-4 .book-body .page-inner section { 74 | font-size: 4rem; 75 | } 76 | .book.font-family-0 { 77 | font-family: Georgia, serif; 78 | } 79 | .book.font-family-1 { 80 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 81 | } 82 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal { 83 | color: #704214; 84 | } 85 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal a { 86 | color: inherit; 87 | } 88 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, 89 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2, 90 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h3, 91 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h4, 92 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h5, 93 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { 94 | color: inherit; 95 | } 96 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1, 97 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2 { 98 | border-color: inherit; 99 | } 100 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 { 101 | color: inherit; 102 | } 103 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal hr { 104 | background-color: inherit; 105 | } 106 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal blockquote { 107 | border-color: inherit; 108 | } 109 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre, 110 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code { 111 | background: #fdf6e3; 112 | color: #657b83; 113 | border-color: #f8df9c; 114 | } 115 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal .highlight { 116 | background-color: inherit; 117 | } 118 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table th, 119 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table td { 120 | border-color: #f5d06c; 121 | } 122 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr { 123 | color: inherit; 124 | background-color: #fdf6e3; 125 | border-color: #444444; 126 | } 127 | .book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { 128 | background-color: #fbeecb; 129 | } 130 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal { 131 | color: #bdcadb; 132 | } 133 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal a { 134 | color: #3eb1d0; 135 | } 136 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, 137 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2, 138 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h3, 139 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h4, 140 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h5, 141 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { 142 | color: #fffffa; 143 | } 144 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1, 145 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2 { 146 | border-color: #373b4e; 147 | } 148 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 { 149 | color: #373b4e; 150 | } 151 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal hr { 152 | background-color: #373b4e; 153 | } 154 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal blockquote { 155 | border-color: #373b4e; 156 | } 157 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre, 158 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code { 159 | color: #9dbed8; 160 | background: #2d3143; 161 | border-color: #2d3143; 162 | } 163 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal .highlight { 164 | background-color: #282a39; 165 | } 166 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table th, 167 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table td { 168 | border-color: #3b3f54; 169 | } 170 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr { 171 | color: #b6c2d2; 172 | background-color: #2d3143; 173 | border-color: #3b3f54; 174 | } 175 | .book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) { 176 | background-color: #35394b; 177 | } 178 | .book.color-theme-1 .book-header { 179 | color: #afa790; 180 | background: transparent; 181 | } 182 | .book.color-theme-1 .book-header .btn { 183 | color: #afa790; 184 | } 185 | .book.color-theme-1 .book-header .btn:hover { 186 | color: #73553c; 187 | background: none; 188 | } 189 | .book.color-theme-1 .book-header h1 { 190 | color: #704214; 191 | } 192 | .book.color-theme-2 .book-header { 193 | color: #7e888b; 194 | background: transparent; 195 | } 196 | .book.color-theme-2 .book-header .btn { 197 | color: #3b3f54; 198 | } 199 | .book.color-theme-2 .book-header .btn:hover { 200 | color: #fffff5; 201 | background: none; 202 | } 203 | .book.color-theme-2 .book-header h1 { 204 | color: #bdcadb; 205 | } 206 | .book.color-theme-1 .book-body .navigation { 207 | color: #afa790; 208 | } 209 | .book.color-theme-1 .book-body .navigation:hover { 210 | color: #73553c; 211 | } 212 | .book.color-theme-2 .book-body .navigation { 213 | color: #383f52; 214 | } 215 | .book.color-theme-2 .book-body .navigation:hover { 216 | color: #fffff5; 217 | } 218 | /* 219 | * Theme 1 220 | */ 221 | .book.color-theme-1 .book-summary { 222 | color: #afa790; 223 | background: #111111; 224 | border-right: 1px solid rgba(0, 0, 0, 0.07); 225 | } 226 | .book.color-theme-1 .book-summary .book-search { 227 | background: transparent; 228 | } 229 | .book.color-theme-1 .book-summary .book-search input, 230 | .book.color-theme-1 .book-summary .book-search input:focus { 231 | border: 1px solid transparent; 232 | } 233 | .book.color-theme-1 .book-summary ul.summary li.divider { 234 | background: #7e888b; 235 | box-shadow: none; 236 | } 237 | .book.color-theme-1 .book-summary ul.summary li i.fa-check { 238 | color: #33cc33; 239 | } 240 | .book.color-theme-1 .book-summary ul.summary li.done > a { 241 | color: #877f6a; 242 | } 243 | .book.color-theme-1 .book-summary ul.summary li a, 244 | .book.color-theme-1 .book-summary ul.summary li span { 245 | color: #877f6a; 246 | background: transparent; 247 | font-weight: normal; 248 | } 249 | .book.color-theme-1 .book-summary ul.summary li.active > a, 250 | .book.color-theme-1 .book-summary ul.summary li a:hover { 251 | color: #704214; 252 | background: transparent; 253 | font-weight: normal; 254 | } 255 | /* 256 | * Theme 2 257 | */ 258 | .book.color-theme-2 .book-summary { 259 | color: #bcc1d2; 260 | background: #2d3143; 261 | border-right: none; 262 | } 263 | .book.color-theme-2 .book-summary .book-search { 264 | background: transparent; 265 | } 266 | .book.color-theme-2 .book-summary .book-search input, 267 | .book.color-theme-2 .book-summary .book-search input:focus { 268 | border: 1px solid transparent; 269 | } 270 | .book.color-theme-2 .book-summary ul.summary li.divider { 271 | background: #272a3a; 272 | box-shadow: none; 273 | } 274 | .book.color-theme-2 .book-summary ul.summary li i.fa-check { 275 | color: #33cc33; 276 | } 277 | .book.color-theme-2 .book-summary ul.summary li.done > a { 278 | color: #62687f; 279 | } 280 | .book.color-theme-2 .book-summary ul.summary li a, 281 | .book.color-theme-2 .book-summary ul.summary li span { 282 | color: #c1c6d7; 283 | background: transparent; 284 | font-weight: 600; 285 | } 286 | .book.color-theme-2 .book-summary ul.summary li.active > a, 287 | .book.color-theme-2 .book-summary ul.summary li a:hover { 288 | color: #f4f4f5; 289 | background: #252737; 290 | font-weight: 600; 291 | } 292 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-highlight/ebook.css: -------------------------------------------------------------------------------- 1 | pre, 2 | code { 3 | /* http://jmblog.github.io/color-themes-for-highlightjs */ 4 | /* Tomorrow Comment */ 5 | /* Tomorrow Red */ 6 | /* Tomorrow Orange */ 7 | /* Tomorrow Yellow */ 8 | /* Tomorrow Green */ 9 | /* Tomorrow Aqua */ 10 | /* Tomorrow Blue */ 11 | /* Tomorrow Purple */ 12 | } 13 | pre .hljs-comment, 14 | code .hljs-comment, 15 | pre .hljs-title, 16 | code .hljs-title { 17 | color: #8e908c; 18 | } 19 | pre .hljs-variable, 20 | code .hljs-variable, 21 | pre .hljs-attribute, 22 | code .hljs-attribute, 23 | pre .hljs-tag, 24 | code .hljs-tag, 25 | pre .hljs-regexp, 26 | code .hljs-regexp, 27 | pre .hljs-deletion, 28 | code .hljs-deletion, 29 | pre .ruby .hljs-constant, 30 | code .ruby .hljs-constant, 31 | pre .xml .hljs-tag .hljs-title, 32 | code .xml .hljs-tag .hljs-title, 33 | pre .xml .hljs-pi, 34 | code .xml .hljs-pi, 35 | pre .xml .hljs-doctype, 36 | code .xml .hljs-doctype, 37 | pre .html .hljs-doctype, 38 | code .html .hljs-doctype, 39 | pre .css .hljs-id, 40 | code .css .hljs-id, 41 | pre .css .hljs-class, 42 | code .css .hljs-class, 43 | pre .css .hljs-pseudo, 44 | code .css .hljs-pseudo { 45 | color: #c82829; 46 | } 47 | pre .hljs-number, 48 | code .hljs-number, 49 | pre .hljs-preprocessor, 50 | code .hljs-preprocessor, 51 | pre .hljs-pragma, 52 | code .hljs-pragma, 53 | pre .hljs-built_in, 54 | code .hljs-built_in, 55 | pre .hljs-literal, 56 | code .hljs-literal, 57 | pre .hljs-params, 58 | code .hljs-params, 59 | pre .hljs-constant, 60 | code .hljs-constant { 61 | color: #f5871f; 62 | } 63 | pre .ruby .hljs-class .hljs-title, 64 | code .ruby .hljs-class .hljs-title, 65 | pre .css .hljs-rules .hljs-attribute, 66 | code .css .hljs-rules .hljs-attribute { 67 | color: #eab700; 68 | } 69 | pre .hljs-string, 70 | code .hljs-string, 71 | pre .hljs-value, 72 | code .hljs-value, 73 | pre .hljs-inheritance, 74 | code .hljs-inheritance, 75 | pre .hljs-header, 76 | code .hljs-header, 77 | pre .hljs-addition, 78 | code .hljs-addition, 79 | pre .ruby .hljs-symbol, 80 | code .ruby .hljs-symbol, 81 | pre .xml .hljs-cdata, 82 | code .xml .hljs-cdata { 83 | color: #718c00; 84 | } 85 | pre .css .hljs-hexcolor, 86 | code .css .hljs-hexcolor { 87 | color: #3e999f; 88 | } 89 | pre .hljs-function, 90 | code .hljs-function, 91 | pre .python .hljs-decorator, 92 | code .python .hljs-decorator, 93 | pre .python .hljs-title, 94 | code .python .hljs-title, 95 | pre .ruby .hljs-function .hljs-title, 96 | code .ruby .hljs-function .hljs-title, 97 | pre .ruby .hljs-title .hljs-keyword, 98 | code .ruby .hljs-title .hljs-keyword, 99 | pre .perl .hljs-sub, 100 | code .perl .hljs-sub, 101 | pre .javascript .hljs-title, 102 | code .javascript .hljs-title, 103 | pre .coffeescript .hljs-title, 104 | code .coffeescript .hljs-title { 105 | color: #4271ae; 106 | } 107 | pre .hljs-keyword, 108 | code .hljs-keyword, 109 | pre .javascript .hljs-function, 110 | code .javascript .hljs-function { 111 | color: #8959a8; 112 | } 113 | pre .hljs, 114 | code .hljs { 115 | display: block; 116 | background: white; 117 | color: #4d4d4c; 118 | padding: 0.5em; 119 | } 120 | pre .coffeescript .javascript, 121 | code .coffeescript .javascript, 122 | pre .javascript .xml, 123 | code .javascript .xml, 124 | pre .tex .hljs-formula, 125 | code .tex .hljs-formula, 126 | pre .xml .javascript, 127 | code .xml .javascript, 128 | pre .xml .vbscript, 129 | code .xml .vbscript, 130 | pre .xml .css, 131 | code .xml .css, 132 | pre .xml .hljs-cdata, 133 | code .xml .hljs-cdata { 134 | opacity: 0.5; 135 | } 136 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-livereload/plugin.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var newEl = document.createElement('script'), 3 | firstScriptTag = document.getElementsByTagName('script')[0]; 4 | 5 | if (firstScriptTag) { 6 | newEl.async = 1; 7 | newEl.src = '//' + window.location.hostname + ':35729/livereload.js'; 8 | firstScriptTag.parentNode.insertBefore(newEl, firstScriptTag); 9 | } 10 | 11 | })(); 12 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-lunr/lunr.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.5.12 3 | * Copyright (C) 2015 Oliver Nightingale 4 | * MIT Licensed 5 | * @license 6 | */ 7 | !function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.5.12",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(t){return arguments.length&&null!=t&&void 0!=t?Array.isArray(t)?t.map(function(t){return t.toLowerCase()}):t.toString().trim().toLowerCase().split(/[\s\-]+/):[]},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,o=0;n>o;o++){for(var r=t[o],s=0;i>s&&(r=this._stack[s](r,o,t),void 0!==r);s++);void 0!==r&&e.push(r)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(r===t)return o;t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o]}return r===t?o:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,o=e+Math.floor(i/2),r=this.elements[o];i>1;)t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o];return r>t?o:t>r?o+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,o=0,r=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>r-1||o>s-1)break;a[i]!==h[o]?a[i]h[o]&&o++:(n.add(a[i]),i++,o++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;return this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone(),i.add.apply(i,n.toArray()),i},t.SortedSet.prototype.toJSON=function(){return this.toArray()},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.Store,this.tokenStore=new t.TokenStore,this.corpusTokens=new t.SortedSet,this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var t=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,t)},t.Index.prototype.off=function(t,e){return this.eventEmitter.removeListener(t,e)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;return n._fields=e.fields,n._ref=e.ref,n.documentStore=t.Store.load(e.documentStore),n.tokenStore=t.TokenStore.load(e.tokenStore),n.corpusTokens=t.SortedSet.load(e.corpusTokens),n.pipeline=t.Pipeline.load(e.pipeline),n},t.Index.prototype.field=function(t,e){var e=e||{},n={name:t,boost:e.boost||1};return this._fields.push(n),this},t.Index.prototype.ref=function(t){return this._ref=t,this},t.Index.prototype.add=function(e,n){var i={},o=new t.SortedSet,r=e[this._ref],n=void 0===n?!0:n;this._fields.forEach(function(n){var r=this.pipeline.run(t.tokenizer(e[n.name]));i[n.name]=r,t.SortedSet.prototype.add.apply(o,r)},this),this.documentStore.set(r,o),t.SortedSet.prototype.add.apply(this.corpusTokens,o.toArray());for(var s=0;s0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(t.tokenizer(e)),i=new t.Vector,o=[],r=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*r,h=this,l=this.tokenStore.expand(e).reduce(function(n,o){var r=h.corpusTokens.indexOf(o),s=h.idf(o),l=1,u=new t.SortedSet;if(o!==e){var c=Math.max(3,o.length-e.length);l=1/Math.log(c)}return r>-1&&i.insert(r,a*s*l),Object.keys(h.tokenStore.get(o)).forEach(function(t){u.add(t)}),n.union(u)},new t.SortedSet);o.push(l)},this);var a=o.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,o=new t.Vector,r=0;i>r;r++){var s=n.elements[r],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);o.insert(this.corpusTokens.indexOf(s),a*h)}return o},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,a="^("+o+")?"+r+o+"("+r+")?$",h="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,u=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(l),p=/^(.+?)(ss|i)es$/,m=/^(.+?)([^s])s$/,v=/^(.+?)eed$/,y=/^(.+?)(ed|ing)$/,g=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),x=new RegExp("^"+o+i+"[^aeiouwxy]$"),k=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,_=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,O=/^(.+?)e$/,P=/ll$/,N=new RegExp("^"+o+i+"[^aeiouwxy]$"),T=function(n){var i,o,r,s,a,h,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,a=m,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=v,a=y,s.test(n)){var T=s.exec(n);s=u,s.test(T[1])&&(s=g,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,l=x,a.test(n)?n+="e":h.test(n)?(s=g,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=k,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+t[o])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+e[o])}if(s=_,a=F,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=O,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=N,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=P,a=c,s.test(n)&&a.test(n)&&(s=g,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==e?e:void 0},t.stopWordFilter.stopWords={a:"a",able:"able",about:"about",across:"across",after:"after",all:"all",almost:"almost",also:"also",am:"am",among:"among",an:"an",and:"and",any:"any",are:"are",as:"as",at:"at",be:"be",because:"because",been:"been",but:"but",by:"by",can:"can",cannot:"cannot",could:"could",dear:"dear",did:"did","do":"do",does:"does",either:"either","else":"else",ever:"ever",every:"every","for":"for",from:"from",get:"get",got:"got",had:"had",has:"has",have:"have",he:"he",her:"her",hers:"hers",him:"him",his:"his",how:"how",however:"however",i:"i","if":"if","in":"in",into:"into",is:"is",it:"it",its:"its",just:"just",least:"least",let:"let",like:"like",likely:"likely",may:"may",me:"me",might:"might",most:"most",must:"must",my:"my",neither:"neither",no:"no",nor:"nor",not:"not",of:"of",off:"off",often:"often",on:"on",only:"only",or:"or",other:"other",our:"our",own:"own",rather:"rather",said:"said",say:"say",says:"says",she:"she",should:"should",since:"since",so:"so",some:"some",than:"than",that:"that",the:"the",their:"their",them:"them",then:"then",there:"there",these:"these",they:"they","this":"this",tis:"tis",to:"to",too:"too",twas:"twas",us:"us",wants:"wants",was:"was",we:"we",were:"were",what:"what",when:"when",where:"where",which:"which","while":"while",who:"who",whom:"whom",why:"why",will:"will","with":"with",would:"would",yet:"yet",you:"you",your:"your"},t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){var e=t.replace(/^\W+/,"").replace(/\W+$/,"");return""===e?void 0:e},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t[0],o=t.slice(1);return i in n||(n[i]={docs:{}}),0===o.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(o,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;no;o++){for(var r=t[o],s=0;i>s&&(r=this._stack[s](r,o,t),void 0!==r);s++);void 0!==r&&e.push(r)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(r===t)return o;t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o]}return r===t?o:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,o=e+Math.floor(i/2),r=this.elements[o];i>1;)t>r&&(e=o),r>t&&(n=o),i=n-e,o=e+Math.floor(i/2),r=this.elements[o];return r>t?o:t>r?o+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,o=0,r=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>r-1||o>s-1)break;a[i]!==h[o]?a[i]h[o]&&o++:(n.add(a[i]),i++,o++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;return this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone(),i.add.apply(i,n.toArray()),i},t.SortedSet.prototype.toJSON=function(){return this.toArray()},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.Store,this.tokenStore=new t.TokenStore,this.corpusTokens=new t.SortedSet,this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var t=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,t)},t.Index.prototype.off=function(t,e){return this.eventEmitter.removeListener(t,e)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;return n._fields=e.fields,n._ref=e.ref,n.documentStore=t.Store.load(e.documentStore),n.tokenStore=t.TokenStore.load(e.tokenStore),n.corpusTokens=t.SortedSet.load(e.corpusTokens),n.pipeline=t.Pipeline.load(e.pipeline),n},t.Index.prototype.field=function(t,e){var e=e||{},n={name:t,boost:e.boost||1};return this._fields.push(n),this},t.Index.prototype.ref=function(t){return this._ref=t,this},t.Index.prototype.add=function(e,n){var i={},o=new t.SortedSet,r=e[this._ref],n=void 0===n?!0:n;this._fields.forEach(function(n){var r=this.pipeline.run(t.tokenizer(e[n.name]));i[n.name]=r,t.SortedSet.prototype.add.apply(o,r)},this),this.documentStore.set(r,o),t.SortedSet.prototype.add.apply(this.corpusTokens,o.toArray());for(var s=0;s0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(t.tokenizer(e)),i=new t.Vector,o=[],r=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*r,h=this,l=this.tokenStore.expand(e).reduce(function(n,o){var r=h.corpusTokens.indexOf(o),s=h.idf(o),l=1,u=new t.SortedSet;if(o!==e){var c=Math.max(3,o.length-e.length);l=1/Math.log(c)}return r>-1&&i.insert(r,a*s*l),Object.keys(h.tokenStore.get(o)).forEach(function(t){u.add(t)}),n.union(u)},new t.SortedSet);o.push(l)},this);var a=o.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,o=new t.Vector,r=0;i>r;r++){var s=n.elements[r],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);o.insert(this.corpusTokens.indexOf(s),a*h)}return o},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,a="^("+o+")?"+r+o+"("+r+")?$",h="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,u=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(l),p=/^(.+?)(ss|i)es$/,m=/^(.+?)([^s])s$/,v=/^(.+?)eed$/,y=/^(.+?)(ed|ing)$/,g=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),x=new RegExp("^"+o+i+"[^aeiouwxy]$"),k=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,_=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,O=/^(.+?)e$/,P=/ll$/,N=new RegExp("^"+o+i+"[^aeiouwxy]$"),T=function(n){var i,o,r,s,a,h,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,a=m,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=v,a=y,s.test(n)){var T=s.exec(n);s=u,s.test(T[1])&&(s=g,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,l=x,a.test(n)?n+="e":h.test(n)?(s=g,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=k,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+t[o])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],o=T[2],s=u,s.test(i)&&(n=i+e[o])}if(s=_,a=F,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=O,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=N,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=P,a=c,s.test(n)&&a.test(n)&&(s=g,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==e?e:void 0},t.stopWordFilter.stopWords={a:"a",able:"able",about:"about",across:"across",after:"after",all:"all",almost:"almost",also:"also",am:"am",among:"among",an:"an",and:"and",any:"any",are:"are",as:"as",at:"at",be:"be",because:"because",been:"been",but:"but",by:"by",can:"can",cannot:"cannot",could:"could",dear:"dear",did:"did","do":"do",does:"does",either:"either","else":"else",ever:"ever",every:"every","for":"for",from:"from",get:"get",got:"got",had:"had",has:"has",have:"have",he:"he",her:"her",hers:"hers",him:"him",his:"his",how:"how",however:"however",i:"i","if":"if","in":"in",into:"into",is:"is",it:"it",its:"its",just:"just",least:"least",let:"let",like:"like",likely:"likely",may:"may",me:"me",might:"might",most:"most",must:"must",my:"my",neither:"neither",no:"no",nor:"nor",not:"not",of:"of",off:"off",often:"often",on:"on",only:"only",or:"or",other:"other",our:"our",own:"own",rather:"rather",said:"said",say:"say",says:"says",she:"she",should:"should",since:"since",so:"so",some:"some",than:"than",that:"that",the:"the",their:"their",them:"them",then:"then",there:"there",these:"these",they:"they","this":"this",tis:"tis",to:"to",too:"too",twas:"twas",us:"us",wants:"wants",was:"was",we:"we",were:"were",what:"what",when:"when",where:"where",which:"which","while":"while",who:"who",whom:"whom",why:"why",will:"will","with":"with",would:"would",yet:"yet",you:"you",your:"your"},t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){var e=t.replace(/^\W+/,"").replace(/\W+$/,"");return""===e?void 0:e},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t[0],o=t.slice(1);return i in n||(n[i]={docs:{}}),0===o.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(o,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n element for each result 48 | res.results.forEach(function(res) { 49 | var $li = $('
            • ', { 50 | 'class': 'search-results-item' 51 | }); 52 | 53 | var $title = $('

              '); 54 | 55 | var $link = $('', { 56 | 'href': gitbook.state.basePath + '/' + res.url, 57 | 'text': res.title 58 | }); 59 | 60 | var content = res.body.trim(); 61 | if (content.length > MAX_DESCRIPTION_SIZE) { 62 | content = content.slice(0, MAX_DESCRIPTION_SIZE).trim()+'...'; 63 | } 64 | var $content = $('

              ').html(content); 65 | 66 | $link.appendTo($title); 67 | $title.appendTo($li); 68 | $content.appendTo($li); 69 | $li.appendTo($searchList); 70 | }); 71 | } 72 | 73 | function launchSearch(q) { 74 | // Add class for loading 75 | $body.addClass('with-search'); 76 | $body.addClass('search-loading'); 77 | 78 | // Launch search query 79 | throttle(gitbook.search.query(q, 0, MAX_RESULTS) 80 | .then(function(results) { 81 | displayResults(results); 82 | }) 83 | .always(function() { 84 | $body.removeClass('search-loading'); 85 | }), 1000); 86 | } 87 | 88 | function closeSearch() { 89 | $body.removeClass('with-search'); 90 | $bookSearchResults.removeClass('open'); 91 | } 92 | 93 | function launchSearchFromQueryString() { 94 | var q = getParameterByName('q'); 95 | if (q && q.length > 0) { 96 | // Update search input 97 | $searchInput.val(q); 98 | 99 | // Launch search 100 | launchSearch(q); 101 | } 102 | } 103 | 104 | function bindSearch() { 105 | // Bind DOM 106 | $searchInput = $('#book-search-input input'); 107 | $bookSearchResults = $('#book-search-results'); 108 | $searchList = $bookSearchResults.find('.search-results-list'); 109 | $searchTitle = $bookSearchResults.find('.search-results-title'); 110 | $searchResultsCount = $searchTitle.find('.search-results-count'); 111 | $searchQuery = $searchTitle.find('.search-query'); 112 | 113 | // Launch query based on input content 114 | function handleUpdate() { 115 | var q = $searchInput.val(); 116 | 117 | if (q.length == 0) { 118 | closeSearch(); 119 | } 120 | else { 121 | launchSearch(q); 122 | } 123 | } 124 | 125 | // Detect true content change in search input 126 | // Workaround for IE < 9 127 | var propertyChangeUnbound = false; 128 | $searchInput.on('propertychange', function(e) { 129 | if (e.originalEvent.propertyName == 'value') { 130 | handleUpdate(); 131 | } 132 | }); 133 | 134 | // HTML5 (IE9 & others) 135 | $searchInput.on('input', function(e) { 136 | // Unbind propertychange event for IE9+ 137 | if (!propertyChangeUnbound) { 138 | $(this).unbind('propertychange'); 139 | propertyChangeUnbound = true; 140 | } 141 | 142 | handleUpdate(); 143 | }); 144 | 145 | // Push to history on blur 146 | $searchInput.on('blur', function(e) { 147 | // Update history state 148 | if (usePushState) { 149 | var uri = updateQueryString('q', $(this).val()); 150 | history.pushState({ path: uri }, null, uri); 151 | } 152 | }); 153 | } 154 | 155 | gitbook.events.on('page.change', function() { 156 | bindSearch(); 157 | closeSearch(); 158 | 159 | // Launch search based on query parameter 160 | if (gitbook.search.isInitialized()) { 161 | launchSearchFromQueryString(); 162 | } 163 | }); 164 | 165 | gitbook.events.on('search.ready', function() { 166 | bindSearch(); 167 | 168 | // Launch search from query param at start 169 | launchSearchFromQueryString(); 170 | }); 171 | 172 | function getParameterByName(name) { 173 | var url = window.location.href; 174 | name = name.replace(/[\[\]]/g, '\\$&'); 175 | var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)', 'i'), 176 | results = regex.exec(url); 177 | if (!results) return null; 178 | if (!results[2]) return ''; 179 | return decodeURIComponent(results[2].replace(/\+/g, ' ')); 180 | } 181 | 182 | function updateQueryString(key, value) { 183 | value = encodeURIComponent(value); 184 | 185 | var url = window.location.href; 186 | var re = new RegExp('([?&])' + key + '=.*?(&|#|$)(.*)', 'gi'), 187 | hash; 188 | 189 | if (re.test(url)) { 190 | if (typeof value !== 'undefined' && value !== null) 191 | return url.replace(re, '$1' + key + '=' + value + '$2$3'); 192 | else { 193 | hash = url.split('#'); 194 | url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, ''); 195 | if (typeof hash[1] !== 'undefined' && hash[1] !== null) 196 | url += '#' + hash[1]; 197 | return url; 198 | } 199 | } 200 | else { 201 | if (typeof value !== 'undefined' && value !== null) { 202 | var separator = url.indexOf('?') !== -1 ? '&' : '?'; 203 | hash = url.split('#'); 204 | url = hash[0] + separator + key + '=' + value; 205 | if (typeof hash[1] !== 'undefined' && hash[1] !== null) 206 | url += '#' + hash[1]; 207 | return url; 208 | } 209 | else 210 | return url; 211 | } 212 | } 213 | }); 214 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/gitbook-plugin-sharing/buttons.js: -------------------------------------------------------------------------------- 1 | require(['gitbook', 'jquery'], function(gitbook, $) { 2 | var SITES = { 3 | 'facebook': { 4 | 'label': 'Facebook', 5 | 'icon': 'fa fa-facebook', 6 | 'onClick': function(e) { 7 | e.preventDefault(); 8 | window.open('http://www.facebook.com/sharer/sharer.php?s=100&p[url]='+encodeURIComponent(location.href)); 9 | } 10 | }, 11 | 'twitter': { 12 | 'label': 'Twitter', 13 | 'icon': 'fa fa-twitter', 14 | 'onClick': function(e) { 15 | e.preventDefault(); 16 | window.open('http://twitter.com/home?status='+encodeURIComponent(document.title+' '+location.href)); 17 | } 18 | }, 19 | 'google': { 20 | 'label': 'Google+', 21 | 'icon': 'fa fa-google-plus', 22 | 'onClick': function(e) { 23 | e.preventDefault(); 24 | window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href)); 25 | } 26 | }, 27 | 'weibo': { 28 | 'label': 'Weibo', 29 | 'icon': 'fa fa-weibo', 30 | 'onClick': function(e) { 31 | e.preventDefault(); 32 | window.open('http://service.weibo.com/share/share.php?content=utf-8&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)); 33 | } 34 | }, 35 | 'instapaper': { 36 | 'label': 'Instapaper', 37 | 'icon': 'fa fa-instapaper', 38 | 'onClick': function(e) { 39 | e.preventDefault(); 40 | window.open('http://www.instapaper.com/text?u='+encodeURIComponent(location.href)); 41 | } 42 | }, 43 | 'vk': { 44 | 'label': 'VK', 45 | 'icon': 'fa fa-vk', 46 | 'onClick': function(e) { 47 | e.preventDefault(); 48 | window.open('http://vkontakte.ru/share.php?url='+encodeURIComponent(location.href)); 49 | } 50 | } 51 | }; 52 | 53 | 54 | 55 | gitbook.events.bind('start', function(e, config) { 56 | var opts = config.sharing; 57 | 58 | // Create dropdown menu 59 | var menu = $.map(opts.all, function(id) { 60 | var site = SITES[id]; 61 | 62 | return { 63 | text: site.label, 64 | onClick: site.onClick 65 | }; 66 | }); 67 | 68 | // Create main button with dropdown 69 | if (menu.length > 0) { 70 | gitbook.toolbar.createButton({ 71 | icon: 'fa fa-share-alt', 72 | label: 'Share', 73 | position: 'right', 74 | dropdown: [menu] 75 | }); 76 | } 77 | 78 | // Direct actions to share 79 | $.each(SITES, function(sideId, site) { 80 | if (!opts[sideId]) return; 81 | 82 | gitbook.toolbar.createButton({ 83 | icon: site.icon, 84 | label: site.text, 85 | position: 'right', 86 | onClick: site.onClick 87 | }); 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /example-app/_book/gitbook/images/apple-touch-icon-precomposed-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/images/apple-touch-icon-precomposed-152.png -------------------------------------------------------------------------------- /example-app/_book/gitbook/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/_book/gitbook/images/favicon.ico -------------------------------------------------------------------------------- /example-app/_book/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Home · My Example Site 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 | 72 | 73 | 74 | 231 | 232 | 233 |
              234 | 235 |
              236 | 237 |
              238 | 239 | 240 | 241 | 250 | 251 | 252 | 253 | 254 |
              255 |
              256 | 257 |
              258 |
              259 | 260 |
              261 | 262 |

              The landing page

              263 |

              This is the landing page for your new Gitbook site! Good job!

              264 | 265 | 266 |
              267 | 268 |
              269 |
              270 |
              271 | 272 |

              results matching ""

              273 |
                274 | 275 |
                276 |
                277 | 278 |

                No results matching ""

                279 | 280 |
                281 |
                282 |
                283 | 284 |
                285 |
                286 | 287 |
                288 | 289 | 290 | 291 | 292 | 293 | 294 |
                295 | 296 | 302 |
                303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | -------------------------------------------------------------------------------- /example-app/_book/search_index.json: -------------------------------------------------------------------------------- 1 | {"index":{"version":"0.5.12","fields":[{"name":"title","boost":10},{"name":"keywords","boost":15},{"name":"body","boost":1}],"ref":"url","documentStore":{"store":{"./":["gitbook","good","home","job!","land","new","page","site!"],"animals/cats.html":["amazing.","artistiq","cat","colours.","come","differ","dude","loan","photo","unsplash"],"animals/dogs.html":["andrew","boy.","dog","good","look","perfect.","photo","stephen","unsplash"],"animals/birds.html":["bird","clode","david","fantastic.","now","photo","unsplash","yellow:"],"foods/fries.html":["belief,","contrari","delici","french","french.","fri","golden","great","ketchup","made","popular","potato","potatoes."],"foods/pasta.html":["boil","easi","make,","pasta","sauc","veri","water."],"foods/tofu.html":["come","cube","differ","dried.","firm,","food","forms:","fried,","futur","mani","protein","silky,","soy","tofu","veri"]},"length":7},"tokenStore":{"root":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"b":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{"./":{"ref":"./","tf":0.1111111111111111}}}}}}}},"o":{"docs":{},"o":{"docs":{},"d":{"docs":{"./":{"ref":"./","tf":0.1111111111111111},"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}},"l":{"docs":{},"d":{"docs":{},"e":{"docs":{},"n":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}},"r":{"docs":{},"e":{"docs":{},"a":{"docs":{},"t":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}},"h":{"docs":{},"o":{"docs":{},"m":{"docs":{},"e":{"docs":{"./":{"ref":"./","tf":10}}}}}},"j":{"docs":{},"o":{"docs":{},"b":{"docs":{},"!":{"docs":{"./":{"ref":"./","tf":0.1111111111111111}}}}}},"l":{"docs":{},"a":{"docs":{},"n":{"docs":{},"d":{"docs":{"./":{"ref":"./","tf":0.2222222222222222}}}}},"o":{"docs":{},"a":{"docs":{},"n":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091}}}},"o":{"docs":{},"k":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}}}},"n":{"docs":{},"e":{"docs":{},"w":{"docs":{"./":{"ref":"./","tf":0.1111111111111111}}}},"o":{"docs":{},"w":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}},"p":{"docs":{},"a":{"docs":{},"g":{"docs":{},"e":{"docs":{"./":{"ref":"./","tf":0.2222222222222222}}}},"s":{"docs":{},"t":{"docs":{},"a":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":10.25}}}}}},"h":{"docs":{},"o":{"docs":{},"t":{"docs":{},"o":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091},"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1},"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}},"e":{"docs":{},"r":{"docs":{},"f":{"docs":{},"e":{"docs":{},"c":{"docs":{},"t":{"docs":{},".":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}}}}}}},"o":{"docs":{},"p":{"docs":{},"u":{"docs":{},"l":{"docs":{},"a":{"docs":{},"r":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}},"t":{"docs":{},"a":{"docs":{},"t":{"docs":{},"o":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}},"e":{"docs":{},"s":{"docs":{},".":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}}}}},"r":{"docs":{},"o":{"docs":{},"t":{"docs":{},"e":{"docs":{},"i":{"docs":{},"n":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}}}},"s":{"docs":{},"i":{"docs":{},"t":{"docs":{},"e":{"docs":{},"!":{"docs":{"./":{"ref":"./","tf":0.1111111111111111}}}}},"l":{"docs":{},"k":{"docs":{},"y":{"docs":{},",":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}},"t":{"docs":{},"e":{"docs":{},"p":{"docs":{},"h":{"docs":{},"e":{"docs":{},"n":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}}}}}},"a":{"docs":{},"u":{"docs":{},"c":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125}}}}},"o":{"docs":{},"y":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}},"a":{"docs":{},"m":{"docs":{},"a":{"docs":{},"z":{"docs":{},"i":{"docs":{},"n":{"docs":{},"g":{"docs":{},".":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091}}}}}}}}},"r":{"docs":{},"t":{"docs":{},"i":{"docs":{},"s":{"docs":{},"t":{"docs":{},"i":{"docs":{},"q":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091}}}}}}}}},"n":{"docs":{},"d":{"docs":{},"r":{"docs":{},"e":{"docs":{},"w":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}}}}}},"c":{"docs":{},"a":{"docs":{},"t":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":10.181818181818182}}}},"o":{"docs":{},"l":{"docs":{},"o":{"docs":{},"u":{"docs":{},"r":{"docs":{},"s":{"docs":{},".":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091}}}}}}}},"m":{"docs":{},"e":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091},"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}},"n":{"docs":{},"t":{"docs":{},"r":{"docs":{},"a":{"docs":{},"r":{"docs":{},"i":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}}}},"l":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}},"u":{"docs":{},"b":{"docs":{},"e":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}},"d":{"docs":{},"i":{"docs":{},"f":{"docs":{},"f":{"docs":{},"e":{"docs":{},"r":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091},"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}},"u":{"docs":{},"d":{"docs":{},"e":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091}}}}},"o":{"docs":{},"g":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":10.2}}}},"a":{"docs":{},"v":{"docs":{},"i":{"docs":{},"d":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}},"e":{"docs":{},"l":{"docs":{},"i":{"docs":{},"c":{"docs":{},"i":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}},"r":{"docs":{},"i":{"docs":{},"e":{"docs":{},"d":{"docs":{},".":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}}},"u":{"docs":{},"n":{"docs":{},"s":{"docs":{},"p":{"docs":{},"l":{"docs":{},"a":{"docs":{},"s":{"docs":{},"h":{"docs":{"animals/cats.html":{"ref":"animals/cats.html","tf":0.09090909090909091},"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1},"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}}}}}},"b":{"docs":{},"o":{"docs":{},"y":{"docs":{},".":{"docs":{"animals/dogs.html":{"ref":"animals/dogs.html","tf":0.1}}}},"i":{"docs":{},"l":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125}}}}},"i":{"docs":{},"r":{"docs":{},"d":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":10.222222222222221}}}}},"e":{"docs":{},"l":{"docs":{},"i":{"docs":{},"e":{"docs":{},"f":{"docs":{},",":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}}}},"f":{"docs":{},"a":{"docs":{},"n":{"docs":{},"t":{"docs":{},"a":{"docs":{},"s":{"docs":{},"t":{"docs":{},"i":{"docs":{},"c":{"docs":{},".":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}}}}}}},"r":{"docs":{},"e":{"docs":{},"n":{"docs":{},"c":{"docs":{},"h":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":5.133333333333334}},".":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}},"i":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":5.133333333333334}},"e":{"docs":{},"d":{"docs":{},",":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}},"i":{"docs":{},"r":{"docs":{},"m":{"docs":{},",":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}},"o":{"docs":{},"o":{"docs":{},"d":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}},"r":{"docs":{},"m":{"docs":{},"s":{"docs":{},":":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}},"u":{"docs":{},"t":{"docs":{},"u":{"docs":{},"r":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}}},"y":{"docs":{},"e":{"docs":{},"l":{"docs":{},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{},":":{"docs":{"animals/birds.html":{"ref":"animals/birds.html","tf":0.1111111111111111}}}}}}}}},"k":{"docs":{},"e":{"docs":{},"t":{"docs":{},"c":{"docs":{},"h":{"docs":{},"u":{"docs":{},"p":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}}}}}}},"m":{"docs":{},"a":{"docs":{},"d":{"docs":{},"e":{"docs":{"foods/fries.html":{"ref":"foods/fries.html","tf":0.06666666666666667}}}},"k":{"docs":{},"e":{"docs":{},",":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125}}}}},"n":{"docs":{},"i":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}},"e":{"docs":{},"a":{"docs":{},"s":{"docs":{},"i":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125}}}}}},"v":{"docs":{},"e":{"docs":{},"r":{"docs":{},"i":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125},"foods/tofu.html":{"ref":"foods/tofu.html","tf":0.06666666666666667}}}}}},"w":{"docs":{},"a":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{},".":{"docs":{"foods/pasta.html":{"ref":"foods/pasta.html","tf":0.125}}}}}}}},"t":{"docs":{},"o":{"docs":{},"f":{"docs":{},"u":{"docs":{"foods/tofu.html":{"ref":"foods/tofu.html","tf":10.066666666666666}}}}}}},"length":70},"corpusTokens":["amazing.","andrew","artistiq","belief,","bird","boil","boy.","cat","clode","colours.","come","contrari","cube","david","delici","differ","dog","dried.","dude","easi","fantastic.","firm,","food","forms:","french","french.","fri","fried,","futur","gitbook","golden","good","great","home","job!","ketchup","land","loan","look","made","make,","mani","new","now","page","pasta","perfect.","photo","popular","potato","potatoes.","protein","sauc","silky,","site!","soy","stephen","tofu","unsplash","veri","water.","yellow:"],"pipeline":["stopWordFilter","stemmer"]},"store":{"./":{"url":"./","title":"Home","keywords":"","body":"The landing page\nThis is the landing page for your new Gitbook site! Good job!\n"},"animals/cats.html":{"url":"animals/cats.html","title":"Cats","keywords":"","body":"Cats\nCats are amazing. They come in different colours.\n \nPhotos by Loan and Artistiq Dude on Unsplash\n"},"animals/dogs.html":{"url":"animals/dogs.html","title":"Dogs","keywords":"","body":"Dogs\nDogs are perfect. Look at this good boy.\n\nPhoto by Stephen Andrews on Unsplash\n"},"animals/birds.html":{"url":"animals/birds.html","title":"Birds","keywords":"","body":"Birds\nBirds are just fantastic. Now in yellow:\n\nPhoto by David Clode on Unsplash\n"},"foods/fries.html":{"url":"foods/fries.html","title":"French fries","keywords":"","body":"French fries\nFrench fries are made from potatoes. Contrary to popular belief, not all potatoes are french.\n\nGreat with ketchup\nGolden\nDelicious\n\n"},"foods/pasta.html":{"url":"foods/pasta.html","title":"Pasta","keywords":"","body":"Pasta\nPasta is very easy to make, only boil it in water.\n\nGet your sauce on\n\n"},"foods/tofu.html":{"url":"foods/tofu.html","title":"Tofu","keywords":"","body":"Tofu\nIt comes in many different forms: silky, firm, fried, and dried.\n\nFood of the future\nProtein cubes\nVery soy\n\n"}}} -------------------------------------------------------------------------------- /example-app/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "./content", 3 | "title": "My Example Site", 4 | "plugins": ["anchorjs"], 5 | "pluginsConfig": { 6 | "anchorjs": { 7 | "placement": "left" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example-app/content/README.md: -------------------------------------------------------------------------------- 1 | # The landing page 2 | 3 | This is the landing page for your new Gitbook site! Good job! -------------------------------------------------------------------------------- /example-app/content/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Home](README.md) 4 | - Animals 5 | - [Cats](animals/cats.md) 6 | - [Dogs](animals/dogs.md) 7 | - [Birds](animals/birds.md) 8 | - Foods 9 | - [French fries](foods/fries.md) 10 | - [Pasta](foods/pasta.md) 11 | - [Tofu](foods/tofu.md) -------------------------------------------------------------------------------- /example-app/content/animals/birds.md: -------------------------------------------------------------------------------- 1 | # Birds 2 | 3 | Birds are just fantastic. Now in yellow: 4 | 5 | 6 | 7 | *Photo by [David Clode](https://unsplash.com/photos/K4vHlGVX0Hs) on [Unsplash](https://unsplash.com)* -------------------------------------------------------------------------------- /example-app/content/animals/cats.md: -------------------------------------------------------------------------------- 1 | # Cats 2 | 3 | Cats are amazing. They come in different colours. 4 | 5 | 6 | 7 | *Photos by [Loan](https://unsplash.com/photos/7AIDE8PrvA0) and [Artistiq Dude](https://unsplash.com/photos/o1mI1HD3NVI) on [Unsplash](https://unsplash.com)* -------------------------------------------------------------------------------- /example-app/content/animals/dogs.md: -------------------------------------------------------------------------------- 1 | # Dogs 2 | 3 | Dogs are perfect. Look at this good boy. 4 | 5 | 6 | 7 | *Photo by [Stephen Andrews](https://unsplash.com/photos/lEe3-hTg4Vg) on [Unsplash](https://unsplash.com)* -------------------------------------------------------------------------------- /example-app/content/animals/img/black-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/content/animals/img/black-cat.jpg -------------------------------------------------------------------------------- /example-app/content/animals/img/good-boy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/content/animals/img/good-boy.jpg -------------------------------------------------------------------------------- /example-app/content/animals/img/tabby-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/content/animals/img/tabby-cat.jpg -------------------------------------------------------------------------------- /example-app/content/animals/img/yellow-bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svt/docker-workshop/a35ae196f86e20903aa4b4f0d3e3680328d67395/example-app/content/animals/img/yellow-bird.jpg -------------------------------------------------------------------------------- /example-app/content/foods/fries.md: -------------------------------------------------------------------------------- 1 | # French fries 2 | 3 | French fries are made from potatoes. Contrary to popular belief, not all potatoes are french. 4 | 5 | * Great with ketchup 6 | * Golden 7 | * Delicious -------------------------------------------------------------------------------- /example-app/content/foods/pasta.md: -------------------------------------------------------------------------------- 1 | # Pasta 2 | 3 | Pasta is very easy to make, only boil it in water. 4 | 5 | * Get your sauce on -------------------------------------------------------------------------------- /example-app/content/foods/tofu.md: -------------------------------------------------------------------------------- 1 | # Tofu 2 | 3 | It comes in many different forms: silky, firm, fried, and dried. 4 | 5 | * Food of the future 6 | * Protein cubes 7 | * Very soy -------------------------------------------------------------------------------- /example-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-example-site", 3 | "version": "0.0.1", 4 | "description": "An example Gitbook site", 5 | "dependencies": { 6 | "gitbook-cli": "^2.3.2", 7 | "gitbook-plugin-anchorjs": "^2.1.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "build": "gitbook build", 12 | "serve": "gitbook serve", 13 | "install": "gitbook install", 14 | "debug": "gitbook build ./ --log=debug --debug" 15 | }, 16 | "author": "Sveriges Television AB", 17 | "license": "CC-BY-SA-4.0" 18 | } 19 | --------------------------------------------------------------------------------