diff --git a/404.html b/404.html index a9360a1b..7eee5579 100644 --- a/404.html +++ b/404.html @@ -4,13 +4,13 @@ Page Not Found | DevOps with Docker - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - + + \ No newline at end of file diff --git a/assets/js/0760ddad.075a0a5e.js b/assets/js/0760ddad.075a0a5e.js new file mode 100644 index 00000000..f2842615 --- /dev/null +++ b/assets/js/0760ddad.075a0a5e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[48],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,h=p["".concat(s,".").concat(m)]||p[m]||c[m]||r;return n?a.createElement(h,l(l({ref:t},d),{},{components:n})):a.createElement(h,l({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>i,toc:()=>u});var a=n(7462),o=(n(7294),n(3905));const r={title:"Defining start conditions for the container"},l=void 0,i={unversionedId:"part-1/section-4",id:"part-1/section-4",title:"Defining start conditions for the container",description:"Next, we will start moving towards a more meaningful image. youtube-dl is a program that downloads Youtube videos . Let's add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let's try another approach. This time we will open up an interactive session and test stuff before \"storing\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:",source:"@site/docs/part-1/section-4.md",sourceDirName:"part-1",slug:"/part-1/section-4",permalink:"/part-1/section-4",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-4.md",tags:[],version:"current",frontMatter:{title:"Defining start conditions for the container"},sidebar:"materialSidebar",previous:{title:"In-depth dive into images",permalink:"/part-1/section-3"},next:{title:"Interacting with the container via volumes and ports",permalink:"/part-1/section-5"}},s={},u=[{value:"Improved curler",id:"improved-curler",level:2}],d={toc:u},p="wrapper";function c(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Next, we will start moving towards a more meaningful image. ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," is a program that downloads Youtube videos ",(0,o.kt)("a",{parentName:"p",href:"https://rg3.github.io/youtube-dl/download.html"},"https://rg3.github.io/youtube-dl/download.html"),". Let's add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let's try another approach. This time we will open up an interactive session and test stuff before \"storing\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu:18.04\n\n\n\n root@8c587232a608:/# curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\n bash: curl: command not found\n")),(0,o.kt)("p",null,"..and, as we already know, curl is not installed - let's add ",(0,o.kt)("inlineCode",{parentName:"p"},"curl")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"apt-get")," again."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ apt-get update && apt-get install -y curl\n$ curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\n")),(0,o.kt)("p",null,"At some point, you may have noticed that ",(0,o.kt)("em",{parentName:"p"},"sudo")," is not installed either, but since we are ",(0,o.kt)("em",{parentName:"p"},"root")," we don't need it."),(0,o.kt)("p",null,"Next, we will add permissions and run it:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ chmod a+rx /usr/local/bin/youtube-dl\n$ youtube-dl\n /usr/bin/env: 'python': No such file or directory\n")),(0,o.kt)("p",null,"Okay - On the top of the ",(0,o.kt)("inlineCode",{parentName:"p"},"youtube-dl")," download page we notice this message:"),(0,o.kt)("p",null,"Remember youtube-dl requires Python version 2.6, 2.7, or 3.2+ to work except for Windows exe."),(0,o.kt)("p",null,"So we will add python"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ apt-get install -y python\n")),(0,o.kt)("p",null,"And let's run it again"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ youtube-dl\n\n WARNING: Assuming --restrict-filenames since file system encoding cannot encode all characters. Set the LC_ALL environment variable to fix this.\n Usage: youtube-dl [OPTIONS] URL [URL...]\n\n youtube-dl: error: You must provide at least one URL.\n Type youtube-dl --help to see a list of all options.\n")),(0,o.kt)("p",null,"It works (we just need to give an URL), but we notice that it outputs a warning about ",(0,o.kt)("inlineCode",{parentName:"p"},"LC_ALL"),". In a regular Ubuntu desktop/server install the localization settings are (usually) set, but in this image they are not set, as we can see by running ",(0,o.kt)("inlineCode",{parentName:"p"},"env")," in our container. To fix this without installing additional locales, see this: ",(0,o.kt)("a",{parentName:"p",href:"https://stackoverflow.com/a/41648500"},"https://stackoverflow.com/a/41648500")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ LC_ALL=C.UTF-8 youtube-dl\n")),(0,o.kt)("p",null,"And it works! Let's persist it for our session and try downloading a video:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ export LC_ALL=C.UTF-8\n$ youtube-dl https://imgur.com/JY5tHqr\n")),(0,o.kt)("p",null,"So now when we know exactly what we need. Starting FROM ubuntu:18.04, add these to our ",(0,o.kt)("inlineCode",{parentName:"p"},"Dockerfile"),". We should always try to keep the most prone to change rows at the bottom, by adding the instructions to the bottom we can preserve our cached layers - this is handy practise to speed up creating the initial version of a Dockerfile when it has time-consuming operations like downloads. Also added WORKDIR, this will ensure the videos will be downloaded there."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\nCMD ["/usr/local/bin/youtube-dl"]\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Instead of using ",(0,o.kt)("inlineCode",{parentName:"p"},"RUN export LC_ALL=C.UTF-8")," we store the environment directly in the image with ENV")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"We also override ",(0,o.kt)("inlineCode",{parentName:"p"},"bash")," as our image command (set on the base image) with ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," itself. This will not work, but let's see why."))),(0,o.kt)("p",null,"When we build this as youtube-dl and run it:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build -t youtube-dl .\n ...\n\n$ docker run youtube-dl\n\n Usage: youtube-dl [OPTIONS] URL [URL...]\n\n youtube-dl: error: You must provide at least one URL.\n\n Type youtube-dl --help to see a list of all options.\n")),(0,o.kt)("p",null,"So far so good, but now the natural way to use this image would be to give the URL as an argument:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker run youtube-dl https://imgur.com/JY5tHqr\n\n /usr/local/bin/docker: Error response from daemon: OCI runtime create failed: container_linux.go:296: starting container process caused "exec: \\"https://imgur.com/JY5tHqr\\": stat https://imgur.com/JY5tHqr: no such file or directory": unknown.\n\n ERRO[0001] error waiting for container: context canceled\n')),(0,o.kt)("p",null,"As we now know, the argument we gave it is replacing the command or ",(0,o.kt)("inlineCode",{parentName:"p"},"CMD"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it youtube-dl ps\n PID TTY TIME CMD\n 1 pts/0 00:00:00 ps\n$ docker run -it youtube-dl ls -l\ntotal 0\n$ docker run -it youtube-dl pwd\n/mydir\n")),(0,o.kt)("p",null,"We need a way to have something ",(0,o.kt)("em",{parentName:"p"},"before")," the command. Luckily we have a way to do this: we can use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#entrypoint"},"ENTRYPOINT")," to define the main executable and then Docker will combine our run arguments for it."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\n# Replacing CMD with ENTRYPOINT\nENTRYPOINT ["/usr/local/bin/youtube-dl"]\n')),(0,o.kt)("p",null,"And now it works like it should:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build -t youtube-dl .\n$ docker run youtube-dl https://imgur.com/JY5tHqr\n\n [Imgur] JY5tHqr: Downloading webpage\n [download] Destination: Imgur-JY5tHqr.mp4\n [download] 100% of 190.20KiB in 00:0044MiB/s ETA 00:000\n")),(0,o.kt)("p",null,"With ",(0,o.kt)("em",{parentName:"p"},"ENTRYPOINT")," ",(0,o.kt)("inlineCode",{parentName:"p"},"docker run")," now executed the combined ",(0,o.kt)("inlineCode",{parentName:"p"},"/usr/local/bin/youtube-dl https://imgur.com/JY5tHqr")," inside the container with that command!"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ENTRYPOINT")," vs ",(0,o.kt)("inlineCode",{parentName:"p"},"CMD")," can be confusing - in a properly set up image such as our youtube-dl the command represents an argument list for the entrypoint. By default entrypoint is set as ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh")," and this is passed if no entrypoint is set. This is why giving path to a script file as CMD works: you're giving the file as a parameter to ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh"),"."),(0,o.kt)("p",null,"If an image defines both, then the CMD is used to give ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#cmd"},"default arguments")," to the entrypoint. Let us now add a CMD to the Dockerfile:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\nENTRYPOINT ["/usr/local/bin/youtube-dl"]\n\n# define a default argument\nCMD ["https://imgur.com/gallery/xwJgflf"]\n')),(0,o.kt)("p",null,"Now (after build again) the image can be run without arguments to download the video defined in CMD:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run youtube-dl\n\n [Imgur] JY5tHqr: Downloading webpage\n [download] Destination: Imgur-JY5tHqr.mp4\n [download] 100% of 190.20KiB in 00:0044MiB/s ETA 00:000\n")),(0,o.kt)("p",null,"The argument defined by CMD can be ",(0,o.kt)("em",{parentName:"p"},"overridden")," by giving one in the command line:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run youtube-dl https://imgur.com/gallery/iT3U4K4\n[imgur:gallery] iT3U4K4: Downloading JSON metadata\n[download] Downloading playlist: A candlelight dinner needs a doggie serenade\n[imgur:gallery] playlist A candlelight dinner needs a doggie serenade: Collected 1 video ids (downloading 1 of them)\n[download] Downloading video 1 of 1\n[Imgur] ZkjbtYw: Downloading webpage\n[download] Destination: Imgur-ZkjbtYw.mp4\n[download] 100% of 5.02MiB in 00:0183MiB/s ETA 00:00known ETA\n[download] Finished downloading playlist: A candlelight dinner needs a doggie serenade\n")),(0,o.kt)("p",null,"Note that despite the name, ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," works currently only with ",(0,o.kt)("a",{parentName:"p",href:"https://imgur.com/"},"imgur.com"),"."),(0,o.kt)("p",null,"In addition to all seen, there are two ways to set the ENTRYPOINT and CMD: ",(0,o.kt)("strong",{parentName:"p"},"exec")," form and ",(0,o.kt)("strong",{parentName:"p"},"shell")," form. We've been using the exec form where the command itself is executed. In shell form the command that is executed is wrapped with ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh -c")," - it's useful when you need to evaluate environment variables in the command like ",(0,o.kt)("inlineCode",{parentName:"p"},"$MYSQL_PASSWORD")," or similar."),(0,o.kt)("p",null,"In the shell form the command is provided as a string without brackets. In the exec form the command and it's arguments are provided as a list (with brackets), see the table below:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Dockerfile"),(0,o.kt)("th",{parentName:"tr",align:null},"Resulting command"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT /bin/ping -c 3 ",(0,o.kt)("br",null)," CMD localhost"),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/sh -c '/bin/ping -c 3' /bin/sh -c localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT ",'["/bin/ping","-c","3"]'," ",(0,o.kt)("br",null)," CMD localhost"),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/ping -c 3 /bin/sh -c localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT /bin/ping -c 3 ",(0,o.kt)("br",null)," CMD ",'["localhost"]'),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/sh -c '/bin/ping -c 3' localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT ",'["/bin/ping","-c","3"]'," ",(0,o.kt)("br",null)," CMD ",'["localhost"]'),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/ping -c 3 localhost")))),(0,o.kt)("p",null,"As the command at the end of Docker run will be the CMD we want to use ENTRYPOINT to specify what to run, and CMD to specify which command (in our case url) to run."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Most of the time")," we can ignore ENTRYPOINT when building our images and only use CMD. For example, Ubuntu image defaults the ENTRYPOINT to bash so we do not have to worry about it. And it gives us the convenience of allowing us to overwrite the CMD easily, for example, with bash to go inside the container."),(0,o.kt)("p",null,"We can test how some other projects do this. Let's try python:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker pull python:3.8\n...\n$ docker run -it python:3.8\n Python 3.8.2 (default, Mar 31 2020, 15:23:55)\n [GCC 8.3.0] on linux\n Type "help", "copyright", "credits" or "license" for more information.\n >>> print("Hello, World!")\n Hello, World!\n >>> exit()\n\n$ docker run -it python:3.8 --version\n docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "--version": executable file not found in $PATH: unknown.\n\n$ docker run -it python:3.8 bash\n root@1b7b99ae2f40:/#\n\n')),(0,o.kt)("p",null,"From this experimentation we learned that they have ENTRYPOINT as something other than python, but the CMD is python and we can overwrite it, here with bash. If they had ENTRYPOINT as python we'd be able to run ",(0,o.kt)("inlineCode",{parentName:"p"},"--version"),". We can create our own image for personal use as we did in a previous exercise with a new Dockerfile."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM python:3.8\nENTRYPOINT ["python3"]\nCMD ["--help"]\n')),(0,o.kt)("p",null,"The result is an image that has python as ENTRYPOINT and you can add the commands at the end, for example --version to see the version. Without overwriting the command, it will output the help."),(0,o.kt)("p",null,"Now we have two problems with the youtube-dl project:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Major: The downloaded files stay in the container")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Minor: Our container build process creates many layers resulting in increased image size"))),(0,o.kt)("p",null,"We will fix the major issue first. The minor issue will get our attention in part 3."),(0,o.kt)("p",null,"By inspecting ",(0,o.kt)("inlineCode",{parentName:"p"},"docker container ls -a")," we can see all our previous runs. When we filter this list with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker container ls -a --last 3\n\n CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n be9fdbcafb23 youtube-dl "/usr/local/bin/yout\u2026" Less than a second ago Exited (0) About a minute ago determined_elion\n b61e4029f997 f2210c2591a1 "/bin/sh -c \\"/usr/lo\u2026" Less than a second ago Exited (2) About a minute ago vigorous_bardeen\n 326bb4f5af1e f2210c2591a1 "/bin/sh -c \\"/usr/lo\u2026" About a minute ago Exited (2) 3 minutes ago hardcore_carson\n')),(0,o.kt)("p",null,"We see that the last container was ",(0,o.kt)("inlineCode",{parentName:"p"},"be9fdbcafb23")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"determined_elion")," for us humans."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker diff determined_elion\n\n C /mydir\n A /mydir/Imgur-JY5tHqr.mp4\n")),(0,o.kt)("p",null,"Let's try ",(0,o.kt)("inlineCode",{parentName:"p"},"docker cp")," command to copy the file. We can use quotes if the filename has spaces."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker cp "determined_elion://mydir/Imgur-JY5tHqr.mp4" .\n')),(0,o.kt)("p",null,"And now we have our file locally. Sadly, this is not sufficient to fix our issue. In the next section, we will improve this."),(0,o.kt)("h2",{id:"improved-curler"},"Improved curler"),(0,o.kt)("p",null,"With ",(0,o.kt)("inlineCode",{parentName:"p"},"ENTRYPOINT")," we can make the curler of the ",(0,o.kt)("a",{parentName:"p",href:"/part-1/section-3#exercises-17---18"},"Exercise 1.7.")," more flexible."),(0,o.kt)("p",null,"Change the script so that it takes the first argument as the input:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\necho "Searching..";\nsleep 1;\ncurl http://$1;\n')),(0,o.kt)("p",null,"And change the CMD to ENTRYPOINT with the format ",(0,o.kt)("inlineCode",{parentName:"p"},'["./script.sh"]'),". Now we can run"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker build . -t curler-v2\n$ docker run curler-v2 helsinki.fi\n\n Searching..\n % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n 100 232 100 232 0 0 13647 0 --:--:-- --:--:-- --:--:-- 13647\n \n \n 301 Moved Permanently\n \n

Moved Permanently

\n

The document has moved here.

\n \n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0760ddad.5de63e4f.js b/assets/js/0760ddad.5de63e4f.js deleted file mode 100644 index 54ab43b1..00000000 --- a/assets/js/0760ddad.5de63e4f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[48],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,h=p["".concat(s,".").concat(m)]||p[m]||c[m]||r;return n?a.createElement(h,l(l({ref:t},d),{},{components:n})):a.createElement(h,l({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>r,metadata:()=>i,toc:()=>u});var a=n(7462),o=(n(7294),n(3905));const r={title:"Defining start conditions for the container"},l=void 0,i={unversionedId:"part-1/section-4",id:"part-1/section-4",title:"Defining start conditions for the container",description:"Next, we will start moving towards a more meaningful image. youtube-dl is a program that downloads Youtube videos . Let's add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let's try another approach. This time we will open up an interactive session and test stuff before \"storing\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:",source:"@site/docs/part-1/section-4.md",sourceDirName:"part-1",slug:"/part-1/section-4",permalink:"/part-1/section-4",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-4.md",tags:[],version:"current",frontMatter:{title:"Defining start conditions for the container"},sidebar:"materialSidebar",previous:{title:"In-depth dive to images",permalink:"/part-1/section-3"},next:{title:"Interacting with the container via volumes and ports",permalink:"/part-1/section-5"}},s={},u=[{value:"Improved curler",id:"improved-curler",level:2}],d={toc:u},p="wrapper";function c(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Next, we will start moving towards a more meaningful image. ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," is a program that downloads Youtube videos ",(0,o.kt)("a",{parentName:"p",href:"https://rg3.github.io/youtube-dl/download.html"},"https://rg3.github.io/youtube-dl/download.html"),". Let's add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let's try another approach. This time we will open up an interactive session and test stuff before \"storing\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu:18.04\n\n\n\n root@8c587232a608:/# curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\n bash: curl: command not found\n")),(0,o.kt)("p",null,"..and, as we already know, curl is not installed - let's add ",(0,o.kt)("inlineCode",{parentName:"p"},"curl")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"apt-get")," again."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ apt-get update && apt-get install -y curl\n$ curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\n")),(0,o.kt)("p",null,"At some point, you may have noticed that ",(0,o.kt)("em",{parentName:"p"},"sudo")," is not installed either, but since we are ",(0,o.kt)("em",{parentName:"p"},"root")," we don't need it."),(0,o.kt)("p",null,"Next, we will add permissions and run it:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ chmod a+rx /usr/local/bin/youtube-dl\n$ youtube-dl\n /usr/bin/env: 'python': No such file or directory\n")),(0,o.kt)("p",null,"Okay - On the top of the ",(0,o.kt)("inlineCode",{parentName:"p"},"youtube-dl")," download page we notice this message:"),(0,o.kt)("p",null,"Remember youtube-dl requires Python version 2.6, 2.7, or 3.2+ to work except for Windows exe."),(0,o.kt)("p",null,"So we will add python"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ apt-get install -y python\n")),(0,o.kt)("p",null,"And let's run it again"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ youtube-dl\n\n WARNING: Assuming --restrict-filenames since file system encoding cannot encode all characters. Set the LC_ALL environment variable to fix this.\n Usage: youtube-dl [OPTIONS] URL [URL...]\n\n youtube-dl: error: You must provide at least one URL.\n Type youtube-dl --help to see a list of all options.\n")),(0,o.kt)("p",null,"It works (we just need to give an URL), but we notice that it outputs a warning about ",(0,o.kt)("inlineCode",{parentName:"p"},"LC_ALL"),". In a regular Ubuntu desktop/server install the localization settings are (usually) set, but in this image they are not set, as we can see by running ",(0,o.kt)("inlineCode",{parentName:"p"},"env")," in our container. To fix this without installing additional locales, see this: ",(0,o.kt)("a",{parentName:"p",href:"https://stackoverflow.com/a/41648500"},"https://stackoverflow.com/a/41648500")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ LC_ALL=C.UTF-8 youtube-dl\n")),(0,o.kt)("p",null,"And it works! Let's persist it for our session and try downloading a video:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ export LC_ALL=C.UTF-8\n$ youtube-dl https://imgur.com/JY5tHqr\n")),(0,o.kt)("p",null,"So now when we know exactly what we need. Starting FROM ubuntu:18.04, add these to our ",(0,o.kt)("inlineCode",{parentName:"p"},"Dockerfile"),". We should always try to keep the most prone to change rows at the bottom, by adding the instructions to the bottom we can preserve our cached layers - this is handy practise to speed up creating the initial version of a Dockerfile when it has time-consuming operations like downloads. Also added WORKDIR, this will ensure the videos will be downloaded there."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\nCMD ["/usr/local/bin/youtube-dl"]\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Instead of using ",(0,o.kt)("inlineCode",{parentName:"p"},"RUN export LC_ALL=C.UTF-8")," we store the environment directly in the image with ENV")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"We also override ",(0,o.kt)("inlineCode",{parentName:"p"},"bash")," as our image command (set on the base image) with ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," itself. This will not work, but let's see why."))),(0,o.kt)("p",null,"When we build this as youtube-dl and run it:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build -t youtube-dl .\n ...\n\n$ docker run youtube-dl\n\n Usage: youtube-dl [OPTIONS] URL [URL...]\n\n youtube-dl: error: You must provide at least one URL.\n\n Type youtube-dl --help to see a list of all options.\n")),(0,o.kt)("p",null,"So far so good, but now the natural way to use this image would be to give the URL as an argument:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker run youtube-dl https://imgur.com/JY5tHqr\n\n /usr/local/bin/docker: Error response from daemon: OCI runtime create failed: container_linux.go:296: starting container process caused "exec: \\"https://imgur.com/JY5tHqr\\": stat https://imgur.com/JY5tHqr: no such file or directory": unknown.\n\n ERRO[0001] error waiting for container: context canceled\n')),(0,o.kt)("p",null,"As we now know, the argument we gave it is replacing the command or ",(0,o.kt)("inlineCode",{parentName:"p"},"CMD"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it youtube-dl ps\n PID TTY TIME CMD\n 1 pts/0 00:00:00 ps\n$ docker run -it youtube-dl ls -l\ntotal 0\n$ docker run -it youtube-dl pwd\n/mydir\n")),(0,o.kt)("p",null,"We need a way to have something ",(0,o.kt)("em",{parentName:"p"},"before")," the command. Luckily we have a way to do this: we can use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#entrypoint"},"ENTRYPOINT")," to define the main executable and then Docker will combine our run arguments for it."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\n# Replacing CMD with ENTRYPOINT\nENTRYPOINT ["/usr/local/bin/youtube-dl"]\n')),(0,o.kt)("p",null,"And now it works like it should:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build -t youtube-dl .\n$ docker run youtube-dl https://imgur.com/JY5tHqr\n\n [Imgur] JY5tHqr: Downloading webpage\n [download] Destination: Imgur-JY5tHqr.mp4\n [download] 100% of 190.20KiB in 00:0044MiB/s ETA 00:000\n")),(0,o.kt)("p",null,"With ",(0,o.kt)("em",{parentName:"p"},"ENTRYPOINT")," ",(0,o.kt)("inlineCode",{parentName:"p"},"docker run")," now executed the combined ",(0,o.kt)("inlineCode",{parentName:"p"},"/usr/local/bin/youtube-dl https://imgur.com/JY5tHqr")," inside the container with that command!"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ENTRYPOINT")," vs ",(0,o.kt)("inlineCode",{parentName:"p"},"CMD")," can be confusing - in a properly set up image such as our youtube-dl the command represents an argument list for the entrypoint. By default entrypoint is set as ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh")," and this is passed if no entrypoint is set. This is why giving path to a script file as CMD works: you're giving the file as a parameter to ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh"),"."),(0,o.kt)("p",null,"If an image defines both, then the CMD is used to give ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#cmd"},"default arguments")," to the entrypoint. Let us now add a CMD to the Dockerfile:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM ubuntu:18.04\n\nWORKDIR /mydir\n\nRUN apt-get update && apt-get install -y curl python\nRUN curl -L https://github.com/ytdl-org/youtube-dl/releases/download/2021.12.17/youtube-dl -o /usr/local/bin/youtube-dl\nRUN chmod a+x /usr/local/bin/youtube-dl\n\nENV LC_ALL=C.UTF-8\n\nENTRYPOINT ["/usr/local/bin/youtube-dl"]\n\n# define a default argument\nCMD ["https://imgur.com/gallery/xwJgflf"]\n')),(0,o.kt)("p",null,"Now (after build again) the image can be run without arguments to download the video defined in CMD:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run youtube-dl\n\n [Imgur] JY5tHqr: Downloading webpage\n [download] Destination: Imgur-JY5tHqr.mp4\n [download] 100% of 190.20KiB in 00:0044MiB/s ETA 00:000\n")),(0,o.kt)("p",null,"The argument defined by CMD can be ",(0,o.kt)("em",{parentName:"p"},"overridden")," by giving one in the command line:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run youtube-dl https://imgur.com/gallery/iT3U4K4\n[imgur:gallery] iT3U4K4: Downloading JSON metadata\n[download] Downloading playlist: A candlelight dinner needs a doggie serenade\n[imgur:gallery] playlist A candlelight dinner needs a doggie serenade: Collected 1 video ids (downloading 1 of them)\n[download] Downloading video 1 of 1\n[Imgur] ZkjbtYw: Downloading webpage\n[download] Destination: Imgur-ZkjbtYw.mp4\n[download] 100% of 5.02MiB in 00:0183MiB/s ETA 00:00known ETA\n[download] Finished downloading playlist: A candlelight dinner needs a doggie serenade\n")),(0,o.kt)("p",null,"Note that despite the name, ",(0,o.kt)("em",{parentName:"p"},"youtube-dl")," works currently only with ",(0,o.kt)("a",{parentName:"p",href:"https://imgur.com/"},"imgur.com"),"."),(0,o.kt)("p",null,"In addition to all seen, there are two ways to set the ENTRYPOINT and CMD: ",(0,o.kt)("strong",{parentName:"p"},"exec")," form and ",(0,o.kt)("strong",{parentName:"p"},"shell")," form. We've been using the exec form where the command itself is executed. In shell form the command that is executed is wrapped with ",(0,o.kt)("inlineCode",{parentName:"p"},"/bin/sh -c")," - it's useful when you need to evaluate environment variables in the command like ",(0,o.kt)("inlineCode",{parentName:"p"},"$MYSQL_PASSWORD")," or similar."),(0,o.kt)("p",null,"In the shell form the command is provided as a string without brackets. In the exec form the command and it's arguments are provided as a list (with brackets), see the table below:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Dockerfile"),(0,o.kt)("th",{parentName:"tr",align:null},"Resulting command"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT /bin/ping -c 3 ",(0,o.kt)("br",null)," CMD localhost"),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/sh -c '/bin/ping -c 3' /bin/sh -c localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT ",'["/bin/ping","-c","3"]'," ",(0,o.kt)("br",null)," CMD localhost"),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/ping -c 3 /bin/sh -c localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT /bin/ping -c 3 ",(0,o.kt)("br",null)," CMD ",'["localhost"]'),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/sh -c '/bin/ping -c 3' localhost")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"ENTRYPOINT ",'["/bin/ping","-c","3"]'," ",(0,o.kt)("br",null)," CMD ",'["localhost"]'),(0,o.kt)("td",{parentName:"tr",align:null},"/bin/ping -c 3 localhost")))),(0,o.kt)("p",null,"As the command at the end of Docker run will be the CMD we want to use ENTRYPOINT to specify what to run, and CMD to specify which command (in our case url) to run."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Most of the time")," we can ignore ENTRYPOINT when building our images and only use CMD. For example, Ubuntu image defaults the ENTRYPOINT to bash so we do not have to worry about it. And it gives us the convenience of allowing us to overwrite the CMD easily, for example, with bash to go inside the container."),(0,o.kt)("p",null,"We can test how some other projects do this. Let's try python:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker pull python:3.8\n...\n$ docker run -it python:3.8\n Python 3.8.2 (default, Mar 31 2020, 15:23:55)\n [GCC 8.3.0] on linux\n Type "help", "copyright", "credits" or "license" for more information.\n >>> print("Hello, World!")\n Hello, World!\n >>> exit()\n\n$ docker run -it python:3.8 --version\n docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "--version": executable file not found in $PATH: unknown.\n\n$ docker run -it python:3.8 bash\n root@1b7b99ae2f40:/#\n\n')),(0,o.kt)("p",null,"From this experimentation we learned that they have ENTRYPOINT as something other than python, but the CMD is python and we can overwrite it, here with bash. If they had ENTRYPOINT as python we'd be able to run ",(0,o.kt)("inlineCode",{parentName:"p"},"--version"),". We can create our own image for personal use as we did in a previous exercise with a new Dockerfile."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-dockerfile"},'FROM python:3.8\nENTRYPOINT ["python3"]\nCMD ["--help"]\n')),(0,o.kt)("p",null,"The result is an image that has python as ENTRYPOINT and you can add the commands at the end, for example --version to see the version. Without overwriting the command, it will output the help."),(0,o.kt)("p",null,"Now we have two problems with the youtube-dl project:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Major: The downloaded files stay in the container")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Minor: Our container build process creates many layers resulting in increased image size"))),(0,o.kt)("p",null,"We will fix the major issue first. The minor issue will get our attention in part 3."),(0,o.kt)("p",null,"By inspecting ",(0,o.kt)("inlineCode",{parentName:"p"},"docker container ls -a")," we can see all our previous runs. When we filter this list with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker container ls -a --last 3\n\n CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n be9fdbcafb23 youtube-dl "/usr/local/bin/yout\u2026" Less than a second ago Exited (0) About a minute ago determined_elion\n b61e4029f997 f2210c2591a1 "/bin/sh -c \\"/usr/lo\u2026" Less than a second ago Exited (2) About a minute ago vigorous_bardeen\n 326bb4f5af1e f2210c2591a1 "/bin/sh -c \\"/usr/lo\u2026" About a minute ago Exited (2) 3 minutes ago hardcore_carson\n')),(0,o.kt)("p",null,"We see that the last container was ",(0,o.kt)("inlineCode",{parentName:"p"},"be9fdbcafb23")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"determined_elion")," for us humans."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},"$ docker diff determined_elion\n\n C /mydir\n A /mydir/Imgur-JY5tHqr.mp4\n")),(0,o.kt)("p",null,"Let's try ",(0,o.kt)("inlineCode",{parentName:"p"},"docker cp")," command to copy the file. We can use quotes if the filename has spaces."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-console"},'$ docker cp "determined_elion://mydir/Imgur-JY5tHqr.mp4" .\n')),(0,o.kt)("p",null,"And now we have our file locally. Sadly, this is not sufficient to fix our issue. In the next section, we will improve this."),(0,o.kt)("h2",{id:"improved-curler"},"Improved curler"),(0,o.kt)("p",null,"With ",(0,o.kt)("inlineCode",{parentName:"p"},"ENTRYPOINT")," we can make the curler of the ",(0,o.kt)("a",{parentName:"p",href:"/part-1/section-3#exercises-17---18"},"Exercise 1.7.")," more flexible."),(0,o.kt)("p",null,"Change the script so that it takes the first argument as the input:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#!/bin/bash\n\necho "Searching..";\nsleep 1;\ncurl http://$1;\n')),(0,o.kt)("p",null,"And change the CMD to ENTRYPOINT with the format ",(0,o.kt)("inlineCode",{parentName:"p"},'["./script.sh"]'),". Now we can run"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker build . -t curler-v2\n$ docker run curler-v2 helsinki.fi\n\n Searching..\n % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n 100 232 100 232 0 0 13647 0 --:--:-- --:--:-- --:--:-- 13647\n \n \n 301 Moved Permanently\n \n

Moved Permanently

\n

The document has moved here.

\n \n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5e47b935.ace70494.js b/assets/js/5e47b935.ace70494.js new file mode 100644 index 00000000..5f36a700 --- /dev/null +++ b/assets/js/5e47b935.ace70494.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[948],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),m=r,h=c["".concat(s,".").concat(m)]||c[m]||d[m]||a;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>u});var o=n(7462),r=(n(7294),n(3905));const a={title:"Running and stopping containers"},i=void 0,l={unversionedId:"part-1/section-2",id:"part-1/section-2",title:"Running and stopping containers",description:"Next we will start using a more useful image than hello-world. We can run Ubuntu just with docker run ubuntu.",source:"@site/docs/part-1/section-2.md",sourceDirName:"part-1",slug:"/part-1/section-2",permalink:"/part-1/section-2",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-2.md",tags:[],version:"current",frontMatter:{title:"Running and stopping containers"},sidebar:"materialSidebar",previous:{title:"Definitions and basic concepts",permalink:"/part-1/section-1"},next:{title:"In-depth dive into images",permalink:"/part-1/section-3"}},s={},u=[{value:"Running processes inside a container with docker exec",id:"running-processes-inside-a-container-with-docker-exec",level:3},{value:"Exercise 1.3",id:"exercise-13",level:3},{value:"Nonmatching host platform",id:"nonmatching-host-platform",level:2},{value:"Ubuntu in a container is just... Ubuntu",id:"ubuntu-in-a-container-is-just-ubuntu",level:2},{value:"Exercise 1.4",id:"exercise-14",level:2}],p={toc:u},c="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Next we will start using a more useful image than hello-world. We can run Ubuntu just with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run ubuntu"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run ubuntu\n Unable to find image 'ubuntu:latest' locally\n latest: Pulling from library/ubuntu\n 83ee3a23efb7: Pull complete\n db98fc6f11f0: Pull complete\n f611acd52c6c: Pull complete\n Digest: sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715\n Status: Downloaded newer image for ubuntu:latest\n")),(0,r.kt)("p",null,"Anticlimactic as nothing really happened. The image was downloaded and ran and that was the end of that. It actually tried to open a shell but we will need to add a few flags to interact with it. ",(0,r.kt)("inlineCode",{parentName:"p"},"-t")," will create a ",(0,r.kt)("a",{parentName:"p",href:"https://itsfoss.com/what-is-tty-in-linux/"},"tty"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -t ubuntu\n root@f83969ce2cd1:/#\n")),(0,r.kt)("p",null,"Now we're inside the container and if we input ",(0,r.kt)("inlineCode",{parentName:"p"},"ls")," and press enter... nothing happens. Because our terminal is not sending the messages into the container. The ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," flag will instruct to pass the STDIN to the container. If you're stuck with the other terminal you can just stop the container."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\n root@2eb70ecf5789:/# ls\n bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var\n")),(0,r.kt)("p",null,"Great! Now we know at least 3 useful flags. ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," (interactive), ",(0,r.kt)("inlineCode",{parentName:"p"},"-t")," (tty) and ",(0,r.kt)("inlineCode",{parentName:"p"},"-d")," (detached)."),(0,r.kt)("p",null,"Let's throw in a few more and run a container in the background:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -d -it --name looper ubuntu sh -c 'while true; do date; sleep 1; done'\n")),(0,r.kt)("admonition",{title:"Quotes",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"If you are command prompt (Windows) user you must use double quotes around the script i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},'docker run -d -it --name looper ubuntu sh -c "while true; do date; sleep 1; done"'),". The quote or double-quote may haunt you later during the course.")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The first part, ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run -d"),". Should be familiar by now, run container detached.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Followed by ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," is short for ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"-t"),". Also familiar, ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," allows you to interact with the container by using the command line.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Because we ran the container with ",(0,r.kt)("inlineCode",{parentName:"p"},"--name looper"),", we can now reference it easily.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The image is ",(0,r.kt)("inlineCode",{parentName:"p"},"ubuntu")," and what follows it is the command given to the container."))),(0,r.kt)("p",null,"And to check that it's running, run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker container ls")),(0,r.kt)("p",null,"Let's follow ",(0,r.kt)("inlineCode",{parentName:"p"},"-f")," the output of logs with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker logs -f looper\n Thu Mar 1 15:51:29 UTC 2023\n Thu Mar 1 15:51:30 UTC 2023\n Thu Mar 1 15:51:31 UTC 2023\n ...\n")),(0,r.kt)("p",null,"Let's test pausing the looper without exiting or stopping it. In another terminal run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker pause looper"),". Notice how the logs output has paused in the first terminal. To unpause run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker unpause looper"),"."),(0,r.kt)("p",null,"Keep the logs open and attach to the running container from the second terminal using 'attach':"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker attach looper\n Thu Mar 1 15:54:38 UTC 2023\n Thu Mar 1 15:54:39 UTC 2023\n ...\n")),(0,r.kt)("p",null,"Now you have process logs (STDOUT) running in two terminals. Now press control+c in the attached window. The container is stopped because the process is no longer running."),(0,r.kt)("p",null,"If we want to attach to a container while making sure we don't close it from the other terminal we can specify to not attach STDIN with ",(0,r.kt)("inlineCode",{parentName:"p"},"--no-stdin")," option. Let's start the stopped container with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker start looper")," and attach to it with ",(0,r.kt)("inlineCode",{parentName:"p"},"--no-stdin"),"."),(0,r.kt)("p",null,"Then try control+c."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker start looper\n\n$ docker attach --no-stdin looper\n Thu Mar 1 15:56:11 UTC 2023\n Thu Mar 1 15:56:12 UTC 2023\n ^C\n")),(0,r.kt)("p",null,"The container will continue running. Control+c now only disconnects you from the STDOUT."),(0,r.kt)("h3",{id:"running-processes-inside-a-container-with-docker-exec"},"Running processes inside a container with docker exec"),(0,r.kt)("p",null,"We often encounter situations where we need to execute commands within a running container. This can be achieved using the ",(0,r.kt)("inlineCode",{parentName:"p"},"docker exec")," command."),(0,r.kt)("p",null,"We could e.g. list all the files inside the container default directory (which is the root) as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker exec looper ls -la\ntotal 56\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 .\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 ..\n-rwxr-xr-x 1 root root 0 Mar 6 10:24 .dockerenv\nlrwxrwxrwx 1 root root 7 Feb 27 16:01 bin -> usr/bin\ndrwxr-xr-x 2 root root 4096 Apr 18 2022 boot\ndrwxr-xr-x 5 root root 360 Mar 6 10:24 dev\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 etc\ndrwxr-xr-x 2 root root 4096 Apr 18 2022 home\nlrwxrwxrwx 1 root root 7 Feb 27 16:01 lib -> usr/lib\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 media\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 mnt\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 opt\ndr-xr-xr-x 293 root root 0 Mar 6 10:24 proc\ndrwx------ 2 root root 4096 Feb 27 16:08 root\ndrwxr-xr-x 5 root root 4096 Feb 27 16:08 run\nlrwxrwxrwx 1 root root 8 Feb 27 16:01 sbin -> usr/sbin\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 srv\ndr-xr-xr-x 13 root root 0 Mar 6 10:24 sys\ndrwxrwxrwt 2 root root 4096 Feb 27 16:08 tmp\ndrwxr-xr-x 11 root root 4096 Feb 27 16:01 usr\ndrwxr-xr-x 11 root root 4096 Feb 27 16:08 var\n")),(0,r.kt)("p",null,"We can execute the Bash shell in the container in interactive mode and then run any commands within that Bash session:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker exec -it looper bash\n\n root@2a49df3ba735:/# ps aux\n\n USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\n root 1 0.2 0.0 2612 1512 pts/0 Ss+ 12:36 0:00 sh -c while true; do date; sleep 1; done\n root 64 1.5 0.0 4112 3460 pts/1 Ss 12:36 0:00 bash\n root 79 0.0 0.0 2512 584 pts/0 S+ 12:36 0:00 sleep 1\n root 80 0.0 0.0 5900 2844 pts/1 R+ 12:36 0:00 ps aux\n")),(0,r.kt)("p",null,"From the ",(0,r.kt)("inlineCode",{parentName:"p"},"ps aux")," listing we can see that our ",(0,r.kt)("inlineCode",{parentName:"p"},"bash")," process got PID (process ID) of 64."),(0,r.kt)("p",null,"Now that we're inside the container it behaves as you'd expect from Ubuntu, and we can exit the container with ",(0,r.kt)("inlineCode",{parentName:"p"},"exit")," and then either kill or stop the container."),(0,r.kt)("p",null,"Our looper won't stop for a SIGTERM signal sent by a stop command. To terminate the process, stop follows the SIGTERM with a SIGKILL after a grace period. In this case, it's simply faster to use kill."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker kill looper\n$ docker rm looper\n")),(0,r.kt)("p",null,"Running the previous two commands is basically equivalent to running ",(0,r.kt)("inlineCode",{parentName:"p"},"docker rm --force looper")),(0,r.kt)("p",null,"Let's start another process with ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," and add ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," in order to remove it automatically after it has exited. The ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," ensures that there are no garbage containers left behind. It also means that ",(0,r.kt)("inlineCode",{parentName:"p"},"docker start")," can not be used to start the container after it has exited."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -d --rm -it --name looper-it ubuntu sh -c 'while true; do date; sleep 1; done'\n")),(0,r.kt)("p",null,"Now let's attach to the container and hit control+p, control+q to detach us from the STDOUT."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker attach looper-it\n\n Mon Jan 15 19:50:42 UTC 2018\n Mon Jan 15 19:50:43 UTC 2018\n ^P^Qread escape sequence\n")),(0,r.kt)("p",null,"Instead, if we had used ctrl+c, it would have sent a kill signal followed by removing the container as we specified ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run")," command."),(0,r.kt)("h3",{id:"exercise-13"},"Exercise 1.3"),(0,r.kt)("admonition",{title:"Exercise 1.3: Secret message",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Now that we've warmed up it's time to get inside a container while it's running!"),(0,r.kt)("p",{parentName:"admonition"},"Image ",(0,r.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu")," will start a container that outputs logs into a file. Go inside the running container and use ",(0,r.kt)("inlineCode",{parentName:"p"},"tail -f ./text.log"),' to follow the logs. Every 10 seconds the clock will send you a "secret message".'),(0,r.kt)("p",{parentName:"admonition"},"Submit the secret message and command(s) given as your answer.")),(0,r.kt)("h2",{id:"nonmatching-host-platform"},"Nonmatching host platform"),(0,r.kt)("p",null,"If you are working with M1/M2 Mac, you quite likely end up with the following warning when running the image ",(0,r.kt)("em",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"WARNING: The requested image's platform (linux/amd64) does not match the detected \nhost platform (linux/arm64/v8) and no specific platform was requested\n")),(0,r.kt)("p",null,"Despite this warning, you can run the container. The warning basically says what's wrong, the image uses a different processor architecture than your machine."),(0,r.kt)("p",null,"The image can be used because Docker Desktop for Mac employs an emulator by default when the image's processor architecture does not match the host's. However, it's important to note that emulated execution may be less efficient in terms of performance than running the image on a compatible native processor architecture."),(0,r.kt)("p",null,"When you run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run ubuntu")," for example, you don't get a warning, why is that? Quite a few popular images are so-called ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/build/building/multi-platform/"},"multi platform images"),", which means that one image contains variations for different architectures. When you are about to pull or run such an image, Docker will detect the host architecture and give you the correct type of image."),(0,r.kt)("h2",{id:"ubuntu-in-a-container-is-just-ubuntu"},"Ubuntu in a container is just... Ubuntu"),(0,r.kt)("p",null,"A container that is running a Ubuntu image works quite like a normal Ubuntu:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\nroot@881a1d4ecff2:/# ls\nbin dev home media opt root sbin sys usr\nboot etc lib mnt proc run srv tmp var\nroot@881a1d4ecff2:/# ps\n PID TTY TIME CMD\n 1 pts/0 00:00:00 bash\n 13 pts/0 00:00:00 ps\nroot@881a1d4ecff2:/# date\nWed Mar 1 12:08:24 UTC 2023\nroot@881a1d4ecff2:/#\n")),(0,r.kt)("p",null,"An image like Ubuntu contains already a nice set of tools but sometimes just the one that we need is not within the standard distribution. Let us assume that we would like to edit some files inside the container. The good old ",(0,r.kt)("a",{parentName:"p",href:"https://www.nano-editor.org/"},"Nano")," editor is a perfect fit for our purposes. We can install it in the container by using ",(0,r.kt)("a",{parentName:"p",href:"https://help.ubuntu.com/community/AptGet/Howto"},"apt-get"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\nroot@881a1d4ecff2:/# apt-get update\nroot@881a1d4ecff2:/# apt-get -y install nano\nroot@881a1d4ecff2:/# cd tmp/\nroot@881a1d4ecff2:/tmp# nano temp_file.txt\n")),(0,r.kt)("p",null,'As can be seen, installing a program or library to a container happens just like the installation is done in "normal" Ubuntu. The remarkable difference is that the installation of Nano is not permanent, that is, if we remove our container, all is gone. We shall soon see how to get a more permanent solution for building images that are perfect to our purposes.'),(0,r.kt)("h2",{id:"exercise-14"},"Exercise 1.4"),(0,r.kt)("admonition",{title:"Exercise 1.4: Missing dependencies",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Start a Ubuntu image with the process ",(0,r.kt)("inlineCode",{parentName:"p"},'sh -c \'while true; do echo "Input website:"; read website; echo "Searching.."; sleep 1; curl http://$website; done\'')),(0,r.kt)("p",{parentName:"admonition"},"If you're on Windows, you'll want to switch the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," and ",(0,r.kt)("inlineCode",{parentName:"p"},'"')," around: ",(0,r.kt)("inlineCode",{parentName:"p"},"sh -c \"while true; do echo 'Input website:'; read website; echo 'Searching..'; sleep 1; curl http://$website; done\""),"."),(0,r.kt)("p",{parentName:"admonition"},"You will notice that a few things required for proper execution are missing. Be sure to remind yourself which flags to use so that the container actually waits for input."),(0,r.kt)("blockquote",{parentName:"admonition"},(0,r.kt)("p",{parentName:"blockquote"},"Note also that curl is NOT installed in the container yet. You will have to install it from inside of the container.")),(0,r.kt)("p",{parentName:"admonition"},"Test inputting ",(0,r.kt)("inlineCode",{parentName:"p"},"helsinki.fi")," into the application. It should respond with something like"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre",className:"language-html"},'\n \n 301 Moved Permanently\n \n\n \n

Moved Permanently

\n

The document has moved here.

\n \n\n')),(0,r.kt)("p",{parentName:"admonition"},"This time return the command you used to start process and the command(s) you used to fix the ensuing problems."),(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"Hint")," for installing the missing dependencies you could start a new process with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker exec"),"."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"This exercise has multiple solutions, if the curl for helsinki.fi works then it's done. Can you figure out other (smart) solutions?"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5e47b935.e8cb86a8.js b/assets/js/5e47b935.e8cb86a8.js deleted file mode 100644 index 55b68d80..00000000 --- a/assets/js/5e47b935.e8cb86a8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[948],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),m=r,h=c["".concat(s,".").concat(m)]||c[m]||d[m]||a;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>u});var o=n(7462),r=(n(7294),n(3905));const a={title:"Running and stopping containers"},i=void 0,l={unversionedId:"part-1/section-2",id:"part-1/section-2",title:"Running and stopping containers",description:"Next we will start using a more useful image than hello-world. We can run Ubuntu just with docker run ubuntu.",source:"@site/docs/part-1/section-2.md",sourceDirName:"part-1",slug:"/part-1/section-2",permalink:"/part-1/section-2",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-2.md",tags:[],version:"current",frontMatter:{title:"Running and stopping containers"},sidebar:"materialSidebar",previous:{title:"Definitions and basic concepts",permalink:"/part-1/section-1"},next:{title:"In-depth dive to images",permalink:"/part-1/section-3"}},s={},u=[{value:"Running processes inside a container with docker exec",id:"running-processes-inside-a-container-with-docker-exec",level:3},{value:"Exercise 1.3",id:"exercise-13",level:3},{value:"Nonmatching host platform",id:"nonmatching-host-platform",level:2},{value:"Ubuntu in a container is just... Ubuntu",id:"ubuntu-in-a-container-is-just-ubuntu",level:2},{value:"Exercise 1.4",id:"exercise-14",level:2}],p={toc:u},c="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Next we will start using a more useful image than hello-world. We can run Ubuntu just with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run ubuntu"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run ubuntu\n Unable to find image 'ubuntu:latest' locally\n latest: Pulling from library/ubuntu\n 83ee3a23efb7: Pull complete\n db98fc6f11f0: Pull complete\n f611acd52c6c: Pull complete\n Digest: sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715\n Status: Downloaded newer image for ubuntu:latest\n")),(0,r.kt)("p",null,"Anticlimactic as nothing really happened. The image was downloaded and ran and that was the end of that. It actually tried to open a shell but we will need to add a few flags to interact with it. ",(0,r.kt)("inlineCode",{parentName:"p"},"-t")," will create a ",(0,r.kt)("a",{parentName:"p",href:"https://itsfoss.com/what-is-tty-in-linux/"},"tty"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -t ubuntu\n root@f83969ce2cd1:/#\n")),(0,r.kt)("p",null,"Now we're inside the container and if we input ",(0,r.kt)("inlineCode",{parentName:"p"},"ls")," and press enter... nothing happens. Because our terminal is not sending the messages into the container. The ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," flag will instruct to pass the STDIN to the container. If you're stuck with the other terminal you can just stop the container."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\n root@2eb70ecf5789:/# ls\n bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var\n")),(0,r.kt)("p",null,"Great! Now we know at least 3 useful flags. ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," (interactive), ",(0,r.kt)("inlineCode",{parentName:"p"},"-t")," (tty) and ",(0,r.kt)("inlineCode",{parentName:"p"},"-d")," (detached)."),(0,r.kt)("p",null,"Let's throw in a few more and run a container in the background:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -d -it --name looper ubuntu sh -c 'while true; do date; sleep 1; done'\n")),(0,r.kt)("admonition",{title:"Quotes",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"If you are command prompt (Windows) user you must use double quotes around the script i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},'docker run -d -it --name looper ubuntu sh -c "while true; do date; sleep 1; done"'),". The quote or double-quote may haunt you later during the course.")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The first part, ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run -d"),". Should be familiar by now, run container detached.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Followed by ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," is short for ",(0,r.kt)("inlineCode",{parentName:"p"},"-i")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"-t"),". Also familiar, ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," allows you to interact with the container by using the command line.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Because we ran the container with ",(0,r.kt)("inlineCode",{parentName:"p"},"--name looper"),", we can now reference it easily.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The image is ",(0,r.kt)("inlineCode",{parentName:"p"},"ubuntu")," and what follows it is the command given to the container."))),(0,r.kt)("p",null,"And to check that it's running, run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker container ls")),(0,r.kt)("p",null,"Let's follow ",(0,r.kt)("inlineCode",{parentName:"p"},"-f")," the output of logs with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker logs -f looper\n Thu Mar 1 15:51:29 UTC 2023\n Thu Mar 1 15:51:30 UTC 2023\n Thu Mar 1 15:51:31 UTC 2023\n ...\n")),(0,r.kt)("p",null,"Let's test pausing the looper without exiting or stopping it. In another terminal run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker pause looper"),". Notice how the logs output has paused in the first terminal. To unpause run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker unpause looper"),"."),(0,r.kt)("p",null,"Keep the logs open and attach to the running container from the second terminal using 'attach':"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker attach looper\n Thu Mar 1 15:54:38 UTC 2023\n Thu Mar 1 15:54:39 UTC 2023\n ...\n")),(0,r.kt)("p",null,"Now you have process logs (STDOUT) running in two terminals. Now press control+c in the attached window. The container is stopped because the process is no longer running."),(0,r.kt)("p",null,"If we want to attach to a container while making sure we don't close it from the other terminal we can specify to not attach STDIN with ",(0,r.kt)("inlineCode",{parentName:"p"},"--no-stdin")," option. Let's start the stopped container with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker start looper")," and attach to it with ",(0,r.kt)("inlineCode",{parentName:"p"},"--no-stdin"),"."),(0,r.kt)("p",null,"Then try control+c."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker start looper\n\n$ docker attach --no-stdin looper\n Thu Mar 1 15:56:11 UTC 2023\n Thu Mar 1 15:56:12 UTC 2023\n ^C\n")),(0,r.kt)("p",null,"The container will continue running. Control+c now only disconnects you from the STDOUT."),(0,r.kt)("h3",{id:"running-processes-inside-a-container-with-docker-exec"},"Running processes inside a container with docker exec"),(0,r.kt)("p",null,"We often encounter situations where we need to execute commands within a running container. This can be achieved using the ",(0,r.kt)("inlineCode",{parentName:"p"},"docker exec")," command."),(0,r.kt)("p",null,"We could e.g. list all the files inside the container default directory (which is the root) as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker exec looper ls -la\ntotal 56\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 .\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 ..\n-rwxr-xr-x 1 root root 0 Mar 6 10:24 .dockerenv\nlrwxrwxrwx 1 root root 7 Feb 27 16:01 bin -> usr/bin\ndrwxr-xr-x 2 root root 4096 Apr 18 2022 boot\ndrwxr-xr-x 5 root root 360 Mar 6 10:24 dev\ndrwxr-xr-x 1 root root 4096 Mar 6 10:24 etc\ndrwxr-xr-x 2 root root 4096 Apr 18 2022 home\nlrwxrwxrwx 1 root root 7 Feb 27 16:01 lib -> usr/lib\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 media\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 mnt\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 opt\ndr-xr-xr-x 293 root root 0 Mar 6 10:24 proc\ndrwx------ 2 root root 4096 Feb 27 16:08 root\ndrwxr-xr-x 5 root root 4096 Feb 27 16:08 run\nlrwxrwxrwx 1 root root 8 Feb 27 16:01 sbin -> usr/sbin\ndrwxr-xr-x 2 root root 4096 Feb 27 16:01 srv\ndr-xr-xr-x 13 root root 0 Mar 6 10:24 sys\ndrwxrwxrwt 2 root root 4096 Feb 27 16:08 tmp\ndrwxr-xr-x 11 root root 4096 Feb 27 16:01 usr\ndrwxr-xr-x 11 root root 4096 Feb 27 16:08 var\n")),(0,r.kt)("p",null,"We can execute the Bash shell in the container in interactive mode and then run any commands within that Bash session:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker exec -it looper bash\n\n root@2a49df3ba735:/# ps aux\n\n USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\n root 1 0.2 0.0 2612 1512 pts/0 Ss+ 12:36 0:00 sh -c while true; do date; sleep 1; done\n root 64 1.5 0.0 4112 3460 pts/1 Ss 12:36 0:00 bash\n root 79 0.0 0.0 2512 584 pts/0 S+ 12:36 0:00 sleep 1\n root 80 0.0 0.0 5900 2844 pts/1 R+ 12:36 0:00 ps aux\n")),(0,r.kt)("p",null,"From the ",(0,r.kt)("inlineCode",{parentName:"p"},"ps aux")," listing we can see that our ",(0,r.kt)("inlineCode",{parentName:"p"},"bash")," process got PID (process ID) of 64."),(0,r.kt)("p",null,"Now that we're inside the container it behaves as you'd expect from Ubuntu, and we can exit the container with ",(0,r.kt)("inlineCode",{parentName:"p"},"exit")," and then either kill or stop the container."),(0,r.kt)("p",null,"Our looper won't stop for a SIGTERM signal sent by a stop command. To terminate the process, stop follows the SIGTERM with a SIGKILL after a grace period. In this case, it's simply faster to use kill."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker kill looper\n$ docker rm looper\n")),(0,r.kt)("p",null,"Running the previous two commands is basically equivalent to running ",(0,r.kt)("inlineCode",{parentName:"p"},"docker rm --force looper")),(0,r.kt)("p",null,"Let's start another process with ",(0,r.kt)("inlineCode",{parentName:"p"},"-it")," and add ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," in order to remove it automatically after it has exited. The ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," ensures that there are no garbage containers left behind. It also means that ",(0,r.kt)("inlineCode",{parentName:"p"},"docker start")," can not be used to start the container after it has exited."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -d --rm -it --name looper-it ubuntu sh -c 'while true; do date; sleep 1; done'\n")),(0,r.kt)("p",null,"Now let's attach to the container and hit control+p, control+q to detach us from the STDOUT."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker attach looper-it\n\n Mon Jan 15 19:50:42 UTC 2018\n Mon Jan 15 19:50:43 UTC 2018\n ^P^Qread escape sequence\n")),(0,r.kt)("p",null,"Instead, if we had used ctrl+c, it would have sent a kill signal followed by removing the container as we specified ",(0,r.kt)("inlineCode",{parentName:"p"},"--rm")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run")," command."),(0,r.kt)("h3",{id:"exercise-13"},"Exercise 1.3"),(0,r.kt)("admonition",{title:"Exercise 1.3: Secret message",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Now that we've warmed up it's time to get inside a container while it's running!"),(0,r.kt)("p",{parentName:"admonition"},"Image ",(0,r.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu")," will start a container that outputs logs into a file. Go inside the running container and use ",(0,r.kt)("inlineCode",{parentName:"p"},"tail -f ./text.log"),' to follow the logs. Every 10 seconds the clock will send you a "secret message".'),(0,r.kt)("p",{parentName:"admonition"},"Submit the secret message and command(s) given as your answer.")),(0,r.kt)("h2",{id:"nonmatching-host-platform"},"Nonmatching host platform"),(0,r.kt)("p",null,"If you are working with M1/M2 Mac, you quite likely end up with the following warning when running the image ",(0,r.kt)("em",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"WARNING: The requested image's platform (linux/amd64) does not match the detected \nhost platform (linux/arm64/v8) and no specific platform was requested\n")),(0,r.kt)("p",null,"Despite this warning, you can run the container. The warning basically says what's wrong, the image uses a different processor architecture than your machine."),(0,r.kt)("p",null,"The image can be used because Docker Desktop for Mac employs an emulator by default when the image's processor architecture does not match the host's. However, it's important to note that emulated execution may be less efficient in terms of performance than running the image on a compatible native processor architecture."),(0,r.kt)("p",null,"When you run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker run ubuntu")," for example, you don't get a warning, why is that? Quite a few popular images are so-called ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/build/building/multi-platform/"},"multi platform images"),", which means that one image contains variations for different architectures. When you are about to pull or run such an image, Docker will detect the host architecture and give you the correct type of image."),(0,r.kt)("h2",{id:"ubuntu-in-a-container-is-just-ubuntu"},"Ubuntu in a container is just... Ubuntu"),(0,r.kt)("p",null,"A container that is running a Ubuntu image works quite like a normal Ubuntu:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\nroot@881a1d4ecff2:/# ls\nbin dev home media opt root sbin sys usr\nboot etc lib mnt proc run srv tmp var\nroot@881a1d4ecff2:/# ps\n PID TTY TIME CMD\n 1 pts/0 00:00:00 bash\n 13 pts/0 00:00:00 ps\nroot@881a1d4ecff2:/# date\nWed Mar 1 12:08:24 UTC 2023\nroot@881a1d4ecff2:/#\n")),(0,r.kt)("p",null,"An image like Ubuntu contains already a nice set of tools but sometimes just the one that we need is not within the standard distribution. Let us assume that we would like to edit some files inside the container. The good old ",(0,r.kt)("a",{parentName:"p",href:"https://www.nano-editor.org/"},"Nano")," editor is a perfect fit for our purposes. We can install it in the container by using ",(0,r.kt)("a",{parentName:"p",href:"https://help.ubuntu.com/community/AptGet/Howto"},"apt-get"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-console"},"$ docker run -it ubuntu\nroot@881a1d4ecff2:/# apt-get update\nroot@881a1d4ecff2:/# apt-get -y install nano\nroot@881a1d4ecff2:/# cd tmp/\nroot@881a1d4ecff2:/tmp# nano temp_file.txt\n")),(0,r.kt)("p",null,'As can be seen, installing a program or library to a container happens just like the installation is done in "normal" Ubuntu. The remarkable difference is that the installation of Nano is not permanent, that is, if we remove our container, all is gone. We shall soon see how to get a more permanent solution for building images that are perfect to our purposes.'),(0,r.kt)("h2",{id:"exercise-14"},"Exercise 1.4"),(0,r.kt)("admonition",{title:"Exercise 1.4: Missing dependencies",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Start a Ubuntu image with the process ",(0,r.kt)("inlineCode",{parentName:"p"},'sh -c \'while true; do echo "Input website:"; read website; echo "Searching.."; sleep 1; curl http://$website; done\'')),(0,r.kt)("p",{parentName:"admonition"},"If you're on Windows, you'll want to switch the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," and ",(0,r.kt)("inlineCode",{parentName:"p"},'"')," around: ",(0,r.kt)("inlineCode",{parentName:"p"},"sh -c \"while true; do echo 'Input website:'; read website; echo 'Searching..'; sleep 1; curl http://$website; done\""),"."),(0,r.kt)("p",{parentName:"admonition"},"You will notice that a few things required for proper execution are missing. Be sure to remind yourself which flags to use so that the container actually waits for input."),(0,r.kt)("blockquote",{parentName:"admonition"},(0,r.kt)("p",{parentName:"blockquote"},"Note also that curl is NOT installed in the container yet. You will have to install it from inside of the container.")),(0,r.kt)("p",{parentName:"admonition"},"Test inputting ",(0,r.kt)("inlineCode",{parentName:"p"},"helsinki.fi")," into the application. It should respond with something like"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre",className:"language-html"},'\n \n 301 Moved Permanently\n \n\n \n

Moved Permanently

\n

The document has moved here.

\n \n\n')),(0,r.kt)("p",{parentName:"admonition"},"This time return the command you used to start process and the command(s) you used to fix the ensuing problems."),(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"Hint")," for installing the missing dependencies you could start a new process with ",(0,r.kt)("inlineCode",{parentName:"p"},"docker exec"),"."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"This exercise has multiple solutions, if the curl for helsinki.fi works then it's done. Can you figure out other (smart) solutions?"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.c2f0fad2.js b/assets/js/935f2afb.c2f0fad2.js deleted file mode 100644 index e4f71b37..00000000 --- a/assets/js/935f2afb.c2f0fad2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"materialSidebar":[{"type":"link","label":"DevOps with Docker","href":"/","className":"hidden","docId":"intro"},{"type":"link","label":"Getting Started","href":"/getting-started","docId":"getting-started"},{"type":"link","label":"Frequently Asked Questions","href":"/faq","docId":"faq"},{"type":"category","label":"Part 1","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 1","href":"/part-1/","docId":"part-1/index"},{"type":"link","label":"Definitions and basic concepts","href":"/part-1/section-1","docId":"part-1/section-1"},{"type":"link","label":"Running and stopping containers","href":"/part-1/section-2","docId":"part-1/section-2"},{"type":"link","label":"In-depth dive to images","href":"/part-1/section-3","docId":"part-1/section-3"},{"type":"link","label":"Defining start conditions for the container","href":"/part-1/section-4","docId":"part-1/section-4"},{"type":"link","label":"Interacting with the container via volumes and ports","href":"/part-1/section-5","docId":"part-1/section-5"},{"type":"link","label":"Utilizing tools from the Registry","href":"/part-1/section-6","docId":"part-1/section-6"},{"type":"link","label":"Summary","href":"/part-1/section-7","docId":"part-1/section-7"}],"href":"/category/part-1"},{"type":"category","label":"Part 2","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 2","href":"/part-2/","docId":"part-2/index"},{"type":"link","label":"Migrating to Docker Compose","href":"/part-2/section-1","docId":"part-2/section-1"},{"type":"link","label":"Docker networking","href":"/part-2/section-2","docId":"part-2/section-2"},{"type":"link","label":"Volumes in action","href":"/part-2/section-3","docId":"part-2/section-3"},{"type":"link","label":"Containers in development","href":"/part-2/section-4","docId":"part-2/section-4"},{"type":"link","label":"Summary","href":"/part-2/section-5","docId":"part-2/section-5"}],"href":"/category/part-2"},{"type":"category","label":"Part 3","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 3","href":"/part-3/","docId":"part-3/index"},{"type":"link","label":"Official Images and trust","href":"/part-3/section-1","docId":"part-3/section-1"},{"type":"link","label":"Deployment pipelines","href":"/part-3/section-2","docId":"part-3/section-2"},{"type":"link","label":"Using a non-root user","href":"/part-3/section-3","docId":"part-3/section-3"},{"type":"link","label":"Optimizing the image size","href":"/part-3/section-4","docId":"part-3/section-4"},{"type":"link","label":"Multi-host environments","href":"/part-3/section-5","docId":"part-3/section-5"},{"type":"link","label":"End","href":"/part-3/section-6","docId":"part-3/section-6"}],"href":"/category/part-3"},{"type":"link","label":"Credits","href":"/credits","className":"hidden","docId":"credits"}]},"docs":{"credits":{"id":"credits","title":"Credits","description":"The DevOps with Docker course was created by Jami Kousa with the help of University of Helsinki\'s Tietojenk\xe4sittelytieteen osaston sovelluskehitysakatemia (Toska) and numerous course attendees. This material is based on gist by Matti Paksula. You can help develop the course material as well.","sidebar":"materialSidebar"},"faq":{"id":"faq","title":"Frequently Asked Questions","description":"How do I sign up for the course?","sidebar":"materialSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it\'s important to read the material carefully and complete the exercises in order to develop the necessary skills.","sidebar":"materialSidebar"},"intro":{"id":"intro","title":"DevOps with Docker","description":"This course provides an introduction to container technologies, with a particular focus on Docker and container orchestration using Docker Compose. Containers are a lightweight, portable way to package and deploy software applications. Throughout the course, we\'ll explore the various components of web services, such as reverse proxies and databases, and how they can be deployed using Docker.","sidebar":"materialSidebar"},"part-1/index":{"id":"part-1/index","title":"Introduction to Part 1","description":"This part introduces containerization with Docker and relevant concepts such as image and volume. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-1/section-1":{"id":"part-1/section-1","title":"Definitions and basic concepts","description":"What is DevOps?","sidebar":"materialSidebar"},"part-1/section-2":{"id":"part-1/section-2","title":"Running and stopping containers","description":"Next we will start using a more useful image than hello-world. We can run Ubuntu just with docker run ubuntu.","sidebar":"materialSidebar"},"part-1/section-3":{"id":"part-1/section-3","title":"In-depth dive to images","description":"Images are the basic building blocks for containers and other images. When you \\"containerize\\" an application you work towards creating the image.","sidebar":"materialSidebar"},"part-1/section-4":{"id":"part-1/section-4","title":"Defining start conditions for the container","description":"Next, we will start moving towards a more meaningful image. youtube-dl is a program that downloads Youtube videos . Let\'s add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let\'s try another approach. This time we will open up an interactive session and test stuff before \\"storing\\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:","sidebar":"materialSidebar"},"part-1/section-5":{"id":"part-1/section-5","title":"Interacting with the container via volumes and ports","description":"Let us get back to youtube downloader. It works yes, but it is quite laborous to get the download videos to the host machine.","sidebar":"materialSidebar"},"part-1/section-6":{"id":"part-1/section-6","title":"Utilizing tools from the Registry","description":"As we\'ve already seen it should be possible to containerize almost any project. As we are in between Dev and Ops let\'s pretend again that some developer teammates of ours did an application with a README that instructs what to install and how to run the application. Now we as the container experts can containerize it in seconds. Open this project and read through the README and think about how to transform it into a Dockerfile. Thanks to the README we should be able to decipher what we will need to do even if we have no clue about the language or technology!","sidebar":"materialSidebar"},"part-1/section-7":{"id":"part-1/section-7","title":"Summary","description":"We started by learning what Docker container and image mean. Basically we started from an empty ubuntu with nothing installed into it. It\'s also possible to start from something else, but for now ubuntu had been enough.","sidebar":"materialSidebar"},"part-2/index":{"id":"part-2/index","title":"Introduction to Part 2","description":"This part introduces container orchestration with Docker Compose and relevant concepts such as docker network. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-2/section-1":{"id":"part-2/section-1","title":"Migrating to Docker Compose","description":"Even with a simple image, we\'ve already been dealing with plenty of command line options in both building, pushing and running the image.","sidebar":"materialSidebar"},"part-2/section-2":{"id":"part-2/section-2","title":"Docker networking","description":"Connecting two services such as a server and its Database in docker can be achieved with a Docker network. In addition to starting services listed in docker-compose.yml Docker Compose automatically creates and joins both containers into a network with a DNS. Each service is named after the name given in the docker-compose.yml file. As such, containers can reference each other simply with their service names, which is different from the container name.","sidebar":"materialSidebar"},"part-2/section-3":{"id":"part-2/section-3","title":"Volumes in action","description":"Next we\'re going to set up the project management application Redmine, a PostgreSQL database and Adminer, a graphical interface for database administration.","sidebar":"materialSidebar"},"part-2/section-4":{"id":"part-2/section-4","title":"Containers in development","description":"Containers are not only great in production. They can be used in development environments as well and offer a number of benefits. The same works-on-my-machine problem is faced often when a new developer joins the team. Not to mention the headache of switching runtime versions or a local database!","sidebar":"materialSidebar"},"part-2/section-5":{"id":"part-2/section-5","title":"Summary","description":"Again we started from the ground up by learning how to translate non-compose setup into docker-compose.yml and ran with it. Compose gave us also a few handy completely new features that we didn\'t even know we needed, networks.","sidebar":"materialSidebar"},"part-3/index":{"id":"part-3/index","title":"Introduction to Part 3","description":"This part introduces production-ready practices such as container optimization and deployment pipelines. We\'ll also familiarize ourselves with other container orchestration solutions. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-3/section-1":{"id":"part-3/section-1","title":"Official Images and trust","description":"We\'ve focused on using Docker as a tool to solve various types of problems. Meanwhile we have decided to push some of the issues until later and completely ignored others.","sidebar":"materialSidebar"},"part-3/section-2":{"id":"part-3/section-2","title":"Deployment pipelines","description":"CI/CD pipeline (sometimes called deployment pipeline) is a corner stone of DevOps.","sidebar":"materialSidebar"},"part-3/section-3":{"id":"part-3/section-3","title":"Using a non-root user","description":"Let\'s get back to the youtube-dl application, that we for last time worked with it Part 2.","sidebar":"materialSidebar"},"part-3/section-4":{"id":"part-3/section-4","title":"Optimizing the image size","description":"A small image size has many advantages, firstly, it takes much less time to pull a small image from the registry. Another thing is the security: the bigger your image is the larger the surface area for an attack it has.","sidebar":"materialSidebar"},"part-3/section-5":{"id":"part-3/section-5","title":"Multi-host environments","description":"Now that we\'ve mastered containers in small systems with Docker Compose it\'s time to look beyond what the tools we practiced are capable of. In situations where we have more than a single host machine we cannot rely solely on Docker. However, Docker does contain other tools to help us with automatic deployment, scaling and management of dockerized applications.","sidebar":"materialSidebar"},"part-3/section-6":{"id":"part-3/section-6","title":"End","description":"Remember to mark your exercises into the submission application! Instructions on how and what to submit are on the getting started page.","sidebar":"materialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.d6534798.js b/assets/js/935f2afb.d6534798.js new file mode 100644 index 00000000..d7902ba5 --- /dev/null +++ b/assets/js/935f2afb.d6534798.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"materialSidebar":[{"type":"link","label":"DevOps with Docker","href":"/","className":"hidden","docId":"intro"},{"type":"link","label":"Getting Started","href":"/getting-started","docId":"getting-started"},{"type":"link","label":"Frequently Asked Questions","href":"/faq","docId":"faq"},{"type":"category","label":"Part 1","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 1","href":"/part-1/","docId":"part-1/index"},{"type":"link","label":"Definitions and basic concepts","href":"/part-1/section-1","docId":"part-1/section-1"},{"type":"link","label":"Running and stopping containers","href":"/part-1/section-2","docId":"part-1/section-2"},{"type":"link","label":"In-depth dive into images","href":"/part-1/section-3","docId":"part-1/section-3"},{"type":"link","label":"Defining start conditions for the container","href":"/part-1/section-4","docId":"part-1/section-4"},{"type":"link","label":"Interacting with the container via volumes and ports","href":"/part-1/section-5","docId":"part-1/section-5"},{"type":"link","label":"Utilizing tools from the Registry","href":"/part-1/section-6","docId":"part-1/section-6"},{"type":"link","label":"Summary","href":"/part-1/section-7","docId":"part-1/section-7"}],"href":"/category/part-1"},{"type":"category","label":"Part 2","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 2","href":"/part-2/","docId":"part-2/index"},{"type":"link","label":"Migrating to Docker Compose","href":"/part-2/section-1","docId":"part-2/section-1"},{"type":"link","label":"Docker networking","href":"/part-2/section-2","docId":"part-2/section-2"},{"type":"link","label":"Volumes in action","href":"/part-2/section-3","docId":"part-2/section-3"},{"type":"link","label":"Containers in development","href":"/part-2/section-4","docId":"part-2/section-4"},{"type":"link","label":"Summary","href":"/part-2/section-5","docId":"part-2/section-5"}],"href":"/category/part-2"},{"type":"category","label":"Part 3","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction to Part 3","href":"/part-3/","docId":"part-3/index"},{"type":"link","label":"Official Images and trust","href":"/part-3/section-1","docId":"part-3/section-1"},{"type":"link","label":"Deployment pipelines","href":"/part-3/section-2","docId":"part-3/section-2"},{"type":"link","label":"Using a non-root user","href":"/part-3/section-3","docId":"part-3/section-3"},{"type":"link","label":"Optimizing the image size","href":"/part-3/section-4","docId":"part-3/section-4"},{"type":"link","label":"Multi-host environments","href":"/part-3/section-5","docId":"part-3/section-5"},{"type":"link","label":"End","href":"/part-3/section-6","docId":"part-3/section-6"}],"href":"/category/part-3"},{"type":"link","label":"Credits","href":"/credits","className":"hidden","docId":"credits"}]},"docs":{"credits":{"id":"credits","title":"Credits","description":"The DevOps with Docker course was created by Jami Kousa with the help of University of Helsinki\'s Tietojenk\xe4sittelytieteen osaston sovelluskehitysakatemia (Toska) and numerous course attendees. This material is based on gist by Matti Paksula. You can help develop the course material as well.","sidebar":"materialSidebar"},"faq":{"id":"faq","title":"Frequently Asked Questions","description":"How do I sign up for the course?","sidebar":"materialSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it\'s important to read the material carefully and complete the exercises in order to develop the necessary skills.","sidebar":"materialSidebar"},"intro":{"id":"intro","title":"DevOps with Docker","description":"This course provides an introduction to container technologies, with a particular focus on Docker and container orchestration using Docker Compose. Containers are a lightweight, portable way to package and deploy software applications. Throughout the course, we\'ll explore the various components of web services, such as reverse proxies and databases, and how they can be deployed using Docker.","sidebar":"materialSidebar"},"part-1/index":{"id":"part-1/index","title":"Introduction to Part 1","description":"This part introduces containerization with Docker and relevant concepts such as image and volume. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-1/section-1":{"id":"part-1/section-1","title":"Definitions and basic concepts","description":"What is DevOps?","sidebar":"materialSidebar"},"part-1/section-2":{"id":"part-1/section-2","title":"Running and stopping containers","description":"Next we will start using a more useful image than hello-world. We can run Ubuntu just with docker run ubuntu.","sidebar":"materialSidebar"},"part-1/section-3":{"id":"part-1/section-3","title":"In-depth dive into images","description":"Images are the basic building blocks for containers and other images. When you \\"containerize\\" an application you work towards creating the image.","sidebar":"materialSidebar"},"part-1/section-4":{"id":"part-1/section-4","title":"Defining start conditions for the container","description":"Next, we will start moving towards a more meaningful image. youtube-dl is a program that downloads Youtube videos . Let\'s add it to an image - but this time, we will change our process. Instead of our current process where we add things to the Dockerfile hope it works, let\'s try another approach. This time we will open up an interactive session and test stuff before \\"storing\\" it in our Dockerfile. By following the youtube-dl install instructions we will see that:","sidebar":"materialSidebar"},"part-1/section-5":{"id":"part-1/section-5","title":"Interacting with the container via volumes and ports","description":"Let us get back to youtube downloader. It works yes, but it is quite laborous to get the download videos to the host machine.","sidebar":"materialSidebar"},"part-1/section-6":{"id":"part-1/section-6","title":"Utilizing tools from the Registry","description":"As we\'ve already seen it should be possible to containerize almost any project. As we are in between Dev and Ops let\'s pretend again that some developer teammates of ours did an application with a README that instructs what to install and how to run the application. Now we as the container experts can containerize it in seconds. Open this project and read through the README and think about how to transform it into a Dockerfile. Thanks to the README we should be able to decipher what we will need to do even if we have no clue about the language or technology!","sidebar":"materialSidebar"},"part-1/section-7":{"id":"part-1/section-7","title":"Summary","description":"We started by learning what Docker container and image mean. Basically we started from an empty ubuntu with nothing installed into it. It\'s also possible to start from something else, but for now ubuntu had been enough.","sidebar":"materialSidebar"},"part-2/index":{"id":"part-2/index","title":"Introduction to Part 2","description":"This part introduces container orchestration with Docker Compose and relevant concepts such as docker network. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-2/section-1":{"id":"part-2/section-1","title":"Migrating to Docker Compose","description":"Even with a simple image, we\'ve already been dealing with plenty of command line options in both building, pushing and running the image.","sidebar":"materialSidebar"},"part-2/section-2":{"id":"part-2/section-2","title":"Docker networking","description":"Connecting two services such as a server and its Database in docker can be achieved with a Docker network. In addition to starting services listed in docker-compose.yml Docker Compose automatically creates and joins both containers into a network with a DNS. Each service is named after the name given in the docker-compose.yml file. As such, containers can reference each other simply with their service names, which is different from the container name.","sidebar":"materialSidebar"},"part-2/section-3":{"id":"part-2/section-3","title":"Volumes in action","description":"Next we\'re going to set up the project management application Redmine, a PostgreSQL database and Adminer, a graphical interface for database administration.","sidebar":"materialSidebar"},"part-2/section-4":{"id":"part-2/section-4","title":"Containers in development","description":"Containers are not only great in production. They can be used in development environments as well and offer a number of benefits. The same works-on-my-machine problem is faced often when a new developer joins the team. Not to mention the headache of switching runtime versions or a local database!","sidebar":"materialSidebar"},"part-2/section-5":{"id":"part-2/section-5","title":"Summary","description":"Again we started from the ground up by learning how to translate non-compose setup into docker-compose.yml and ran with it. Compose gave us also a few handy completely new features that we didn\'t even know we needed, networks.","sidebar":"materialSidebar"},"part-3/index":{"id":"part-3/index","title":"Introduction to Part 3","description":"This part introduces production-ready practices such as container optimization and deployment pipelines. We\'ll also familiarize ourselves with other container orchestration solutions. By the end of this part you are able to:","sidebar":"materialSidebar"},"part-3/section-1":{"id":"part-3/section-1","title":"Official Images and trust","description":"We\'ve focused on using Docker as a tool to solve various types of problems. Meanwhile we have decided to push some of the issues until later and completely ignored others.","sidebar":"materialSidebar"},"part-3/section-2":{"id":"part-3/section-2","title":"Deployment pipelines","description":"CI/CD pipeline (sometimes called deployment pipeline) is a corner stone of DevOps.","sidebar":"materialSidebar"},"part-3/section-3":{"id":"part-3/section-3","title":"Using a non-root user","description":"Let\'s get back to the youtube-dl application, that we for last time worked with it Part 2.","sidebar":"materialSidebar"},"part-3/section-4":{"id":"part-3/section-4","title":"Optimizing the image size","description":"A small image size has many advantages, firstly, it takes much less time to pull a small image from the registry. Another thing is the security: the bigger your image is the larger the surface area for an attack it has.","sidebar":"materialSidebar"},"part-3/section-5":{"id":"part-3/section-5","title":"Multi-host environments","description":"Now that we\'ve mastered containers in small systems with Docker Compose it\'s time to look beyond what the tools we practiced are capable of. In situations where we have more than a single host machine we cannot rely solely on Docker. However, Docker does contain other tools to help us with automatic deployment, scaling and management of dockerized applications.","sidebar":"materialSidebar"},"part-3/section-6":{"id":"part-3/section-6","title":"End","description":"Remember to mark your exercises into the submission application! Instructions on how and what to submit are on the getting started page.","sidebar":"materialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/d589d3a7.11404f08.js b/assets/js/d589d3a7.11404f08.js deleted file mode 100644 index 4117c648..00000000 --- a/assets/js/d589d3a7.11404f08.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[162],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>m});var r=o(7294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function a(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var l=r.createContext({}),c=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):a(a({},t),e)),o},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var o=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(o),h=n,m=d["".concat(l,".").concat(h)]||d[h]||p[h]||i;return o?r.createElement(m,a(a({ref:t},u),{},{components:o})):r.createElement(m,a({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=o.length,a=new Array(i);a[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:n,a[1]=s;for(var c=2;c{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=o(7462),n=(o(7294),o(3905));const i={sidebar_position:2},a="Getting Started",s={unversionedId:"getting-started",id:"getting-started",title:"Getting Started",description:"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it's important to read the material carefully and complete the exercises in order to develop the necessary skills.",source:"@site/docs/getting-started.md",sourceDirName:".",slug:"/getting-started",permalink:"/getting-started",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/getting-started.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"materialSidebar",previous:{title:"DevOps with Docker",permalink:"/"},next:{title:"Frequently Asked Questions",permalink:"/faq"}},l={},c=[{value:"About different architectures and contributing",id:"about-different-architectures-and-contributing",level:3},{value:"Grading",id:"grading",level:3},{value:"Learning objectives",id:"learning-objectives",level:3},{value:"Where to find information about the course?",id:"where-to-find-information-about-the-course",level:3},{value:"Discord",id:"discord",level:3},{value:"Installing Docker",id:"installing-docker",level:2},{value:"Deadline",id:"deadline",level:2},{value:"General guidance",id:"general-guidance",level:2},{value:"How to submit the exercises",id:"how-to-submit-the-exercises",level:2},{value:"Completing",id:"completing",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...i}=e;return(0,n.kt)(d,(0,r.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("p",null,"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it's important to read the material carefully and complete the exercises in order to develop the necessary skills."),(0,n.kt)("p",null,"To pass the course, you will need to complete all of the exercises. However, one exercise can be skipped per part, except for the exercises marked as mandatory. The mandatory exercises cannot be skipped."),(0,n.kt)("p",null,"The exercises are designed to reinforce the material covered in each part, and are placed at strategic points in the course to ensure that you have learned the necessary skills prior to attempting each exercise. You can complete the exercises at your own pace, and there is no deadline for submission outside of the last date, when the entire course ends."),(0,n.kt)("p",null,"When submitting your exercises, please follow the instructions provided in the course material. Exercises should be submitted in a specific format, which will be outlined in the instructions for each exercise."),(0,n.kt)("p",null,"We hope that you enjoy the course and find it informative and engaging. Good luck!"),(0,n.kt)("h3",{id:"about-different-architectures-and-contributing"},"About different architectures and contributing"),(0,n.kt)("p",null,"Please note that while Docker runs on all major operating systems and even on ARM architecture, this course material may not cover platform-specific details for all operating systems. However, we've had students successfully complete the course using a variety of machines and operating systems."),(0,n.kt)("p",null,"If you encounter any issues while working through the course material on your particular system, we recommend consulting the Docker documentation or seeking help on the course forums. Our community is here to support you and help you succeed in the course!"),(0,n.kt)("p",null,"We welcome contributions to the course material from students and other members of the DevOps community! If you notice any mistakes, typos, or errors in the material, please consider submitting a pull request to the course repository on GitHub."),(0,n.kt)("p",null,"Thank you in advance for your contributions to this open source project!"),(0,n.kt)("h3",{id:"grading"},"Grading"),(0,n.kt)("p",null,"Passing this course requires you to do the exercises for each part. This means generally every exercise, but you are allowed to skip one non-mandatory exercise in each part. Some of the exercises are mandatory and can not be skipped."),(0,n.kt)("p",null,"This course is worth 1-3 credits depending on the completed parts. Completing part 1 gives you 1 credit. Completing parts 1 and 2 is worth 2 credits. Completing all of the parts will grant you 3 credits."),(0,n.kt)("p",null,"There are additional instructions for completion after each part and at the end of this page."),(0,n.kt)("h3",{id:"learning-objectives"},"Learning objectives"),(0,n.kt)("p",null,"Part 1: DevOps with Docker (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/toteutus/otm-4bd45ab8-8b23-4973-a918-a6b6f7bbb347/TKT21036"},"TKT21036"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Understand the fundamental concepts of Docker, including images and containers."),(0,n.kt)("li",{parentName:"ul"},"Learn how to build Docker images for existing projects and run them."),(0,n.kt)("li",{parentName:"ul"},"Understand how Docker can simplify the development process.")),(0,n.kt)("p",null,"Part 2: DevOps with Docker: docker-compose (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/toteutus/otm-c73ef1c6-8fb0-42e8-9052-ef59b01cb409/TKT21037"},"TKT21037"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Learn how to manage complex multi-container applications with Docker Compose."),(0,n.kt)("li",{parentName:"ul"},"Understand the role of Docker Compose in container orchestration"),(0,n.kt)("li",{parentName:"ul"},"Practice deploying and managing real-world applications using Docker Compose.")),(0,n.kt)("p",null,"Part 3: DevOps with Docker: security and optimization (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/opintojakso/hy-CU-142971306-2020-08-01/TKT21038"},"TKT21038"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Learn how to optimize Docker images for production, including reducing image size and improving security."),(0,n.kt)("li",{parentName:"ul"},"Understand the limitations of using Docker Compose in production environments and the need for more advanced orchestration tools."),(0,n.kt)("li",{parentName:"ul"},"Explore alternative container orchestration solutions, including Kubernetes.")),(0,n.kt)("h3",{id:"where-to-find-information-about-the-course"},"Where to find information about the course?"),(0,n.kt)("p",null,"All of the details you need to complete the course should be found on this page. If something is missing or unclear after reading this page, please contact ",(0,n.kt)("a",{parentName:"p",href:"mailto:matti.luukkainen@helsinki.fi"},"matti.luukkainen@helsinki.fi")," or get in touch through Discord."),(0,n.kt)("h3",{id:"discord"},"Discord"),(0,n.kt)("p",null,"This course has a Discord group where we discuss everything about the course. Support is available almost 24/7, with the discussion being in both English and Finnish."),(0,n.kt)("p",null,"Join our discord group ",(0,n.kt)("a",{parentName:"p",href:"https://study.cs.helsinki.fi/discord/join/docker"},"here"),"."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"All")," inappropriate, degrading or discriminating comments on the channel are prohibited and will lead to action taken against the commenter."),(0,n.kt)("h1",{id:"warning-before-installing-docker"},"Warning: Before installing Docker"),(0,n.kt)("p",null,"Containers leverage the power of your own operating system. As such ",(0,n.kt)("strong",{parentName:"p"},"by default")," any containerized application, or user who has external access to your container, would have super user privileges to your computer."),(0,n.kt)("p",null,"I will try my best to alert you of potential risks as we encounter them, but due to the structure of the course we will focus on security in part 3."),(0,n.kt)("p",null,"Please keep this in mind as you move through the installation and exercises. If you ever feel unsure about what you're doing, come to the Discord channel and have a chat with us."),(0,n.kt)("h2",{id:"installing-docker"},"Installing Docker"),(0,n.kt)("p",null,"Use the official documentation to find download instructions for docker-ce for the platform of your choice:"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/install/linux/docker-ce/ubuntu/"},"Ubuntu")),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-for-mac/install/"},"MacOS")),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-for-windows/install/"},"Windows")),(0,n.kt)("p",null,"Confirm that Docker installed correctly by opening a terminal and running ",(0,n.kt)("inlineCode",{parentName:"p"},"docker -v")," to see the installed version."),(0,n.kt)("admonition",{title:"Docker group",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"To avoid writing sudos you may consider ",(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/install/linux/linux-postinstall/"},"adding yourself to docker group")),(0,n.kt)("p",{parentName:"admonition"},"Keep in mind that if you do so, you can now run containers without sudo and containers give you super user access to the computer.")),(0,n.kt)("h2",{id:"deadline"},"Deadline"),(0,n.kt)("p",null,"The sign up for ECTS credits and the course ends 16.6.2024! After that course is locked and submissions can no longer be made or credits earned. As the certificate is received through submissions, you have to submit everything before the course ends. More details under completion and after each part."),(0,n.kt)("h2",{id:"general-guidance"},"General guidance"),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Do not alter the code of the projects, unless by pull-requests to the original projects")),(0,n.kt)("p",null,"You do not need to touch Ruby, Java, Javascript or Python code during this course. You may have to read their error messages."),(0,n.kt)("p",null,"Visit the Discord channel if you are stuck!"),(0,n.kt)("h2",{id:"how-to-submit-the-exercises"},"How to submit the exercises"),(0,n.kt)("p",null,"Make a repository to GitHub and publish your solutions in clearly ordered files / folders. If you need help publishing using Git you should refer to their ",(0,n.kt)("a",{parentName:"p",href:"https://guides.github.com/activities/hello-world/"},"guide"),". Make sure that the repository is available to us, either by using a public repository or a private repository and adding Jakousa and mluukkai as collaborators."),(0,n.kt)("p",null,"Most of the exercises will be focused on a Dockerfile and/or docker-compose.yml. In those cases, submitting the file is enough. In other cases, a picture or copy-paste from your command line or a link to Docker Hub and/or project inside the repository is enough. For the command line exercises at start the command ",(0,n.kt)("a",{parentName:"p",href:"https://linux.die.net/man/1/script"},"script")," may be helpful."),(0,n.kt)("p",null,"Because the course exercises are designed to build upon each other, it's more important that you document the exercises for yourself. We will be looking at the submissions of the later exercises as they are more demanding."),(0,n.kt)("p",null,"When you have completed a part, use the ",(0,n.kt)("a",{parentName:"p",href:"https://studies.cs.helsinki.fi/stats/courses/docker2024"},"submission application")," to mark your exercises. You can ",(0,n.kt)("strong",{parentName:"p"},"not")," edit a submission, so make sure you have completed enough exercises for a part before submitting."),(0,n.kt)("h2",{id:"completing"},"Completing"),(0,n.kt)("p",null,"The certificate is available from the small icon beneath your submissions!"),(0,n.kt)("p",null,'After you have returned all of the required exercises and wish to end your course completion and want the ECTS credits press the following button in the submission application (ignore the message about an "exam" as there is no exam in this course):'),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Incomplete course",src:o(6795).Z,width:"874",height:"188"})),(0,n.kt)("p",null,'After that, double-check that the application has the message "Course marked as completed" and the date. If the date is not visible, we have not been notified.'),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Completed course",src:o(38).Z,width:"482",height:"469"})))}p.isMDXComponent=!0},38:(e,t,o)=>{o.d(t,{Z:()=>r});const r=o.p+"assets/images/completed_course-1c9c27f6aefc0214cb0b511b6358980c.png"},6795:(e,t,o)=>{o.d(t,{Z:()=>r});const r=o.p+"assets/images/incomplete_course-8a93bc802c0307b99b884cb844e664ff.png"}}]); \ No newline at end of file diff --git a/assets/js/d589d3a7.36cb76b0.js b/assets/js/d589d3a7.36cb76b0.js new file mode 100644 index 00000000..e640e018 --- /dev/null +++ b/assets/js/d589d3a7.36cb76b0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[162],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>m});var r=o(7294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function a(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var l=r.createContext({}),c=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):a(a({},t),e)),o},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var o=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(o),h=n,m=d["".concat(l,".").concat(h)]||d[h]||p[h]||i;return o?r.createElement(m,a(a({ref:t},u),{},{components:o})):r.createElement(m,a({ref:t},u))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=o.length,a=new Array(i);a[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:n,a[1]=s;for(var c=2;c{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=o(7462),n=(o(7294),o(3905));const i={sidebar_position:2},a="Getting Started",s={unversionedId:"getting-started",id:"getting-started",title:"Getting Started",description:"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it's important to read the material carefully and complete the exercises in order to develop the necessary skills.",source:"@site/docs/getting-started.md",sourceDirName:".",slug:"/getting-started",permalink:"/getting-started",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/getting-started.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"materialSidebar",previous:{title:"DevOps with Docker",permalink:"/"},next:{title:"Frequently Asked Questions",permalink:"/faq"}},l={},c=[{value:"Updating of the material for 2024 edition",id:"updating-of-the-material-for-2024-edition",level:3},{value:"About different architectures and contributing",id:"about-different-architectures-and-contributing",level:3},{value:"Grading",id:"grading",level:3},{value:"Learning objectives",id:"learning-objectives",level:3},{value:"Where to find information about the course?",id:"where-to-find-information-about-the-course",level:3},{value:"Discord",id:"discord",level:3},{value:"Installing Docker",id:"installing-docker",level:2},{value:"Deadline",id:"deadline",level:2},{value:"General guidance",id:"general-guidance",level:2},{value:"How to submit the exercises",id:"how-to-submit-the-exercises",level:2},{value:"Completing",id:"completing",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...i}=e;return(0,n.kt)(d,(0,r.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("p",null,"Welcome to the DevOps with Docker course! This course is designed to be completed sequentially, from start to finish. Each part builds on the previous one, so it's important to read the material carefully and complete the exercises in order to develop the necessary skills."),(0,n.kt)("p",null,"To pass the course, you will need to complete all of the exercises. However, one exercise can be skipped per part, except for the exercises marked as mandatory. The mandatory exercises cannot be skipped."),(0,n.kt)("p",null,"The exercises are designed to reinforce the material covered in each part, and are placed at strategic points in the course to ensure that you have learned the necessary skills prior to attempting each exercise. You can complete the exercises at your own pace, and there is no deadline for submission outside of the last date, when the entire course ends."),(0,n.kt)("p",null,"When submitting your exercises, please follow the instructions provided in the course material. Exercises should be submitted in a specific format, which will be outlined in the instructions for each exercise."),(0,n.kt)("p",null,"We hope that you enjoy the course and find it informative and engaging. Good luck!"),(0,n.kt)("h3",{id:"updating-of-the-material-for-2024-edition"},"Updating of the material for 2024 edition"),(0,n.kt)("p",null,"The 2024 edition of the course starts officially on 11th March. The material is currently being updated. At the time of writing (7th March) the following parts are already updated"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Part 1, up to section ",(0,n.kt)("em",{parentName:"li"},"In-depth dive into images"))),(0,n.kt)("p",null,"You may continue already beyond the updated material but beware, there might be some outdated content!"),(0,n.kt)("h3",{id:"about-different-architectures-and-contributing"},"About different architectures and contributing"),(0,n.kt)("p",null,"Please note that while Docker runs on all major operating systems and even on ARM architecture, this course material may not cover platform-specific details for all operating systems. However, we've had students successfully complete the course using a variety of machines and operating systems."),(0,n.kt)("p",null,"If you encounter any issues while working through the course material on your particular system, we recommend consulting the Docker documentation or seeking help on the course forums. Our community is here to support you and help you succeed in the course!"),(0,n.kt)("p",null,"We welcome contributions to the course material from students and other members of the DevOps community! If you notice any mistakes, typos, or errors in the material, please consider submitting a pull request to the course repository on GitHub."),(0,n.kt)("p",null,"Thank you in advance for your contributions to this open source project!"),(0,n.kt)("h3",{id:"grading"},"Grading"),(0,n.kt)("p",null,"Passing this course requires you to do the exercises for each part. This means generally every exercise, but you are allowed to skip one non-mandatory exercise in each part. Some of the exercises are mandatory and can not be skipped."),(0,n.kt)("p",null,"This course is worth 1-3 credits depending on the completed parts. Completing part 1 gives you 1 credit. Completing parts 1 and 2 is worth 2 credits. Completing all of the parts will grant you 3 credits."),(0,n.kt)("p",null,"There are additional instructions for completion after each part and at the end of this page."),(0,n.kt)("h3",{id:"learning-objectives"},"Learning objectives"),(0,n.kt)("p",null,"Part 1: DevOps with Docker (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/toteutus/otm-4bd45ab8-8b23-4973-a918-a6b6f7bbb347/TKT21036"},"TKT21036"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Understand the fundamental concepts of Docker, including images and containers."),(0,n.kt)("li",{parentName:"ul"},"Learn how to build Docker images for existing projects and run them."),(0,n.kt)("li",{parentName:"ul"},"Understand how Docker can simplify the development process.")),(0,n.kt)("p",null,"Part 2: DevOps with Docker: docker-compose (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/toteutus/otm-c73ef1c6-8fb0-42e8-9052-ef59b01cb409/TKT21037"},"TKT21037"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Learn how to manage complex multi-container applications with Docker Compose."),(0,n.kt)("li",{parentName:"ul"},"Understand the role of Docker Compose in container orchestration"),(0,n.kt)("li",{parentName:"ul"},"Practice deploying and managing real-world applications using Docker Compose.")),(0,n.kt)("p",null,"Part 3: DevOps with Docker: security and optimization (",(0,n.kt)("a",{parentName:"p",href:"https://studies.helsinki.fi/kurssit/opintojakso/hy-CU-142971306-2020-08-01/TKT21038"},"TKT21038"),")"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Learn how to optimize Docker images for production, including reducing image size and improving security."),(0,n.kt)("li",{parentName:"ul"},"Understand the limitations of using Docker Compose in production environments and the need for more advanced orchestration tools."),(0,n.kt)("li",{parentName:"ul"},"Explore alternative container orchestration solutions, including Kubernetes.")),(0,n.kt)("h3",{id:"where-to-find-information-about-the-course"},"Where to find information about the course?"),(0,n.kt)("p",null,"All of the details you need to complete the course should be found on this page. If something is missing or unclear after reading this page, please contact ",(0,n.kt)("a",{parentName:"p",href:"mailto:matti.luukkainen@helsinki.fi"},"matti.luukkainen@helsinki.fi")," or get in touch through Discord."),(0,n.kt)("h3",{id:"discord"},"Discord"),(0,n.kt)("p",null,"This course has a Discord group where we discuss everything about the course. Support is available almost 24/7, with the discussion being in both English and Finnish."),(0,n.kt)("p",null,"Join our discord group ",(0,n.kt)("a",{parentName:"p",href:"https://study.cs.helsinki.fi/discord/join/docker"},"here"),"."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"All")," inappropriate, degrading or discriminating comments on the channel are prohibited and will lead to action taken against the commenter."),(0,n.kt)("h1",{id:"warning-before-installing-docker"},"Warning: Before installing Docker"),(0,n.kt)("p",null,"Containers leverage the power of your own operating system. As such ",(0,n.kt)("strong",{parentName:"p"},"by default")," any containerized application, or user who has external access to your container, would have super user privileges to your computer."),(0,n.kt)("p",null,"I will try my best to alert you of potential risks as we encounter them, but due to the structure of the course we will focus on security in part 3."),(0,n.kt)("p",null,"Please keep this in mind as you move through the installation and exercises. If you ever feel unsure about what you're doing, come to the Discord channel and have a chat with us."),(0,n.kt)("h2",{id:"installing-docker"},"Installing Docker"),(0,n.kt)("p",null,"Use the official documentation to find download instructions for docker-ce for the platform of your choice:"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/install/linux/docker-ce/ubuntu/"},"Ubuntu")),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-for-mac/install/"},"MacOS")),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-for-windows/install/"},"Windows")),(0,n.kt)("p",null,"Confirm that Docker installed correctly by opening a terminal and running ",(0,n.kt)("inlineCode",{parentName:"p"},"docker -v")," to see the installed version."),(0,n.kt)("admonition",{title:"Docker group",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"To avoid writing sudos you may consider ",(0,n.kt)("a",{parentName:"p",href:"https://docs.docker.com/install/linux/linux-postinstall/"},"adding yourself to docker group")),(0,n.kt)("p",{parentName:"admonition"},"Keep in mind that if you do so, you can now run containers without sudo and containers give you super user access to the computer.")),(0,n.kt)("h2",{id:"deadline"},"Deadline"),(0,n.kt)("p",null,"The sign up for ECTS credits and the course ends 16.6.2024! After that course is locked and submissions can no longer be made or credits earned. As the certificate is received through submissions, you have to submit everything before the course ends. More details under completion and after each part."),(0,n.kt)("h2",{id:"general-guidance"},"General guidance"),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"Do not alter the code of the projects, unless by pull-requests to the original projects")),(0,n.kt)("p",null,"You do not need to touch Ruby, Java, Javascript or Python code during this course. You may have to read their error messages."),(0,n.kt)("p",null,"Visit the Discord channel if you are stuck!"),(0,n.kt)("h2",{id:"how-to-submit-the-exercises"},"How to submit the exercises"),(0,n.kt)("p",null,"Make a repository to GitHub and publish your solutions in clearly ordered files / folders. If you need help publishing using Git you should refer to their ",(0,n.kt)("a",{parentName:"p",href:"https://guides.github.com/activities/hello-world/"},"guide"),". Make sure that the repository is available to us, either by using a public repository or a private repository and adding Jakousa and mluukkai as collaborators."),(0,n.kt)("p",null,"Most of the exercises will be focused on a Dockerfile and/or docker-compose.yml. In those cases, submitting the file is enough. In other cases, a picture or copy-paste from your command line or a link to Docker Hub and/or project inside the repository is enough. For the command line exercises at start the command ",(0,n.kt)("a",{parentName:"p",href:"https://linux.die.net/man/1/script"},"script")," may be helpful."),(0,n.kt)("p",null,"Because the course exercises are designed to build upon each other, it's more important that you document the exercises for yourself. We will be looking at the submissions of the later exercises as they are more demanding."),(0,n.kt)("p",null,"When you have completed a part, use the ",(0,n.kt)("a",{parentName:"p",href:"https://studies.cs.helsinki.fi/stats/courses/docker2024"},"submission application")," to mark your exercises. You can ",(0,n.kt)("strong",{parentName:"p"},"not")," edit a submission, so make sure you have completed enough exercises for a part before submitting."),(0,n.kt)("h2",{id:"completing"},"Completing"),(0,n.kt)("p",null,"The certificate is available from the small icon beneath your submissions!"),(0,n.kt)("p",null,'After you have returned all of the required exercises and wish to end your course completion and want the ECTS credits press the following button in the submission application (ignore the message about an "exam" as there is no exam in this course):'),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Incomplete course",src:o(6795).Z,width:"874",height:"188"})),(0,n.kt)("p",null,'After that, double-check that the application has the message "Course marked as completed" and the date. If the date is not visible, we have not been notified.'),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Completed course",src:o(38).Z,width:"482",height:"469"})))}p.isMDXComponent=!0},38:(e,t,o)=>{o.d(t,{Z:()=>r});const r=o.p+"assets/images/completed_course-1c9c27f6aefc0214cb0b511b6358980c.png"},6795:(e,t,o)=>{o.d(t,{Z:()=>r});const r=o.p+"assets/images/incomplete_course-8a93bc802c0307b99b884cb844e664ff.png"}}]); \ No newline at end of file diff --git a/assets/js/f1c60e00.4f2ae498.js b/assets/js/f1c60e00.4f2ae498.js deleted file mode 100644 index daa36f0a..00000000 --- a/assets/js/f1c60e00.4f2ae498.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[33],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),u=i,m=p["".concat(s,".").concat(u)]||p[u]||h[u]||o;return n?a.createElement(m,r(r({ref:t},d),{},{components:n})):a.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:i,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const o={title:"In-depth dive to images"},r=void 0,l={unversionedId:"part-1/section-3",id:"part-1/section-3",title:"In-depth dive to images",description:'Images are the basic building blocks for containers and other images. When you "containerize" an application you work towards creating the image.',source:"@site/docs/part-1/section-3.md",sourceDirName:"part-1",slug:"/part-1/section-3",permalink:"/part-1/section-3",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-3.md",tags:[],version:"current",frontMatter:{title:"In-depth dive to images"},sidebar:"materialSidebar",previous:{title:"Running and stopping containers",permalink:"/part-1/section-2"},next:{title:"Defining start conditions for the container",permalink:"/part-1/section-4"}},s={},c=[{value:"Where do the images come from?",id:"where-do-the-images-come-from",level:2},{value:"A detailed look into an image",id:"a-detailed-look-into-an-image",level:2},{value:"Exercises 1.5 - 1.6",id:"exercises-15---16",level:2},{value:"Building images",id:"building-images",level:2},{value:"Exercises 1.7 - 1.8",id:"exercises-17---18",level:2}],d={toc:c},p="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,'Images are the basic building blocks for containers and other images. When you "containerize" an application you work towards creating the image.'),(0,i.kt)("p",null,"By learning what images are and how to create them you are ready to start utilizing containers in your own projects."),(0,i.kt)("h2",{id:"where-do-the-images-come-from"},"Where do the images come from?"),(0,i.kt)("p",null,"When running a command such as ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run hello-world"),", Docker will automatically search ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/"},"Docker Hub")," for the image if it is not found locally."),(0,i.kt)("p",null,"This means that we can pull and run any public image from Docker's servers. For example\u201a if we wanted to start an instance of the PostgreSQL database, we could just run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run postgres"),", which would pull and run ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/postgres/"},"https://hub.docker.com/","_","/postgres/"),"."),(0,i.kt)("p",null,"We can search for images in the Docker Hub with ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search"),". Try running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search hello-world"),"."),(0,i.kt)("p",null,'The search finds plenty of results, and prints each image\'s name, short description, amount of stars, and "official" and "automated" statuses.'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker search hello-world\n\n NAME DESCRIPTION STARS OFFICIAL AUTOMATED\n hello-world Hello World!\u2026 1988 [OK]\n kitematic/hello-world-nginx A light-weig\u2026 153\n tutum/hello-world Image to tes\u2026 90 [OK]\n ...\n")),(0,i.kt)("p",null,"Let's examine the list."),(0,i.kt)("p",null,"The first result, ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-world"),", is an official image. ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-hub/official_images/"},"Official images")," are curated and reviewed by Docker, Inc. and are usually actively maintained by the authors. They are built from repositories in the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/docker-library"},"docker-library"),"."),(0,i.kt)("p",null,"When browsing the CLI's search results, you can recognize an official image from the \"","[OK]",'" in the "OFFICIAL" column and also from the fact that the image\'s name has no prefix (aka organization/user). When browsing Docker Hub, the page will show "Docker Official Images" as the repository, instead of a user or organization. For example, see the ',(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/hello-world/"},"Docker Hub page")," of the ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-world")," image."),(0,i.kt)("p",null,"The third result, ",(0,i.kt)("inlineCode",{parentName:"p"},"tutum/hello-world"),', is marked as "automated". This means that the image is ',(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-hub/builds/"},"automatically built")," from the source repository. Its ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/tutum/hello-world/"},"Docker Hub page"),' shows its previous "Builds" and a link to the image\'s "Source Repository" (in this case, to GitHub) from which Docker Hub builds the image.'),(0,i.kt)("p",null,"The second result, ",(0,i.kt)("inlineCode",{parentName:"p"},"kitematic/hello-world-nginx"),", is neither an official nor an automated image. We can't know what the image is built from, since its ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/kitematic/hello-world-nginx/"},"Docker Hub page"),' has no links to any repositories. The only thing its Docker Hub page reveals is that the image is 9 years old. Even if the image\'s "Overview" section had links to a repository, we would have no guarantees that the published image was built from that source.'),(0,i.kt)("p",null,"There are also other Docker registries competing with Docker Hub, such as ",(0,i.kt)("a",{parentName:"p",href:"https://quay.io/"},"Quay"),". By default, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search")," will only search from Docker Hub, but to a search different registry, you can add the registry address before the search term, for example, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search quay.io/hello"),". Alternatively, you can use the registry's web pages to search for images. Take a look at the page of ",(0,i.kt)("a",{parentName:"p",href:"https://quay.io/repository/nordstrom/hello-world"},"the ",(0,i.kt)("inlineCode",{parentName:"a"},"nordstrom/hello-world")," image on Quay"),". The page shows the command to use to pull the image, which reveals that we can also pull images from hosts other than Docker Hub:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"docker pull quay.io/nordstrom/hello-world")),(0,i.kt)("p",null,"So, if the host's name (here: ",(0,i.kt)("inlineCode",{parentName:"p"},"quay.io"),") is omitted, it will pull from Docker Hub by default."),(0,i.kt)("p",null,"NOTE: Trying the above command may fail giving manifest errors as the default tag latest is not present in quay.io/nordstrom/hello-world image. Specifying a correct tag for a image will pull the image without any errors, for ex.\n",(0,i.kt)("inlineCode",{parentName:"p"},"docker pull quay.io/nordstrom/hello-world:2.0")),(0,i.kt)("h2",{id:"a-detailed-look-into-an-image"},"A detailed look into an image"),(0,i.kt)("p",null,"Let's go back to a more relevant image than 'hello-world', the Ubuntu image, one of the most common Docker images to use as a base for your own image."),(0,i.kt)("p",null,"Let's pull Ubuntu and look at the first lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker pull ubuntu\n Using default tag: latest\n latest: Pulling from library/ubuntu\n")),(0,i.kt)("p",null,"Since we didn't specify a tag, Docker defaulted to ",(0,i.kt)("inlineCode",{parentName:"p"},"latest"),", which is usually the latest image built and pushed to the registry. ",(0,i.kt)("strong",{parentName:"p"},"However"),", in this case, the repository's ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/ubuntu"},"README")," says that the ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:latest"),' tag points to the "latest LTS" instead since that\'s the version recommended for general use.'),(0,i.kt)("p",null,"Images can be tagged to save different versions of the same image. You define an image's tag by adding ",(0,i.kt)("inlineCode",{parentName:"p"},":")," after the image's name."),(0,i.kt)("p",null,"Ubuntu's ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/library/ubuntu/tags/"},"Docker Hub page")," reveals that there's a tag named 22.04 which promises us that the image is based on Ubuntu 22.04. Let's pull that as well:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker pull ubuntu:22.04\n\n 18.04: Pulling from library/ubuntu\n c2ca09a1934b: Downloading [============================================> ] 34.25MB/38.64MB\n d6c3619d2153: Download complete\n 0efe07335a04: Download complete\n 6b1bb01b3a3b: Download complete\n 43a98c187399: Download complete\n")),(0,i.kt)("p",null,"Images are composed of different layers that are downloaded in parallel to speed up the download. Images being made of layers also have other aspects and we will talk about them in part 3."),(0,i.kt)("p",null,"We can also tag images locally for convenience, for example, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker tag ubuntu:22.04 ubuntu:jammy_jellyfish")," creates the tag ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:jammy_jellyfish")," which refers to ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:22.04"),"."),(0,i.kt)("p",null,'Tagging is also a way to "rename" images. Run ',(0,i.kt)("inlineCode",{parentName:"p"},"docker tag ubuntu:22.04 fav_distro:jammy_jellyfish")," and check ",(0,i.kt)("inlineCode",{parentName:"p"},"docker image ls")," to see what effects the command had."),(0,i.kt)("p",null,"To summarize, an image name may consist of 3 parts plus a tag. Usually like the following: ",(0,i.kt)("inlineCode",{parentName:"p"},"registry/organisation/image:tag"),". But may be as short as ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu"),", then the registry will default to Docker hub, organisation to ",(0,i.kt)("em",{parentName:"p"},"library")," and tag to ",(0,i.kt)("em",{parentName:"p"},"latest"),". The organisation may also be a user, but calling it an organisation may be more clear."),(0,i.kt)("h2",{id:"exercises-15---16"},"Exercises 1.5 - 1.6"),(0,i.kt)("admonition",{title:"Exercise 1.5: Sizes of images",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"In the ",(0,i.kt)("a",{parentName:"p",href:"/part-1/section-2#exercise-13"},"Exercise 1.3")," we used ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu"),"."),(0,i.kt)("p",{parentName:"admonition"},"Here is the same application but instead of Ubuntu is using ",(0,i.kt)("a",{parentName:"p",href:"https://www.alpinelinux.org/"},"Alpine Linux"),": ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:alpine"),"."),(0,i.kt)("p",{parentName:"admonition"},"Pull both images and compare the image sizes.\nGo inside the Alpine container and make sure the secret message functionality is the same. Alpine version doesn't have ",(0,i.kt)("inlineCode",{parentName:"p"},"bash")," but it has ",(0,i.kt)("inlineCode",{parentName:"p"},"sh"),", a more bare-bones shell.")),(0,i.kt)("admonition",{title:"Exercise 1.6: Hello Docker Hub",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run -it devopsdockeruh/pull_exercise"),"."),(0,i.kt)("p",{parentName:"admonition"},"The command will wait for your input."),(0,i.kt)("p",{parentName:"admonition"},"Navigate through the ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/"},"Docker hub")," to find the docs and Dockerfile that was used to create the image."),(0,i.kt)("p",{parentName:"admonition"},'Read the Dockerfile and/or docs to learn what input will get the application to answer a "secret message".'),(0,i.kt)("p",{parentName:"admonition"},"Submit the secret message and command(s) given to get it as your answer.")),(0,i.kt)("h2",{id:"building-images"},"Building images"),(0,i.kt)("p",null,"Finally, we get to build our own images and get to talk about ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/"},(0,i.kt)("inlineCode",{parentName:"a"},"Dockerfile"))," and why it's so great."),(0,i.kt)("p",null,"Dockerfile is simply a file that contains the build instructions for an image. You define what should be included in the image with different instructions. We'll learn about the best practices here by creating one."),(0,i.kt)("p",null,'Let\'s take a most simple application and containerize it first. Here is a script called "hello.sh"'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"hello.sh")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-sh"},'#!/bin/sh\n\necho "Hello, docker!"\n')),(0,i.kt)("p",null,"First, we will test that it even works. Create the file, add execution permissions and run it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ chmod +x hello.sh\n\n$ ./hello.sh\n Hello, docker!\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If you're using Windows you can skip these two and add chmod +x hello.sh to the Dockerfile.")),(0,i.kt)("p",null,"And now to create an image from it. We'll have to create the ",(0,i.kt)("inlineCode",{parentName:"p"},"Dockerfile")," that declares all of the required dependencies. At least it depends on something that can run shell scripts. We will choose ",(0,i.kt)("a",{parentName:"p",href:"https://www.alpinelinux.org/"},"Alpine"),", a small Linux distribution that is often used to create small images."),(0,i.kt)("p",null,"Even though we're using Alpine here, you can use Ubuntu during exercises. Ubuntu images by default contain more tools to debug what is wrong when something doesn't work. In part 3 we will talk more about why small images are important."),(0,i.kt)("p",null,"We will choose exactly which version of a given image we want to use. This guarantees that we don't accidentally update through a breaking change, and we know which images need updating when there are known security vulnerabilities in old images."),(0,i.kt)("p",null,'Now create a file and name it "Dockerfile" and put the following instructions inside it:'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dockerfile")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-Dockerfile"},"# Start from the alpine image that is smaller but no fancy tools\nFROM alpine:3.19\n\n# Use /usr/src/app as our workdir. The following instructions will be executed in this location.\nWORKDIR /usr/src/app\n\n# Copy the hello.sh file from this directory to /usr/src/app/ creating /usr/src/app/hello.sh\nCOPY hello.sh .\n\n# Alternatively, if we skipped chmod earlier, we can add execution permissions during the build.\n# RUN chmod +x hello.sh\n\n# When running docker run the command will be ./hello.sh\nCMD ./hello.sh\n")),(0,i.kt)("p",null,"Great! We can use the command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/build/"},"docker build")," to turn the Dockerfile to an image."),(0,i.kt)("p",null,"By default ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build")," will look for a file named Dockerfile. Now we can run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build")," with instructions where to build (",(0,i.kt)("inlineCode",{parentName:"p"},"."),") and give it a name (",(0,i.kt)("inlineCode",{parentName:"p"},"-t "),"):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build . -t hello-docker\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 478B 0.0s\n => [internal] load metadata for docker.io/library/alpine:3.19 2.1s\n => [auth] library/alpine:pull token for registry-1.docker.io 0.0s\n => [internal] load .dockerignore 0.0s\n => => transferring context: 2B 0.0s\n => [1/3] FROM docker.io/library/alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b 0.0s\n => [internal] load build context 0.0s\n => => transferring context: 68B 0.0s\n => [2/3] WORKDIR /usr/src/app 0.0s\n => [3/3] COPY hello.sh . 0.0s\n => exporting to image 0.0s\n => => exporting layers 0.0s\n => => writing image sha256:5f8f5d7445f34b0bcfaaa4d685a068cdccc1ed79e65068337a3a228c79ea69c8 0.0s\n => => naming to docker.io/library/hello-docker\n")),(0,i.kt)("p",null,"Let us ensure that the image exists:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker image ls\n REPOSITORY TAG IMAGE ID CREATED SIZE\n hello-docker latest 5f8f5d7445f3 4 minutes ago 7.73MB\n")),(0,i.kt)("admonition",{title:"Permission denied",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you're now getting \"/bin/sh: ./hello.sh: Permission denied\" it's because the ",(0,i.kt)("inlineCode",{parentName:"p"},"chmod +x hello.sh")," was skipped earlier. You can simply uncomment the RUN instruction between COPY and CMD instructions")),(0,i.kt)("admonition",{title:"not found",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you're now getting \"/bin/sh: ./hello.sh: not found\" and you're using Windows it might be because by default Windows uses ",(0,i.kt)("a",{parentName:"p",href:"https://www.cs.toronto.edu/~krueger/csc209h/tut/line-endings.html"},"CRLF")," as line ending. Unix, in our case Alpine, uses just LF which makes the copying of our ",(0,i.kt)("inlineCode",{parentName:"p"},"hello.sh")," invalid bash script in the build phase. To overcome this error change the line endings to LF before running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build"))),(0,i.kt)("p",null,"Now executing the application is as simple as running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run hello-docker"),". Try it!"),(0,i.kt)("p",null,"During the build we see from the output that there are three steps: ","[1/3]",", ","[2/3]"," and ","[3/3]",". The steps here represent ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/build/guide/layers/"},"layers")," of the image so that each step is a new layer on top of the base image (alpine:3.19 in our case)."),(0,i.kt)("p",null,"Layers have multiple functions. We often try to limit the number of layers to save on storage space but layers can work as a cache during build time. If we just edit the last lines of Dockerfile the build command can start from the previous layer and skip straight to the section that has changed. COPY automatically detects changes in the files, so if we change the hello.sh it'll run from step 3/3, skipping 1 and 2. This can be used to create faster build pipelines. We'll talk more about optimization in part 3."),(0,i.kt)("p",null,"It is also possible to manually create new layers on top of a image. Let us now create a new file called ",(0,i.kt)("inlineCode",{parentName:"p"},"additional.txt")," and copy it inside a container."),(0,i.kt)("p",null,"We'll need two terminals, that shall be called 1 and 2 in the following listings. Let us start by running the image: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 1\n$ docker run -it hello-docker sh\n/usr/src/app #\n")),(0,i.kt)("p",null,"Now we're inside of the container. We replaced the CMD we defined earlier with ",(0,i.kt)("inlineCode",{parentName:"p"},"sh")," and used -i and -t to start the container so that we can interact with it."),(0,i.kt)("p",null,"In the second terminal we will copy the file inside the contained:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},'# do this in terminal 2\n$ docker ps\n CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n 9c06b95e3e85 hello-docker "sh" 4 minutes ago Up 4 minutes zen_rosalind\n\n$ touch additional.txt\n$ docker cp ./additional.txt zen_rosalind:/usr/src/app/\n')),(0,i.kt)("p",null,"The file is created with command ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," right before copying it in."),(0,i.kt)("p",null,"Let us ensure that the file is copied inside the container:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 1\n/usr/src/app # ls\nadditional.txt hello.sh\n")),(0,i.kt)("p",null,"Great! Now we've made a change to the container. We can use command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/reference/cli/docker/container/diff/"},"docker diff")," to check what has changed"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 2\n$ docker diff zen_rosalind\n C /usr\n C /usr/src\n C /usr/src/app\n A /usr/src/app/additional.txt\n C /root\n A /root/.ash_history\n")),(0,i.kt)("p",null,"The character in front of the file name indicates the type of the change in the container's filesystem: A = added, D = deleted, C = changed. The additional.txt was created and our ",(0,i.kt)("inlineCode",{parentName:"p"},"ls")," created .ash_history."),(0,i.kt)("p",null,"Next we will save the changes as ",(0,i.kt)("em",{parentName:"p"},"a new image")," with the command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/container_commit/"},"docker commit"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 2\n$ docker commit zen_rosalind hello-docker-additional\n sha256:2f63baa355ce5976bf89fe6000b92717f25dd91172aed716208e784315bfc4fd\n$ docker image ls\n REPOSITORY TAG IMAGE ID CREATED SIZE\n hello-docker-additional latest 2f63baa355ce 3 seconds ago 7.73MB\n hello-docker latest 444f21cf7bd5 31 minutes ago 7.73MB\n")),(0,i.kt)("p",null,"Technically the command ",(0,i.kt)("inlineCode",{parentName:"p"},"docker commit")," added a new layer on top of the image ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-docker"),", and the resulting image was given the name ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-docker-additional"),"."),(0,i.kt)("p",null,"We will actually not use the command ",(0,i.kt)("inlineCode",{parentName:"p"},"docker commit")," again during this course. This is because defining the changes to the Dockerfile is much more sustainable method of managing changes. No magic actions or scripts, just a Dockerfile that can be version controlled."),(0,i.kt)("p",null,"Let's do just that and create hello-docker with v2 tag that includes the file additional.txt. The new file can be added with a ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#run"},"RUN")," instruction:"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dockerfile")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-Dockerfile"},"# Start from the alpine image\nFROM alpine:3.19\n\n# Use /usr/src/app as our workdir. The following instructions will be executed in this location.\nWORKDIR /usr/src/app\n\n# Copy the hello.sh file from this location to /usr/src/app/ creating /usr/src/app/hello.sh.\nCOPY hello.sh .\n\n# Execute a command with `/bin/sh -c` prefix.\nRUN touch additional.txt\n\n# When running Docker run the command will be ./hello.sh\nCMD ./hello.sh\n")),(0,i.kt)("p",null,"Now we used the RUN instruction to execute the command ",(0,i.kt)("inlineCode",{parentName:"p"},"touch additional.txt")," which creates a file inside the resulting image. Pretty much anything that can be executed in the container based on the created image, can be instructed to be run with the RUN instruction during the build of a Dockerfile."),(0,i.kt)("p",null,"Build now the Dockerfile with ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build . -t hello-docker:v2")," and we are done! Let's compare the output of ls:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"$ docker run hello-docker-additional ls\n additional.txt\n hello.sh\n\n$ docker run hello-docker:v2 ls\n additional.txt\n hello.sh\n")),(0,i.kt)("p",null,"Now we know that all instructions in a Dockerfile ",(0,i.kt)("strong",{parentName:"p"},"except")," CMD (and one other that we will learn about soon) are executed during build time. ",(0,i.kt)("strong",{parentName:"p"},"CMD")," is executed when we call docker run, unless we overwrite it."),(0,i.kt)("h2",{id:"exercises-17---18"},"Exercises 1.7 - 1.8"),(0,i.kt)("admonition",{title:"Exercise 1.7: Image for script",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We can improve our previous solutions now that we know how to create and build a Dockerfile."),(0,i.kt)("p",{parentName:"admonition"},"Let us now get back to ",(0,i.kt)("a",{parentName:"p",href:"/part-1/section-2#exercise-14"},"Exercise 1.4"),"."),(0,i.kt)("p",{parentName:"admonition"},"Create a new file on your local machine and append the script we used previously into that file:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'while true\ndo\n echo "Input website:"\n read website; echo "Searching.."\n sleep 1; curl http://$website\ndone\n')),(0,i.kt)("p",{parentName:"admonition"},"Create a Dockerfile for a new image that starts from ubuntu:20.04 and add instructions to install curl into that image. Then add instructions to copy the script file into that image and finally set it to run on container start using CMD."),(0,i.kt)("p",{parentName:"admonition"},'After you have filled the Dockerfile, build the image with the name "curler".'),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"If you are getting permission denied, use ",(0,i.kt)("inlineCode",{parentName:"li"},"chmod")," to give permission to run the script.")),(0,i.kt)("p",{parentName:"admonition"},"The following should now work:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker run -it curler\n\n Input website:\n helsinki.fi\n Searching..\n \n \n 301 Moved Permanently\n \n

Moved Permanently

\n

The document has moved here.

\n \n')),(0,i.kt)("p",{parentName:"admonition"},"Remember that ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#run"},"RUN")," can be used to execute commands while building the image!"),(0,i.kt)("p",{parentName:"admonition"},"Submit the Dockerfile.")),(0,i.kt)("admonition",{title:"Exercise 1.8: Two line Dockerfile",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"By default our ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:alpine")," doesn't have a CMD. It instead uses ",(0,i.kt)("em",{parentName:"p"},"ENTRYPOINT")," to declare which application is run."),(0,i.kt)("p",{parentName:"admonition"},"We'll talk more about ",(0,i.kt)("em",{parentName:"p"},"ENTRYPOINT")," in the next section, but you already know that the last argument in ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run")," can be used to give a command or an argument."),(0,i.kt)("p",{parentName:"admonition"},"As you might've noticed it doesn't start the web service even though the name is \"simple-web-service\". A suitable argument is needed to start the server!"),(0,i.kt)("p",{parentName:"admonition"},"Try ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run devopsdockeruh/simple-web-service:alpine hello"),'. The application reads the argument "hello" but will inform that hello isn\'t accepted.'),(0,i.kt)("p",{parentName:"admonition"},"In this exercise create a Dockerfile and use FROM and CMD to create a brand new image that automatically runs ",(0,i.kt)("inlineCode",{parentName:"p"},"server"),"."),(0,i.kt)("p",{parentName:"admonition"},"The Docker documentation ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#cmd"},"CMD")," says a bit indirectly that if a image has ENTRYPOINT defined, CMD is used to define it the default arguments."),(0,i.kt)("p",{parentName:"admonition"},'Tag the new image as "web-server"'),(0,i.kt)("p",{parentName:"admonition"},"Return the Dockerfile and the command you used to run the container."),(0,i.kt)("p",{parentName:"admonition"},'Running the built "web-server" image should look like this:'),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-console"},'$ docker run web-server\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.\n- using env: export GIN_MODE=release\n- using code: gin.SetMode(gin.ReleaseMode)\n\n[GIN-debug] GET /*path --\x3e server.Start.func1 (3 handlers)\n[GIN-debug] Listening and serving HTTP on :8080\n')),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"We don't have any method of accessing the web service yet. As such confirming that the console output is the same will suffice.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"The exercise title may be a useful hint here.")))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f1c60e00.f09609db.js b/assets/js/f1c60e00.f09609db.js new file mode 100644 index 00000000..8e21e392 --- /dev/null +++ b/assets/js/f1c60e00.f09609db.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[33],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),u=i,m=p["".concat(s,".").concat(u)]||p[u]||h[u]||o;return n?a.createElement(m,r(r({ref:t},d),{},{components:n})):a.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:i,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var a=n(7462),i=(n(7294),n(3905));const o={title:"In-depth dive into images"},r=void 0,l={unversionedId:"part-1/section-3",id:"part-1/section-3",title:"In-depth dive into images",description:'Images are the basic building blocks for containers and other images. When you "containerize" an application you work towards creating the image.',source:"@site/docs/part-1/section-3.md",sourceDirName:"part-1",slug:"/part-1/section-3",permalink:"/part-1/section-3",draft:!1,editUrl:"https://github.com/docker-hy/docker-hy.github.io/blob/master/docs/part-1/section-3.md",tags:[],version:"current",frontMatter:{title:"In-depth dive into images"},sidebar:"materialSidebar",previous:{title:"Running and stopping containers",permalink:"/part-1/section-2"},next:{title:"Defining start conditions for the container",permalink:"/part-1/section-4"}},s={},c=[{value:"Where do the images come from?",id:"where-do-the-images-come-from",level:2},{value:"A detailed look into an image",id:"a-detailed-look-into-an-image",level:2},{value:"Exercises 1.5 - 1.6",id:"exercises-15---16",level:2},{value:"Building images",id:"building-images",level:2},{value:"Exercises 1.7 - 1.8",id:"exercises-17---18",level:2}],d={toc:c},p="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,'Images are the basic building blocks for containers and other images. When you "containerize" an application you work towards creating the image.'),(0,i.kt)("p",null,"By learning what images are and how to create them you are ready to start utilizing containers in your own projects."),(0,i.kt)("h2",{id:"where-do-the-images-come-from"},"Where do the images come from?"),(0,i.kt)("p",null,"When running a command such as ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run hello-world"),", Docker will automatically search ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/"},"Docker Hub")," for the image if it is not found locally."),(0,i.kt)("p",null,"This means that we can pull and run any public image from Docker's servers. For example\u201a if we wanted to start an instance of the PostgreSQL database, we could just run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run postgres"),", which would pull and run ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/postgres/"},"https://hub.docker.com/","_","/postgres/"),"."),(0,i.kt)("p",null,"We can search for images in the Docker Hub with ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search"),". Try running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search hello-world"),"."),(0,i.kt)("p",null,'The search finds plenty of results, and prints each image\'s name, short description, amount of stars, and "official" and "automated" statuses.'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker search hello-world\n\n NAME DESCRIPTION STARS OFFICIAL AUTOMATED\n hello-world Hello World!\u2026 1988 [OK]\n kitematic/hello-world-nginx A light-weig\u2026 153\n tutum/hello-world Image to tes\u2026 90 [OK]\n ...\n")),(0,i.kt)("p",null,"Let's examine the list."),(0,i.kt)("p",null,"The first result, ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-world"),", is an official image. ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-hub/official_images/"},"Official images")," are curated and reviewed by Docker, Inc. and are usually actively maintained by the authors. They are built from repositories in the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/docker-library"},"docker-library"),"."),(0,i.kt)("p",null,"When browsing the CLI's search results, you can recognize an official image from the \"","[OK]",'" in the "OFFICIAL" column and also from the fact that the image\'s name has no prefix (aka organization/user). When browsing Docker Hub, the page will show "Docker Official Images" as the repository, instead of a user or organization. For example, see the ',(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/hello-world/"},"Docker Hub page")," of the ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-world")," image."),(0,i.kt)("p",null,"The third result, ",(0,i.kt)("inlineCode",{parentName:"p"},"tutum/hello-world"),', is marked as "automated". This means that the image is ',(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/docker-hub/builds/"},"automatically built")," from the source repository. Its ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/tutum/hello-world/"},"Docker Hub page"),' shows its previous "Builds" and a link to the image\'s "Source Repository" (in this case, to GitHub) from which Docker Hub builds the image.'),(0,i.kt)("p",null,"The second result, ",(0,i.kt)("inlineCode",{parentName:"p"},"kitematic/hello-world-nginx"),", is neither an official nor an automated image. We can't know what the image is built from, since its ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/kitematic/hello-world-nginx/"},"Docker Hub page"),' has no links to any repositories. The only thing its Docker Hub page reveals is that the image is 9 years old. Even if the image\'s "Overview" section had links to a repository, we would have no guarantees that the published image was built from that source.'),(0,i.kt)("p",null,"There are also other Docker registries competing with Docker Hub, such as ",(0,i.kt)("a",{parentName:"p",href:"https://quay.io/"},"Quay"),". By default, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search")," will only search from Docker Hub, but to a search different registry, you can add the registry address before the search term, for example, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker search quay.io/hello"),". Alternatively, you can use the registry's web pages to search for images. Take a look at the page of ",(0,i.kt)("a",{parentName:"p",href:"https://quay.io/repository/nordstrom/hello-world"},"the ",(0,i.kt)("inlineCode",{parentName:"a"},"nordstrom/hello-world")," image on Quay"),". The page shows the command to use to pull the image, which reveals that we can also pull images from hosts other than Docker Hub:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"docker pull quay.io/nordstrom/hello-world")),(0,i.kt)("p",null,"So, if the host's name (here: ",(0,i.kt)("inlineCode",{parentName:"p"},"quay.io"),") is omitted, it will pull from Docker Hub by default."),(0,i.kt)("p",null,"NOTE: Trying the above command may fail giving manifest errors as the default tag latest is not present in quay.io/nordstrom/hello-world image. Specifying a correct tag for a image will pull the image without any errors, for ex.\n",(0,i.kt)("inlineCode",{parentName:"p"},"docker pull quay.io/nordstrom/hello-world:2.0")),(0,i.kt)("h2",{id:"a-detailed-look-into-an-image"},"A detailed look into an image"),(0,i.kt)("p",null,"Let's go back to a more relevant image than 'hello-world', the Ubuntu image, one of the most common Docker images to use as a base for your own image."),(0,i.kt)("p",null,"Let's pull Ubuntu and look at the first lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker pull ubuntu\n Using default tag: latest\n latest: Pulling from library/ubuntu\n")),(0,i.kt)("p",null,"Since we didn't specify a tag, Docker defaulted to ",(0,i.kt)("inlineCode",{parentName:"p"},"latest"),", which is usually the latest image built and pushed to the registry. ",(0,i.kt)("strong",{parentName:"p"},"However"),", in this case, the repository's ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/_/ubuntu"},"README")," says that the ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:latest"),' tag points to the "latest LTS" instead since that\'s the version recommended for general use.'),(0,i.kt)("p",null,"Images can be tagged to save different versions of the same image. You define an image's tag by adding ",(0,i.kt)("inlineCode",{parentName:"p"},":")," after the image's name."),(0,i.kt)("p",null,"Ubuntu's ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/library/ubuntu/tags/"},"Docker Hub page")," reveals that there's a tag named 22.04 which promises us that the image is based on Ubuntu 22.04. Let's pull that as well:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker pull ubuntu:22.04\n\n 18.04: Pulling from library/ubuntu\n c2ca09a1934b: Downloading [============================================> ] 34.25MB/38.64MB\n d6c3619d2153: Download complete\n 0efe07335a04: Download complete\n 6b1bb01b3a3b: Download complete\n 43a98c187399: Download complete\n")),(0,i.kt)("p",null,"Images are composed of different layers that are downloaded in parallel to speed up the download. Images being made of layers also have other aspects and we will talk about them in part 3."),(0,i.kt)("p",null,"We can also tag images locally for convenience, for example, ",(0,i.kt)("inlineCode",{parentName:"p"},"docker tag ubuntu:22.04 ubuntu:jammy_jellyfish")," creates the tag ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:jammy_jellyfish")," which refers to ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu:22.04"),"."),(0,i.kt)("p",null,'Tagging is also a way to "rename" images. Run ',(0,i.kt)("inlineCode",{parentName:"p"},"docker tag ubuntu:22.04 fav_distro:jammy_jellyfish")," and check ",(0,i.kt)("inlineCode",{parentName:"p"},"docker image ls")," to see what effects the command had."),(0,i.kt)("p",null,"To summarize, an image name may consist of 3 parts plus a tag. Usually like the following: ",(0,i.kt)("inlineCode",{parentName:"p"},"registry/organisation/image:tag"),". But may be as short as ",(0,i.kt)("inlineCode",{parentName:"p"},"ubuntu"),", then the registry will default to Docker hub, organisation to ",(0,i.kt)("em",{parentName:"p"},"library")," and tag to ",(0,i.kt)("em",{parentName:"p"},"latest"),". The organisation may also be a user, but calling it an organisation may be more clear."),(0,i.kt)("h2",{id:"exercises-15---16"},"Exercises 1.5 - 1.6"),(0,i.kt)("admonition",{title:"Exercise 1.5: Sizes of images",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"In the ",(0,i.kt)("a",{parentName:"p",href:"/part-1/section-2#exercise-13"},"Exercise 1.3")," we used ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:ubuntu"),"."),(0,i.kt)("p",{parentName:"admonition"},"Here is the same application but instead of Ubuntu is using ",(0,i.kt)("a",{parentName:"p",href:"https://www.alpinelinux.org/"},"Alpine Linux"),": ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:alpine"),"."),(0,i.kt)("p",{parentName:"admonition"},"Pull both images and compare the image sizes.\nGo inside the Alpine container and make sure the secret message functionality is the same. Alpine version doesn't have ",(0,i.kt)("inlineCode",{parentName:"p"},"bash")," but it has ",(0,i.kt)("inlineCode",{parentName:"p"},"sh"),", a more bare-bones shell.")),(0,i.kt)("admonition",{title:"Exercise 1.6: Hello Docker Hub",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run -it devopsdockeruh/pull_exercise"),"."),(0,i.kt)("p",{parentName:"admonition"},"The command will wait for your input."),(0,i.kt)("p",{parentName:"admonition"},"Navigate through the ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/"},"Docker hub")," to find the docs and Dockerfile that was used to create the image."),(0,i.kt)("p",{parentName:"admonition"},'Read the Dockerfile and/or docs to learn what input will get the application to answer a "secret message".'),(0,i.kt)("p",{parentName:"admonition"},"Submit the secret message and command(s) given to get it as your answer.")),(0,i.kt)("h2",{id:"building-images"},"Building images"),(0,i.kt)("p",null,"Finally, we get to build our own images and get to talk about ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/"},(0,i.kt)("inlineCode",{parentName:"a"},"Dockerfile"))," and why it's so great."),(0,i.kt)("p",null,"Dockerfile is simply a file that contains the build instructions for an image. You define what should be included in the image with different instructions. We'll learn about the best practices here by creating one."),(0,i.kt)("p",null,'Let\'s take a most simple application and containerize it first. Here is a script called "hello.sh"'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"hello.sh")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-sh"},'#!/bin/sh\n\necho "Hello, docker!"\n')),(0,i.kt)("p",null,"First, we will test that it even works. Create the file, add execution permissions and run it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ chmod +x hello.sh\n\n$ ./hello.sh\n Hello, docker!\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"If you're using Windows you can skip these two and add chmod +x hello.sh to the Dockerfile.")),(0,i.kt)("p",null,"And now to create an image from it. We'll have to create the ",(0,i.kt)("inlineCode",{parentName:"p"},"Dockerfile")," that declares all of the required dependencies. At least it depends on something that can run shell scripts. We will choose ",(0,i.kt)("a",{parentName:"p",href:"https://www.alpinelinux.org/"},"Alpine"),", a small Linux distribution that is often used to create small images."),(0,i.kt)("p",null,"Even though we're using Alpine here, you can use Ubuntu during exercises. Ubuntu images by default contain more tools to debug what is wrong when something doesn't work. In part 3 we will talk more about why small images are important."),(0,i.kt)("p",null,"We will choose exactly which version of a given image we want to use. This guarantees that we don't accidentally update through a breaking change, and we know which images need updating when there are known security vulnerabilities in old images."),(0,i.kt)("p",null,'Now create a file and name it "Dockerfile" and put the following instructions inside it:'),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dockerfile")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-Dockerfile"},"# Start from the alpine image that is smaller but no fancy tools\nFROM alpine:3.19\n\n# Use /usr/src/app as our workdir. The following instructions will be executed in this location.\nWORKDIR /usr/src/app\n\n# Copy the hello.sh file from this directory to /usr/src/app/ creating /usr/src/app/hello.sh\nCOPY hello.sh .\n\n# Alternatively, if we skipped chmod earlier, we can add execution permissions during the build.\n# RUN chmod +x hello.sh\n\n# When running docker run the command will be ./hello.sh\nCMD ./hello.sh\n")),(0,i.kt)("p",null,"Great! We can use the command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/build/"},"docker build")," to turn the Dockerfile to an image."),(0,i.kt)("p",null,"By default ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build")," will look for a file named Dockerfile. Now we can run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build")," with instructions where to build (",(0,i.kt)("inlineCode",{parentName:"p"},"."),") and give it a name (",(0,i.kt)("inlineCode",{parentName:"p"},"-t "),"):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker build . -t hello-docker\n => [internal] load build definition from Dockerfile 0.0s\n => => transferring dockerfile: 478B 0.0s\n => [internal] load metadata for docker.io/library/alpine:3.19 2.1s\n => [auth] library/alpine:pull token for registry-1.docker.io 0.0s\n => [internal] load .dockerignore 0.0s\n => => transferring context: 2B 0.0s\n => [1/3] FROM docker.io/library/alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b 0.0s\n => [internal] load build context 0.0s\n => => transferring context: 68B 0.0s\n => [2/3] WORKDIR /usr/src/app 0.0s\n => [3/3] COPY hello.sh . 0.0s\n => exporting to image 0.0s\n => => exporting layers 0.0s\n => => writing image sha256:5f8f5d7445f34b0bcfaaa4d685a068cdccc1ed79e65068337a3a228c79ea69c8 0.0s\n => => naming to docker.io/library/hello-docker\n")),(0,i.kt)("p",null,"Let us ensure that the image exists:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"$ docker image ls\n REPOSITORY TAG IMAGE ID CREATED SIZE\n hello-docker latest 5f8f5d7445f3 4 minutes ago 7.73MB\n")),(0,i.kt)("admonition",{title:"Permission denied",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you're now getting \"/bin/sh: ./hello.sh: Permission denied\" it's because the ",(0,i.kt)("inlineCode",{parentName:"p"},"chmod +x hello.sh")," was skipped earlier. You can simply uncomment the RUN instruction between COPY and CMD instructions")),(0,i.kt)("admonition",{title:"not found",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you're now getting \"/bin/sh: ./hello.sh: not found\" and you're using Windows it might be because by default Windows uses ",(0,i.kt)("a",{parentName:"p",href:"https://www.cs.toronto.edu/~krueger/csc209h/tut/line-endings.html"},"CRLF")," as line ending. Unix, in our case Alpine, uses just LF which makes the copying of our ",(0,i.kt)("inlineCode",{parentName:"p"},"hello.sh")," invalid bash script in the build phase. To overcome this error change the line endings to LF before running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build"))),(0,i.kt)("p",null,"Now executing the application is as simple as running ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run hello-docker"),". Try it!"),(0,i.kt)("p",null,"During the build we see from the output that there are three steps: ","[1/3]",", ","[2/3]"," and ","[3/3]",". The steps here represent ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/build/guide/layers/"},"layers")," of the image so that each step is a new layer on top of the base image (alpine:3.19 in our case)."),(0,i.kt)("p",null,"Layers have multiple functions. We often try to limit the number of layers to save on storage space but layers can work as a cache during build time. If we just edit the last lines of Dockerfile the build command can start from the previous layer and skip straight to the section that has changed. COPY automatically detects changes in the files, so if we change the hello.sh it'll run from step 3/3, skipping 1 and 2. This can be used to create faster build pipelines. We'll talk more about optimization in part 3."),(0,i.kt)("p",null,"It is also possible to manually create new layers on top of a image. Let us now create a new file called ",(0,i.kt)("inlineCode",{parentName:"p"},"additional.txt")," and copy it inside a container."),(0,i.kt)("p",null,"We'll need two terminals, that shall be called 1 and 2 in the following listings. Let us start by running the image: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 1\n$ docker run -it hello-docker sh\n/usr/src/app #\n")),(0,i.kt)("p",null,"Now we're inside of the container. We replaced the CMD we defined earlier with ",(0,i.kt)("inlineCode",{parentName:"p"},"sh")," and used -i and -t to start the container so that we can interact with it."),(0,i.kt)("p",null,"In the second terminal we will copy the file inside the contained:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},'# do this in terminal 2\n$ docker ps\n CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n 9c06b95e3e85 hello-docker "sh" 4 minutes ago Up 4 minutes zen_rosalind\n\n$ touch additional.txt\n$ docker cp ./additional.txt zen_rosalind:/usr/src/app/\n')),(0,i.kt)("p",null,"The file is created with command ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," right before copying it in."),(0,i.kt)("p",null,"Let us ensure that the file is copied inside the container:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 1\n/usr/src/app # ls\nadditional.txt hello.sh\n")),(0,i.kt)("p",null,"Great! Now we've made a change to the container. We can use command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/reference/cli/docker/container/diff/"},"docker diff")," to check what has changed"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 2\n$ docker diff zen_rosalind\n C /usr\n C /usr/src\n C /usr/src/app\n A /usr/src/app/additional.txt\n C /root\n A /root/.ash_history\n")),(0,i.kt)("p",null,"The character in front of the file name indicates the type of the change in the container's filesystem: A = added, D = deleted, C = changed. The additional.txt was created and our ",(0,i.kt)("inlineCode",{parentName:"p"},"ls")," created .ash_history."),(0,i.kt)("p",null,"Next we will save the changes as ",(0,i.kt)("em",{parentName:"p"},"a new image")," with the command ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/commandline/container_commit/"},"docker commit"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-console"},"# do this in terminal 2\n$ docker commit zen_rosalind hello-docker-additional\n sha256:2f63baa355ce5976bf89fe6000b92717f25dd91172aed716208e784315bfc4fd\n$ docker image ls\n REPOSITORY TAG IMAGE ID CREATED SIZE\n hello-docker-additional latest 2f63baa355ce 3 seconds ago 7.73MB\n hello-docker latest 444f21cf7bd5 31 minutes ago 7.73MB\n")),(0,i.kt)("p",null,"Technically the command ",(0,i.kt)("inlineCode",{parentName:"p"},"docker commit")," added a new layer on top of the image ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-docker"),", and the resulting image was given the name ",(0,i.kt)("inlineCode",{parentName:"p"},"hello-docker-additional"),"."),(0,i.kt)("p",null,"We will actually not use the command ",(0,i.kt)("inlineCode",{parentName:"p"},"docker commit")," again during this course. This is because defining the changes to the Dockerfile is much more sustainable method of managing changes. No magic actions or scripts, just a Dockerfile that can be version controlled."),(0,i.kt)("p",null,"Let's do just that and create hello-docker with v2 tag that includes the file additional.txt. The new file can be added with a ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#run"},"RUN")," instruction:"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dockerfile")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-Dockerfile"},"# Start from the alpine image\nFROM alpine:3.19\n\n# Use /usr/src/app as our workdir. The following instructions will be executed in this location.\nWORKDIR /usr/src/app\n\n# Copy the hello.sh file from this location to /usr/src/app/ creating /usr/src/app/hello.sh.\nCOPY hello.sh .\n\n# Execute a command with `/bin/sh -c` prefix.\nRUN touch additional.txt\n\n# When running Docker run the command will be ./hello.sh\nCMD ./hello.sh\n")),(0,i.kt)("p",null,"Now we used the RUN instruction to execute the command ",(0,i.kt)("inlineCode",{parentName:"p"},"touch additional.txt")," which creates a file inside the resulting image. Pretty much anything that can be executed in the container based on the created image, can be instructed to be run with the RUN instruction during the build of a Dockerfile."),(0,i.kt)("p",null,"Build now the Dockerfile with ",(0,i.kt)("inlineCode",{parentName:"p"},"docker build . -t hello-docker:v2")," and we are done! Let's compare the output of ls:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"$ docker run hello-docker-additional ls\n additional.txt\n hello.sh\n\n$ docker run hello-docker:v2 ls\n additional.txt\n hello.sh\n")),(0,i.kt)("p",null,"Now we know that all instructions in a Dockerfile ",(0,i.kt)("strong",{parentName:"p"},"except")," CMD (and one other that we will learn about soon) are executed during build time. ",(0,i.kt)("strong",{parentName:"p"},"CMD")," is executed when we call docker run, unless we overwrite it."),(0,i.kt)("h2",{id:"exercises-17---18"},"Exercises 1.7 - 1.8"),(0,i.kt)("admonition",{title:"Exercise 1.7: Image for script",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We can improve our previous solutions now that we know how to create and build a Dockerfile."),(0,i.kt)("p",{parentName:"admonition"},"Let us now get back to ",(0,i.kt)("a",{parentName:"p",href:"/part-1/section-2#exercise-14"},"Exercise 1.4"),"."),(0,i.kt)("p",{parentName:"admonition"},"Create a new file ",(0,i.kt)("inlineCode",{parentName:"p"},"script.sh")," on your local machine with the following contents:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'while true\ndo\n echo "Input website:"\n read website; echo "Searching.."\n sleep 1; curl http://$website\ndone\n')),(0,i.kt)("p",{parentName:"admonition"},"Create a Dockerfile for a new image that starts from ",(0,i.kt)("em",{parentName:"p"},"ubuntu:22.04")," and add instructions to install ",(0,i.kt)("inlineCode",{parentName:"p"},"curl")," into that image. Then add instructions to copy the script file into that image and finally set it to run on container start using CMD."),(0,i.kt)("p",{parentName:"admonition"},'After you have filled the Dockerfile, build the image with the name "curler".'),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"If you are getting permission denied, use ",(0,i.kt)("inlineCode",{parentName:"li"},"chmod")," to give permission to run the script.")),(0,i.kt)("p",{parentName:"admonition"},"The following should now work:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker run -it curler\n\n Input website:\n helsinki.fi\n Searching..\n \n \n 301 Moved Permanently\n \n

Moved Permanently

\n

The document has moved here.

\n \n')),(0,i.kt)("p",{parentName:"admonition"},"Remember that ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#run"},"RUN")," can be used to execute commands while building the image!"),(0,i.kt)("p",{parentName:"admonition"},"Submit the Dockerfile.")),(0,i.kt)("admonition",{title:"Exercise 1.8: Two line Dockerfile",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"By default our ",(0,i.kt)("inlineCode",{parentName:"p"},"devopsdockeruh/simple-web-service:alpine")," doesn't have a CMD. Instead, it uses ",(0,i.kt)("em",{parentName:"p"},"ENTRYPOINT")," to declare which application is run."),(0,i.kt)("p",{parentName:"admonition"},"We'll talk more about ",(0,i.kt)("em",{parentName:"p"},"ENTRYPOINT")," in the next section, but you already know that the last argument in ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run")," can be used to give a command or an argument."),(0,i.kt)("p",{parentName:"admonition"},"As you might've noticed it doesn't start the web service even though the name is \"simple-web-service\". A suitable argument is needed to start the server!"),(0,i.kt)("p",{parentName:"admonition"},"Try ",(0,i.kt)("inlineCode",{parentName:"p"},"docker run devopsdockeruh/simple-web-service:alpine hello"),'. The application reads the argument "hello" but will inform that hello isn\'t accepted.'),(0,i.kt)("p",{parentName:"admonition"},"In this exercise create a Dockerfile and use FROM and CMD to create a brand new image that automatically runs ",(0,i.kt)("inlineCode",{parentName:"p"},"server"),"."),(0,i.kt)("p",{parentName:"admonition"},"The Docker documentation ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/engine/reference/builder/#cmd"},"CMD")," says a bit indirectly that if a image has ENTRYPOINT defined, CMD is used to define it the default arguments."),(0,i.kt)("p",{parentName:"admonition"},'Tag the new image as "web-server"'),(0,i.kt)("p",{parentName:"admonition"},"Return the Dockerfile and the command you used to run the container."),(0,i.kt)("p",{parentName:"admonition"},'Running the built "web-server" image should look like this:'),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-console"},'$ docker run web-server\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.\n- using env: export GIN_MODE=release\n- using code: gin.SetMode(gin.ReleaseMode)\n\n[GIN-debug] GET /*path --\x3e server.Start.func1 (3 handlers)\n[GIN-debug] Listening and serving HTTP on :8080\n')),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"We don't have any method of accessing the web service yet. As such confirming that the console output is the same will suffice.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"The exercise title may be a useful hint here.")))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/main.e1150bb0.js b/assets/js/main.f3743596.js similarity index 99% rename from assets/js/main.e1150bb0.js rename to assets/js/main.f3743596.js index 637ebfe6..70173464 100644 --- a/assets/js/main.e1150bb0.js +++ b/assets/js/main.f3743596.js @@ -1,2 +1,2 @@ -/*! For license information please see main.e1150bb0.js.LICENSE.txt */ -(self.webpackChunk=self.webpackChunk||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(7462),o=n(8356),i=n.n(o),l=n(6887);const s={"0480b142":[()=>n.e(836).then(n.bind(n,3584)),"@site/docs/faq.md",3584],"06d0a36c":[()=>n.e(366).then(n.bind(n,2403)),"@site/docs/part-2/section-3.md",2403],"0760ddad":[()=>n.e(48).then(n.bind(n,1389)),"@site/docs/part-1/section-4.md",1389],"0da1f8d4":[()=>n.e(139).then(n.bind(n,3071)),"@site/docs/part-2/section-4.md",3071],"10e9c4ba":[()=>n.e(862).then(n.bind(n,8494)),"@site/docs/part-1/section-5.md",8494],"14eb3368":[()=>Promise.all([n.e(532),n.e(817)]).then(n.bind(n,4228)),"@theme/DocCategoryGeneratedIndexPage",4228],"152729e2":[()=>n.e(943).then(n.bind(n,5683)),"@site/docs/part-3/section-6.md",5683],17896441:[()=>Promise.all([n.e(532),n.e(918)]).then(n.bind(n,5824)),"@theme/DocItem",5824],"18ba09e8":[()=>n.e(657).then(n.bind(n,3375)),"@site/docs/credits.md",3375],"1be78505":[()=>Promise.all([n.e(532),n.e(514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"2d61a0bd":[()=>n.e(906).then(n.t.bind(n,4858,19)),"~docs/default/category-materialsidebar-category-part-3-0b8.json",4858],"3006da3d":[()=>n.e(654).then(n.bind(n,1851)),"@site/docs/part-2/section-5.md",1851],"3358ea11":[()=>n.e(540).then(n.bind(n,7506)),"@site/docs/part-2/section-2.md",7506],"3496bbe8":[()=>n.e(882).then(n.bind(n,9999)),"@site/docs/part-3/section-3.md",9999],"3669c705":[()=>n.e(768).then(n.bind(n,5146)),"@site/docs/part-3/index.md",5146],"4172bbd4":[()=>n.e(501).then(n.bind(n,154)),"@site/docs/part-1/section-1.md",154],"44a2208c":[()=>n.e(328).then(n.t.bind(n,6031,19)),"~docs/default/category-materialsidebar-category-part-2-e23.json",6031],"5e47b935":[()=>n.e(948).then(n.bind(n,3906)),"@site/docs/part-1/section-2.md",3906],"71951c43":[()=>n.e(93).then(n.bind(n,8660)),"@site/docs/part-1/section-6.md",8660],"85ab0e2f":[()=>n.e(97).then(n.bind(n,7544)),"@site/docs/part-3/section-2.md",7544],"88cfbd19":[()=>n.e(935).then(n.bind(n,9524)),"@site/docs/part-3/section-4.md",9524],"8c5badca":[()=>n.e(847).then(n.t.bind(n,4245,19)),"~docs/default/category-materialsidebar-category-part-1-c10.json",4245],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"9ed8673f":[()=>n.e(261).then(n.t.bind(n,3769,19)),"/home/runner/work/docker-hy.github.io/docker-hy.github.io/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],b99b65ed:[()=>n.e(221).then(n.bind(n,888)),"@site/docs/part-1/index.md",888],c6640654:[()=>n.e(745).then(n.bind(n,383)),"@site/docs/part-3/section-5.md",383],cca8f319:[()=>n.e(451).then(n.bind(n,320)),"@site/docs/part-2/index.md",320],d589d3a7:[()=>n.e(162).then(n.bind(n,9390)),"@site/docs/getting-started.md",9390],dbf6ab84:[()=>n.e(258).then(n.bind(n,3469)),"@site/docs/part-3/section-1.md",3469],eea426ee:[()=>n.e(538).then(n.bind(n,7530)),"@site/docs/part-2/section-1.md",7530],f1c60e00:[()=>n.e(33).then(n.bind(n,6920)),"@site/docs/part-1/section-3.md",6920],f8409a7e:[()=>Promise.all([n.e(532),n.e(206)]).then(n.bind(n,3509)),"@site/docs/intro.mdx",3509],ff03218c:[()=>n.e(632).then(n.bind(n,6093)),"@site/docs/part-1/section-7.md",6093]};function u(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var c=n(9670),d=n(226);function f(e,t){if("*"===e)return i()({loading:u,loader:()=>n.e(972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const o=l[`${e}-${t}`],f={},p=[],m=[],h=(0,c.Z)(o);return Object.entries(h).forEach((e=>{let[t,n]=e;const r=s[n];r&&(f[t]=r[0],p.push(r[1]),m.push(r[2]))})),i().Map({loading:u,loader:f,modules:p,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let o=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{o=o[e]})),o[l[l.length-1]]=a}));const l=i.__comp;delete i.__comp;const s=i.__context;return delete i.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,a.Z)({},i,n)))}})}const p=[{path:"/",component:f("/","ca0"),routes:[{path:"/",component:f("/","a21"),exact:!0,sidebar:"materialSidebar"},{path:"/category/part-1",component:f("/category/part-1","31f"),exact:!0,sidebar:"materialSidebar"},{path:"/category/part-2",component:f("/category/part-2","5c2"),exact:!0,sidebar:"materialSidebar"},{path:"/category/part-3",component:f("/category/part-3","395"),exact:!0,sidebar:"materialSidebar"},{path:"/credits",component:f("/credits","f75"),exact:!0,sidebar:"materialSidebar"},{path:"/faq",component:f("/faq","2d3"),exact:!0,sidebar:"materialSidebar"},{path:"/getting-started",component:f("/getting-started","2d9"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/",component:f("/part-1/","29b"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-1",component:f("/part-1/section-1","53c"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-2",component:f("/part-1/section-2","0ad"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-3",component:f("/part-1/section-3","092"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-4",component:f("/part-1/section-4","879"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-5",component:f("/part-1/section-5","5f5"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-6",component:f("/part-1/section-6","d3b"),exact:!0,sidebar:"materialSidebar"},{path:"/part-1/section-7",component:f("/part-1/section-7","ee1"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/",component:f("/part-2/","97f"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/section-1",component:f("/part-2/section-1","44d"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/section-2",component:f("/part-2/section-2","521"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/section-3",component:f("/part-2/section-3","a8e"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/section-4",component:f("/part-2/section-4","d1f"),exact:!0,sidebar:"materialSidebar"},{path:"/part-2/section-5",component:f("/part-2/section-5","a8a"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/",component:f("/part-3/","bfe"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-1",component:f("/part-3/section-1","03d"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-2",component:f("/part-3/section-2","edf"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-3",component:f("/part-3/section-3","bf2"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-4",component:f("/part-3/section-4","89f"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-5",component:f("/part-3/section-5","10f"),exact:!0,sidebar:"materialSidebar"},{path:"/part-3/section-6",component:f("/part-3/section-6","1b6"),exact:!0,sidebar:"materialSidebar"}]},{path:"*",component:f("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>o});var r=n(7294);const a=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),o=n(3727),i=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(2295)];var u=n(723),c=n(6550),d=n(8790);function f(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var p=n(7462),m=n(5742),h=n(2263),g=n(4996),b=n(6668),v=n(1944),y=n(4711),w=n(9727),k=n(3320),E=n(197);function S(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,h.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function x(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.Z)(),a=function(){const{siteConfig:{url:e}}=(0,h.Z)(),{pathname:t}=(0,c.TH)();return e+(0,g.Z)(t)}(),o=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:o}),r.createElement("link",{rel:"canonical",href:o}))}function C(){const{i18n:{currentLocale:e}}=(0,h.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(x,null),r.createElement(S,null),r.createElement(E.Z,{tag:k.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,p.Z)({key:t},e))))))}const _=new Map;function T(e){if(_.has(e.pathname))return{...e,pathname:_.get(e.pathname)};if((0,d.f)(u.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return _.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return _.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),L=n(8940);function R(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const N=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),R("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function O(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(u.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class P extends r.Component{constructor(e){super(e),this.previousLocation=void 0,this.routeUpdateCleanupCb=void 0,this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?R("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=R("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),O(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(N,{previousLocation:this.previousLocation,location:t},r.createElement(c.AW,{location:t,render:()=>e}))}}const D=P,I="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner",F="docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function j(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${I}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{window[B]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,j(e))),r.createElement("div",{id:I}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,h.Z)(),{pathname:n}=(0,c.TH)();return t&&n===e?r.createElement(z,null):null}function $(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,h.Z)(),i=(0,g.Z)(e),{htmlLang:l,direction:s}=o[a];return r.createElement(m.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var q=n(4763);function H(){const e=(0,d.H)(u.Z),t=(0,c.TH)();return r.createElement(q.Z,null,r.createElement(L.M,null,r.createElement(A.t,null,r.createElement(f,null,r.createElement($,null),r.createElement(C,null),r.createElement(U,null),r.createElement(D,{location:T(t)},e)))))}var G=n(6887);const Z=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var V=n(9670);const W=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!W.has(e))(e))return!1;W.add(e);const t=(0,d.f)(u.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,V.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Z(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),O(e))},X=Object.freeze(Q);if(l.Z.canUseDOM){window.docusaurus=X;const e=a.hydrate;O(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(o.VK,null,r.createElement(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>c,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-lunr-search":{"default":{"fileNames":{"searchDoc":"search-doc-1709761755256.json","lunrIndex":"lunr-index-1709761755256.json"}}},"docusaurus-plugin-content-docs":{"default":{"path":"/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/","mainDocId":"intro","docs":[{"id":"credits","path":"/credits","sidebar":"materialSidebar"},{"id":"faq","path":"/faq","sidebar":"materialSidebar"},{"id":"getting-started","path":"/getting-started","sidebar":"materialSidebar"},{"id":"intro","path":"/","sidebar":"materialSidebar"},{"id":"part-1/index","path":"/part-1/","sidebar":"materialSidebar"},{"id":"part-1/section-1","path":"/part-1/section-1","sidebar":"materialSidebar"},{"id":"part-1/section-2","path":"/part-1/section-2","sidebar":"materialSidebar"},{"id":"part-1/section-3","path":"/part-1/section-3","sidebar":"materialSidebar"},{"id":"part-1/section-4","path":"/part-1/section-4","sidebar":"materialSidebar"},{"id":"part-1/section-5","path":"/part-1/section-5","sidebar":"materialSidebar"},{"id":"part-1/section-6","path":"/part-1/section-6","sidebar":"materialSidebar"},{"id":"part-1/section-7","path":"/part-1/section-7","sidebar":"materialSidebar"},{"id":"part-2/index","path":"/part-2/","sidebar":"materialSidebar"},{"id":"part-2/section-1","path":"/part-2/section-1","sidebar":"materialSidebar"},{"id":"part-2/section-2","path":"/part-2/section-2","sidebar":"materialSidebar"},{"id":"part-2/section-3","path":"/part-2/section-3","sidebar":"materialSidebar"},{"id":"part-2/section-4","path":"/part-2/section-4","sidebar":"materialSidebar"},{"id":"part-2/section-5","path":"/part-2/section-5","sidebar":"materialSidebar"},{"id":"part-3/index","path":"/part-3/","sidebar":"materialSidebar"},{"id":"part-3/section-1","path":"/part-3/section-1","sidebar":"materialSidebar"},{"id":"part-3/section-2","path":"/part-3/section-2","sidebar":"materialSidebar"},{"id":"part-3/section-3","path":"/part-3/section-3","sidebar":"materialSidebar"},{"id":"part-3/section-4","path":"/part-3/section-4","sidebar":"materialSidebar"},{"id":"part-3/section-5","path":"/part-3/section-5","sidebar":"materialSidebar"},{"id":"part-3/section-6","path":"/part-3/section-6","sidebar":"materialSidebar"},{"id":"/category/part-1","path":"/category/part-1","sidebar":"materialSidebar"},{"id":"/category/part-2","path":"/category/part-2","sidebar":"materialSidebar"},{"id":"/category/part-3","path":"/category/part-3","sidebar":"materialSidebar"}],"draftIds":[],"sidebars":{"materialSidebar":{"link":{"path":"/","label":"intro"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.3.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.3.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.3.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.3.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.3.1"},"docusaurus-lunr-search":{"type":"package","name":"docusaurus-lunr-search","version":"2.3.2"}}}'),u={siteConfig:a.Z,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},c=r.createContext(u);function d(e){let{children:t}=e;return r.createElement(c.Provider,{value:u},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var r=n(7294),a=n(412),o=n(5742),i=n(4510);function l(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function s(e){let{error:t,tryAgain:n}=e;return r.createElement(c,{fallback:()=>r.createElement(l,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(i.Z,null,r.createElement(l,{error:t,tryAgain:n})))}const u=e=>r.createElement(s,e);class c extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??u)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(405);function o(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>h});var r=n(7462),a=n(7294),o=n(3727),i=n(8780),l=n(2263),s=n(3919),u=n(412);const c=a.createContext({collectLink:()=>{}}),d=()=>(0,a.useContext)(c);var f=n(4996);const p=e=>e.startsWith("/");function m(e,t){let{isNavLink:n,to:c,href:m,activeClassName:h,isActive:g,"data-noBrokenLinkCheck":b,autoAddBaseUrl:v=!0,...y}=e;const{siteConfig:{trailingSlash:w,baseUrl:k}}=(0,l.Z)(),{withBaseUrl:E}=(0,f.C)(),S=d(),x=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>x.current));const C=c||m;const _=(0,s.Z)(C),T=C?.replace("pathname://","");let A=void 0!==T?(L=T,v&&p(L)?E(L):L):void 0;var L;A&&_&&(A=(0,i.applyTrailingSlash)(A,{trailingSlash:w,baseUrl:k}));const R=(0,a.useRef)(!1),N=n?o.OL:o.rU,O=u.Z.canUseIntersectionObserver,P=(0,a.useRef)(),D=()=>{R.current||null==A||(window.docusaurus.preload(A),R.current=!0)};(0,a.useEffect)((()=>(!O&&_&&null!=A&&window.docusaurus.prefetch(A),()=>{O&&P.current&&P.current.disconnect()})),[P,A,O,_]);const I=A?.startsWith("#")??!1,M=!A||!_||I;return M||b||S.collectLink(A),M?a.createElement("a",(0,r.Z)({ref:x,href:A},C&&!_&&{target:"_blank",rel:"noopener noreferrer"},y)):a.createElement(N,(0,r.Z)({},y,{onMouseEnter:D,onTouchStart:D,innerRef:e=>{x.current=e,O&&e&&_&&(P.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(P.current.unobserve(e),P.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),P.current.observe(e))},to:A},n&&{isActive:g,activeClassName:h}))}const h=a.forwardRef(m)},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const l=i({message:t,id:n});return r.createElement(r.Fragment,null,a(l,o))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},8084:(e,t,n)=>{"use strict";n.d(t,{OD:()=>o,eZ:()=>i});var r=n(2263),a=n(9935);function o(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,r.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}function i(e,t,n){void 0===t&&(t=a.m),void 0===n&&(n={});const r=o(e),i=r?.[t];if(!i&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return i}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t=".",n={};return function e(a,o){Object.entries(a).forEach((a=>{let[i,l]=a;const s=o?`${o}${t}${i}`:i;r(l)?e(l,s):n[s]=l}))}(e),n}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>o});var r=n(7294);const a=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(a),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return r.createElement(a.Provider,{value:i},t)}},4104:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>p,gA:()=>c,_r:()=>s,Jo:()=>m,zh:()=>u,yW:()=>f,gB:()=>d});var r=n(6550),a=n(8084);const o=e=>e.versions.find((e=>e.isLast));function i(e,t){const n=function(e,t){const n=o(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const l={},s=()=>(0,a.OD)("docusaurus-plugin-content-docs")??l,u=e=>(0,a.eZ)("docusaurus-plugin-content-docs",e,{failfast:!0});function c(e){void 0===e&&(e={});const t=s(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function d(e){return u(e).versions}function f(e){const t=u(e);return o(t)}function p(e){const t=u(e),{pathname:n}=(0,r.TH)();return i(t,n)}function m(e){const t=u(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=o(e);return{latestDocSuggestion:i(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.Z,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(6726)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function o(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},4510:(e,t,n)=>{"use strict";n.d(t,{Z:()=>ut});var r=n(7294),a=n(6010),o=n(4763),i=n(1944),l=n(7462),s=n(6550),u=n(5999),c=n(5936);const d="docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,c.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const m=(0,u.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:a}=p();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var g=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(h,{className:v.skipToContent})}var w=n(6668),k=n(9689);function E(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:o=1.2,className:i,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:o},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const S={closeButton:"closeButton_CVFx"};function x(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,u.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",S.closeButton,e.className)}),r.createElement(E,{width:14,height:14,strokeWidth:3.1}))}const C={content:"content_knG7"};function _(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(C.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const T={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function A(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,k.nT)();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return r.createElement("div",{className:T.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:T.announcementBarPlaceholder}),r.createElement(_,{className:T.announcementBarContent}),i&&r.createElement(x,{onClick:n,className:T.announcementBarClose}))}var L=n(2961),R=n(2466);var N=n(902),O=n(3102);const P=r.createContext(null);function D(e){let{children:t}=e;const n=function(){const e=(0,L.e)(),t=(0,O.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,N.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(P.Provider,{value:n},t)}function I(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(P);if(!e)throw new N.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,O.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:I(o)})),[a,o,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var B=n(2949),j=n(2389);function z(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function U(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function q(e){let{className:t,value:n,onChange:o}=e;const i=(0,j.Z)(),l=(0,u.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,u.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,u.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)($.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",$.toggleButton,!i&&$.toggleButtonDisabled),type:"button",onClick:()=>o("dark"===n?"light":"dark"),disabled:!i,title:l,"aria-label":l,"aria-live":"polite"},r.createElement(z,{className:(0,a.Z)($.toggleIcon,$.lightToggleIcon)}),r.createElement(U,{className:(0,a.Z)($.toggleIcon,$.darkToggleIcon)})))}const H=r.memo(q);function G(e){let{className:t}=e;const n=(0,w.L)().colorMode.disableSwitch,{colorMode:a,setColorMode:o}=(0,B.I)();return n?null:r.createElement(H,{className:t,value:a,onChange:o})}var Z=n(1327);function V(){return r.createElement(Z.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function W(){const e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,u.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(E,{color:"var(--ifm-color-emphasis-600)"}))}function Y(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(V,null),r.createElement(G,{className:"margin-right--md"}),r.createElement(W,null))}var K=n(9960),Q=n(4996),X=n(3919);function J(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var ee=n(9471);function te(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:u,prependBaseUrlToHref:c,...d}=e;const f=(0,Q.Z)(a),p=(0,Q.Z)(t),m=(0,Q.Z)(o,{forcePrependBaseUrl:!0}),h=i&&o&&!(0,X.Z)(o),g=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,h&&r.createElement(ee.Z,u&&{width:12,height:12}))};return o?r.createElement(K.Z,(0,l.Z)({href:c?m:o},d,g)):r.createElement(K.Z,(0,l.Z)({to:f,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?J(n,t.pathname):t.pathname.startsWith(p)},d,g))}function ne(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(te,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?r.createElement("li",null,i):i}function re(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(te,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function ae(e){let{mobile:t=!1,position:n,...a}=e;const o=t?re:ne;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var oe=n(6043),ie=n(8596),le=n(2263);function se(e,t){return e.some((e=>function(e,t){return!!(0,ie.Mg)(e.to,t)||!!J(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const u=(0,r.useRef)(null),[c,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{u.current&&!u.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[u]),r.createElement("div",{ref:u,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c})},r.createElement(te,(0,l.Z)({"aria-haspopup":"true","aria-expanded":c,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",o)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(Te,(0,l.Z)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.length-1&&"Tab"===e.key){e.preventDefault(),d(!1);const t=u.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:n}))))))}function ce(e){let{items:t,className:n,position:o,onClick:i,...u}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,le.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=se(t,c),{collapsed:f,toggleCollapsed:p,setCollapsed:m}=(0,oe.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[c,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":f})},r.createElement(te,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},u,{onClick:e=>{e.preventDefault(),p()}}),u.children??u.label),r.createElement(oe.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:f},t.map(((e,t)=>r.createElement(Te,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function de(e){let{mobile:t=!1,...n}=e;const a=t?ce:ue;return r.createElement(a,n)}var fe=n(4711);function pe(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const me={iconLanguage:"iconLanguage_nlXk"};var he=n(4184),ge=n.n(he),be=n(8084);const ve=e=>{const t=(0,r.useRef)(!1),a=(0,r.useRef)(null),[o,i]=(0,r.useState)(!1),l=(0,s.k6)(),{siteConfig:u={}}=(0,le.Z)(),c=(0,j.Z)(),{baseUrl:d}=u,f=(0,be.eZ)("docusaurus-lunr-search"),p=()=>{t.current||(Promise.all([fetch(`${d}${f.fileNames.searchDoc}`).then((e=>e.json())),fetch(`${d}${f.fileNames.lunrIndex}`).then((e=>e.json())),Promise.all([n.e(878),n.e(339)]).then(n.bind(n,894)),Promise.all([n.e(532),n.e(343)]).then(n.bind(n,3343))]).then((e=>{let[t,n,{default:r}]=e;0!==t.length&&(((e,t,n)=>{new n({searchDocs:e,searchIndex:t,baseUrl:d,inputSelector:"#search_input_react",handleSelected:(e,t,n)=>{const r=n.url||"/";document.createElement("a").href=r,l.push(r)}})})(t,n,r),i(!0))})),t.current=!0)},m=(0,r.useCallback)((t=>{a.current.contains(t.target)||a.current.focus(),e.handleSearchBarToggle&&e.handleSearchBarToggle(!e.isSearchBarExpanded)}),[e.isSearchBarExpanded]);return c&&p(),r.createElement("div",{className:"navbar__search",key:"search-box"},r.createElement("span",{"aria-label":"expand searchbar",role:"button",className:ge()("search-icon",{"search-icon-hidden":e.isSearchBarExpanded}),onClick:m,onKeyDown:m,tabIndex:0}),r.createElement("input",{id:"search_input_react",type:"search",placeholder:o?"Search":"Loading...","aria-label":"Search",className:ge()("navbar__search-input",{"search-bar-expanded":e.isSearchBarExpanded},{"search-bar":!e.isSearchBarExpanded}),onClick:p,onMouseOver:p,onFocus:m,onBlur:m,ref:a,disabled:!o}))},ye={searchBox:"searchBox_ZlJk"};function we(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,ye.searchBox)},t)}var ke=n(4104),Ee=n(2802);const Se=e=>e.docs.find((t=>t.id===e.mainDocId));var xe=n(373);const Ce=e=>e.docs.find((t=>t.id===e.mainDocId));const _e={default:ae,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:c,localeConfigs:d}}=(0,le.Z)(),f=(0,fe.l)(),{search:p,hash:m}=(0,s.TH)(),h=[...n,...c.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...a],g=t?(0,u.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(de,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(pe,{className:me.iconLanguage}),g),items:h}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(we,{className:n},r.createElement(ve,null))},dropdown:de,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,ke.Iw)(a),s=(0,Ee.vY)(t,a);return null===s?null:r.createElement(ae,(0,l.Z)({exact:!0},o,{isActive:()=>i?.path===s.path||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,ke.Iw)(a),s=(0,Ee.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(ae,(0,l.Z)({exact:!0},o,{isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...o}=e;const i=(0,Ee.lO)(a)[0],s=t??i.label,u=n??Se(i).path;return r.createElement(ae,(0,l.Z)({},o,{label:s,to:u}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...c}=e;const{search:d,hash:f}=(0,s.TH)(),p=(0,ke.Iw)(n),m=(0,ke.gB)(n),{savePreferredVersionName:h}=(0,xe.J)(n),g=[...o,...m.map((e=>{const t=p.alternateDocVersions[e.name]??Ce(e);return{label:e.label,to:`${t.path}${d}${f}`,isActive:()=>e===p.activeVersion,onClick:()=>h(e.name)}})),...i],b=(0,Ee.lO)(n)[0],v=t&&g.length>1?(0,u.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:Ce(b).path;return g.length<=1?r.createElement(ae,(0,l.Z)({},c,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(de,(0,l.Z)({},c,{mobile:t,label:v,to:y,items:g,isActive:a?()=>!1:void 0}))}};function Te(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=_e[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function Ae(){const e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Te,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Le(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(u.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Re(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Le,{onClick:()=>t.hide()}),t.content)}function Ne(){const e=(0,L.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(F,{header:r.createElement(Y,null),primaryMenu:r.createElement(Ae,null),secondaryMenu:r.createElement(Re,null)}):null}const Oe={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Pe(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function De(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,w.L)(),i=(0,L.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,R.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+u{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,"aria-label":(0,u.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Oe.navbarHideable,!s&&Oe.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Pe,{onClick:i.toggle}),r.createElement(Ne,null))}const Ie="right";function Me(e){let{width:t=30,height:n=30,className:a,...o}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Fe(){const{toggle:e,shown:t}=(0,L.e)();return r.createElement("button",{onClick:e,"aria-label":(0,u.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(Me,null))}const Be={colorModeToggle:"colorModeToggle_DEke"};function je(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Te,(0,l.Z)({},e,{key:t})))))}function ze(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Ue(){const e=(0,L.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??Ie)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(ze,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Fe,null),r.createElement(V,null),r.createElement(je,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(je,{items:a}),r.createElement(G,{className:Be.colorModeToggle}),!o&&r.createElement(we,null,r.createElement(ve,null)))})}function $e(){return r.createElement(De,null,r.createElement(Ue,null))}function qe(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,u=(0,Q.Z)(n),c=(0,Q.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(K.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?c:a}:{to:u},s),o,a&&!(0,X.Z)(a)&&r.createElement(ee.Z,null))}function He(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(qe,{item:t}))}function Ge(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(He,{key:t,item:e})))))}function Ze(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ge,{key:t,column:e}))))}function Ve(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function We(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(qe,{item:t})}function Ye(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(We,{item:e}),t.length!==n+1&&r.createElement(Ve,null))))))}function Ke(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(Ze,{columns:t}):r.createElement(Ye,{links:t})}var Qe=n(941);const Xe={footerLogoLink:"footerLogoLink_BH7S"};function Je(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Q.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(Qe.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function et(e){let{logo:t}=e;return t.href?r.createElement(K.Z,{href:t.href,className:Xe.footerLogoLink,target:t.target},r.createElement(Je,{logo:t})):r.createElement(Je,{logo:t})}function tt(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function nt(e){let{style:t,links:n,logo:o,copyright:i}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(o||i)&&r.createElement("div",{className:"footer__bottom text--center"},o&&r.createElement("div",{className:"margin-bottom--sm"},o),i)))}function rt(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(nt,{style:o,links:n&&n.length>0&&r.createElement(Ke,{links:n}),logo:a&&r.createElement(et,{logo:a}),copyright:t&&r.createElement(tt,{copyright:t})})}const at=r.memo(rt),ot=(0,N.Qc)([B.S,k.pl,R.OC,xe.L5,i.VC,function(e){let{children:t}=e;return r.createElement(O.n2,null,r.createElement(L.M,null,r.createElement(D,null,t)))}]);function it(e){let{children:t}=e;return r.createElement(ot,null,t)}function lt(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(u.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(u.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}const st={mainWrapper:"mainWrapper_z2l0"};function ut(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:u}=e;return(0,b.t)(),r.createElement(it,null,r.createElement(i.d,{title:s,description:u}),r.createElement(y,null),r.createElement(A,null),r.createElement($e,null),r.createElement("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,st.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(lt,e)},t)),!n&&r.createElement(at,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),o=n(9960),i=n(4996),l=n(2263),s=n(6668),u=n(941);function c(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=a.createElement(u.Z,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:u}}=(0,s.L)(),{imageClassName:d,titleClassName:f,...p}=e,m=(0,i.Z)(u?.href||"/"),h=n?"":t,g=u?.alt??h;return a.createElement(o.Z,(0,r.Z)({to:m},p,u?.target&&{target:u.target}),u&&a.createElement(c,{logo:u,alt:g,imageClassName:d}),null!=n&&a.createElement("b",{className:f},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(5742);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7462),a=n(7294),o=n(6010),i=n(2389),l=n(2949);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function u(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:u,className:c,alt:d,...f}=e,p=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,p.map((e=>a.createElement("img",(0,r.Z)({key:e,src:u[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],c)},f)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>l,z:()=>h});var r=n(7462),a=n(7294),o=n(412);const i="ease-in-out";function l(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),o=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:o}}const s={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function c(e,t){const n=t?s:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const o=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??i}`,height:`${t}px`}}function l(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return c(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function f(e){if(!o.Z.canUseDOM)return e?s:u}function p(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const u=(0,a.useRef)(null);return d({collapsibleRef:u,collapsed:n,animation:o}),a.createElement(t,{ref:u,style:s?void 0:f(n),onTransitionEnd:e=>{"height"===e.propertyName&&(c(u.current,n),i?.(n))},className:l},r)}function m(e){let{collapsed:t,...n}=e;const[o,i]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,a.useLayoutEffect)((()=>{o&&s(t)}),[o,t]),o?a.createElement(p,(0,r.Z)({},n,{collapsed:l})):null}function h(e){let{lazy:t,...n}=e;const r=t?m:p;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>p});var r=n(7294),a=n(2389),o=n(12),i=n(902),l=n(6668);const s=(0,o.WA)("docusaurus.announcement.dismiss"),u=(0,o.WA)("docusaurus.announcement.id"),c=()=>"true"===s.get(),d=e=>s.set(String(e)),f=r.createContext(null);function p(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,o]=(0,r.useState)((()=>!!t&&c()));(0,r.useEffect)((()=>{o(c())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&d(!1),!r&&c()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(f.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(f);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>g,S:()=>h});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),u="theme",c=(0,i.WA)(u),d={light:"light",dark:"dark"},f=e=>e===d.dark?d.dark:d.light,p=e=>a.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),m=e=>{c.set(f(e))};function h(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(p(e));(0,r.useEffect)((()=>{t&&c.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),c.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=c.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[a,i])}();return r.createElement(s.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>g});var r=n(7294),a=n(4104),o=n(9935),i=n(6668),l=n(2802),s=n(902),u=n(12);const c=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,u.WA)(c(e),{persistence:t}).set(n)},read:(e,t)=>(0,u.WA)(c(e),{persistence:t}).get(),clear:(e,t)=>{(0,u.WA)(c(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const p=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>f(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function h(e){let{children:t}=e;const n=m();return r.createElement(p.Provider,{value:n},t)}function g(e){let{children:t}=e;return l.cE?r.createElement(h,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(p);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.m);const t=(0,a.zh)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(i.Provider,{value:o},t)}function s(){const e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>l,q:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t,version:n}=e;return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(null===e)throw new a.i6("DocsVersionProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>f,e:()=>p});var r=n(7294),a=n(3102),o=n(7524),i=n(6550),l=(n(1688),n(902));function s(e){!function(e){const t=(0,i.k6)(),n=(0,l.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var u=n(6668);const c=r.createContext(void 0);function d(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,u.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1);s((()=>{if(i)return l(!1),!1}));const c=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:c,shown:i})),[e,n,c,i])}function f(e){let{children:t}=e;const n=d();return r.createElement(c.Provider,{value:n},t)}function p(){const e=r.useContext(c);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>u});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){return a.Z.canUseDOM?window.innerWidth>i?o.desktop:o.mobile:o.ssr}const s=!1;function u(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},2802:(e,t,n)=>{"use strict";n.d(t,{MN:()=>C,Wl:()=>m,_F:()=>v,cE:()=>f,jA:()=>h,xz:()=>p,hI:()=>x,lO:()=>k,vY:()=>S,oz:()=>E,s1:()=>w});var r=n(7294),a=n(6550),o=n(8790),i=n(4104),l=n(373),s=n(4477),u=n(1116);function c(e){return Array.from(new Set(e))}var d=n(8596);const f=!!i._r;function p(e){const t=(0,s.E)();if(!e)return;const n=t.docs[e];if(!n)throw new Error(`no version doc found by id=${e}`);return n}function m(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=m(t);if(e)return e}}}function h(){const{pathname:e}=(0,a.TH)(),t=(0,u.V)();if(!t)throw new Error("Unexpected: cant find current sidebar in context");const n=y({sidebarItems:t.items,pathname:e,onlyCategories:!0}).slice(-1)[0];if(!n)throw new Error(`${e} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`);return n}const g=(e,t)=>void 0!==e&&(0,d.Mg)(e,t),b=(e,t)=>e.some((e=>v(e,t)));function v(e,t){return"link"===e.type?g(e.href,t):"category"===e.type&&(g(e.href,t)||b(e.items,t))}function y(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function w(){const e=(0,u.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>c([t,n,a].filter(Boolean))),[t,n,a])}function E(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\n Available sidebar ids are:\n - ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function S(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`DocNavbarItem: couldn't find any doc with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function x(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),i=t.routes,l=i.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,u=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:u}}function C(e){return e.filter((e=>"category"!==e.type||!!m(e)))}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>f,d:()=>c,VC:()=>p});var r=n(7294),a=n(6010),o=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),u=n(2263);function c(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const c=function(e){const{siteConfig:t}=(0,u.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.C)(),f=i?d(i,{absolute:!0}):void 0;return r.createElement(o.Z,null,t&&r.createElement("title",null,c),t&&r.createElement("meta",{property:"og:title",content:c}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),f&&r.createElement("meta",{property:"og:image",content:f}),f&&r.createElement("meta",{name:"twitter:image",content:f}),l)}const d=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function p(e){let{children:t}=e;const n=l(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(f,{className:(0,a.Z)(o,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>u,Ql:()=>s,i6:()=>l,zX:()=>o});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function o(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>l});var r=n(7294),a=n(723),o=n(2263);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>f,OC:()=>s,RF:()=>d});var r=n(7294),a=n(412),o=n(2389),i=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function u(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const c=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),a=(0,r.useRef)(c()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=c();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function f(){const e=(0,r.useRef)(null),t=(0,o.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&at&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>s});n(7294),n(1688);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=o(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>o});var r=n(2263),a=n(6550);function o(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:o}}=(0,r.Z)(),{pathname:i}=(0,a.TH)(),l=o===n?e:e.replace(`/${o}/`,"/"),s=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),a=n(6550),o=n(902);function i(e){const t=(0,a.TH)(),n=(0,o.D9)(t),i=(0,o.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(a,o)}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}})},4184:(e,t)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function a(){for(var e=[],t=0;t{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;ta});const a=function(){for(var e,t,n=0,a="";n{"use strict";n.d(t,{lX:()=>w,q_:()=>_,ob:()=>p,PP:()=>A,Ep:()=>f});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r=0;f--){var p=i[f];"."===p?o(i,f):".."===p?(o(i,f),d++):d&&(o(i,f),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function p(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=p(e,t,h(),w.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var u=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=p(n);a&&a!==m&&e(t,a,r)}var i=c(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),g=0;g{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),u=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&p(a),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function u(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var o,i,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s{var r=n(5826);e.exports=p,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=f;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",c=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],f=n[1],p=n.index;if(l+=e.slice(i,p),i=p+d.length,f)l+=f[1];else{var m=e[i],h=n[2],g=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=h&&null!=m&&m!==h,E="+"===y||"*"===y,S="?"===y||"*"===y,x=n[2]||c,C=b||v;r.push({name:g||o++,prefix:h||"",delimiter:x,optional:S,repeat:E,partial:k,asterisk:!!w,pattern:C?u(C):w?".*":"[^"+s(x)+"]+?"})}}return i{"use strict";n.d(t,{Z:()=>o});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);S+=E.value.length,E=E.next){var x=E.value;if(t.length>e.length)return;if(!(x instanceof a)){var C,_=1;if(v){if(!(C=o(k,S,e,b))||C.index>=e.length)break;var T=C.index,A=C.index+C[0].length,L=S;for(L+=E.value.length;T>=L;)L+=(E=E.next).value.length;if(S=L-=E.value.length,E.value instanceof a)continue;for(var R=E;R!==t.tail&&(Ld.reach&&(d.reach=D);var I=E.prev;if(O&&(I=s(t,I,O),S+=O.length),u(t,I,_),E=s(t,I,new a(f,g?r.tokenize(N,g):N,y,N)),P&&s(t,E,P),_>1){var M={cause:f+","+m,reach:D};i(e,t,n,E.prev,S,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function u(e,t,n){for(var r=t.next,a=0;a"+o.content+""},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n0)){var l=f(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s=0&&p(u,"variable-input")}}}}function c(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function u(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,s(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function c(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,c={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return c[n]=a,n})).join(""),n,r),f=Object.keys(c);return i=0,function e(t){for(var n=0;n=f.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=f[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var s=o.substring(0,l),d=u(c[a]),p=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),p){var h=[p];e(h),m.push.apply(m,h)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(//g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r*\.{3}(?:[^{}]|)*\})/.source;function o(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(a);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=i(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=o.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=o[a],d=n.tokenStack[c],f="string"==typeof u?u:u.content,p=t(r,c),m=f.indexOf(p);if(m>-1){++a;var h=f.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=f.substring(m+p.length),v=[];h&&v.push.apply(v,i([h])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof u?l.splice.apply(l,[s,1].concat(v)):u.content=v}}else u.content&&i(u.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const o=a},9901:e=>{e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041a\u0443\u041c\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:(e,t,n)=>{const r=n(9901),a=n(9642),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(6500).resolve(t)],delete Prism.languages[e],n(6500)(t),o.add(e)}))}i.silent=!1,e.exports=i},6726:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6726},6500:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6500},9642:e=>{"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,r=e.length;n "));var l={},s=e[r];if(s){function u(t){if(!(t in e))throw new Error(r+" depends on an unknown component "+t);if(!(t in l))for(var i in a(t,o),l[t]=!0,n[t])l[i]=!0}t(s.require,u),t(s.optional,u),t(s.modify,u)}n[r]=l,o.pop()}}return function(e){var t=n[e];return t||(a(e,r),t=n[e]),t}}function a(e){for(var t in e)return!0;return!1}return function(o,i,l){var s=function(e){var t={};for(var n in e){var r=e[n];for(var a in r)if("meta"!=a){var o=r[a];t[a]="string"==typeof o?{title:o}:o}}return t}(o),u=function(e){var n;return function(r){if(r in e)return r;if(!n)for(var a in n={},e){var o=e[a];t(o&&o.alias,(function(t){if(t in n)throw new Error(t+" cannot be alias for both "+a+" and "+n[t]);if(t in e)throw new Error(t+" cannot be alias of "+a+" because it is a component.");n[t]=a}))}return n[r]||r}}(s);i=i.map(u),l=(l||[]).map(u);var c=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(c[t]=!0,e(t))}))}));for(var f,p=r(s),m=c;a(m);){for(var h in f={},m){var g=s[h];t(g&&g.modify,(function(e){e in d&&(f[e]=!0)}))}for(var b in d)if(!(b in c))for(var v in p(b))if(v in c){f[b]=!0;break}for(var y in m=f)c[y]=!0}var w={getIds:function(){var e=[];return w.load((function(t){e.push(t)})),e},load:function(t,n){return function(t,n,r,a){var o=a?a.series:void 0,i=a?a.parallel:e,l={},s={};function u(e){if(e in l)return l[e];s[e]=!0;var a,c=[];for(var d in t(e))d in n&&c.push(d);if(0===c.length)a=r(e);else{var f=i(c.map((function(e){var t=u(e);return delete s[e],t})));o?a=o(f,(function(){return r(e)})):r(e)}return l[e]=a}for(var c in n)u(c);var d=[];for(var f in s)d.push(l[f]);return i(d)}(p,c,t,n)}};return w}}();e.exports=t},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),o=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n