Part 6: Hello Config - 대본¶
AI 지원 번역 - 자세히 알아보기 및 개선 제안
중요 사항
이 페이지는 대본만 표시합니다. 전체 단계별 지침은 교육 자료로 돌아가십시오.
대본에 표시된 섹션 번호는 참고용으로만 제공되며 자료의 모든 섹션 번호를 포함하지 않을 수 있습니다.
환영합니다¶
안녕하세요, Hello Nextflow 교육 과정의 여섯 번째 파트에 오신 것을 환영합니다.
이번 챕터는 Hello Config이며, 우리 교육 과정의 마지막 파트입니다.
이번 챕터에서는 Nextflow 구성에 대해 이야기할 것입니다. Nextflow 구성은 정말 강력합니다. 동일한 pipeline을 여러 다른 컴퓨팅 인프라에서 다른 소프트웨어 프로비저닝과 pipeline 자체의 다른 옵션으로 실행할 수 있게 해줍니다.
이것은 다른 사람들이 만든 Nextflow pipeline을 가져다가 여러분의 시스템에서 실행할 수 있다는 것을 의미하며, 완전히 다른 인프라를 위해 만들어졌을 수도 있습니다. Nextflow를 구성하는 이 능력은 workflow를 진정으로 이식 가능하고 공유 가능하게 만듭니다.
이번 챕터에서는 이전 파트에서 만든 workflow를 사용할 것이지만, workflow 코드는 전혀 편집하지 않을 것입니다. 단지 Nextflow config 파일을 살펴보고 config를 변경하면 Nextflow가 실행되는 방식이 어떻게 바뀌는지 볼 것입니다.
좋습니다, 시작해 봅시다.
이전과 마찬가지로, training.nextflow.io로 가서 시작해 봅시다. 왼쪽의 Hello Nextflow와 챕터 6으로 이동합니다. Hello config입니다. 이제 제 GitHub code Spaces 환경으로 들어가서 사용할 스크립트를 다시 확인하겠습니다.
0. 워밍업: Docker가 활성화되어 있는지 확인하고 Hello Config workflow 실행하기¶
이것은 Hello Config라고 불리며, 이전에 있던 곳에서 시작합니다. CSV 파일에 대한 greetings, 출력 batch 이름에 대한 batch, 그리고 cowpy 이름에 대한 character라는 세 가지 매개변수가 있는 것과 정확히 같게 보입니다. 서로 다른 프로세스의 네 가지 imports가 있고, 그것들을 함께 체인으로 연결하는 workflow가 있습니다.
실제로 이 챕터에서는 Nextflow 파일을 전혀 건드리지 않을 것이기 때문에, 이제 이 파일을 닫겠습니다. 순전히 구성 파일 내에서 작업할 것입니다. 이전 챕터 5에서 간단히 살펴본 Nextflow dot config 파일을 보면, 여기에 단일 문장이 있습니다: Docker enabled equals true, 이것은 Nextflow에게 이 workflow를 실행할 때 Docker를 사용하라고 지시합니다.
저는 여기 pipeline 루트에 있는 Nextflow dot config를 사용하고 있으며, Nextflow를 실행할 때 자동으로 로드됩니다. 하지만 기억하세요, Nextflow는 여러 위치에서 config 파일을 로드할 수 있습니다.
Nextflow docs에서 확인하고 Configuration으로 이동하면, 이러한 위치 목록과 로드되는 우선순위를 볼 수 있습니다.
좋습니다. workflow가 예상대로 실행되는지 확인해 봅시다. 터미널을 열고 Nextflow를 입력합니다. Run. Hello, config. 그리고 엔터를 누릅니다. 네 개의 프로세스가 실행되어 cowpy 명령으로 끝나야 합니다. 확실히, 이것은 제대로 작동했습니다. Docker를 활성화했고, Docker를 가져와서 cowpy를 실행했으며, 챕터 5 끝에서 했던 것과 같습니다.
1. 사용할 소프트웨어 패키징 기술 결정하기¶
좋습니다. HPC에서 실행 중이고 Docker가 설치되어 있지 않다고 가정해 봅시다. 이 시나리오에서 가장 좋은 방법은 Singularity 또는 Apptainer를 사용하는 것입니다. 그렇게 하려면, module cowpy로 이동하여 이전 챕터에서 보여드린 것처럼 oras://로 시작하는 singularity 이미지를 사용하도록 이 container를 변경할 것입니다. 이것도 Seqera Containers에서 얻을 수 있습니다.
그런 다음 Nextflow dot config로 이동하여 Docker enabled를 false로 설정하고 singularity enabled equals true를 수행합니다. 또는 Apptainer를 사용하는 경우 apptainer enabled equals true를 수행하면 작동할 것입니다.
Nextflow는 컨테이너 외에도 다른 기술도 지원합니다. 익숙할 수 있는 것은 conda입니다. 여기서 conda enabled equals true를 수행하고 Docker를 false로 설정할 수 있습니다. conda는 동일한 container 지시문을 사용하지 않습니다. 대신, conda라는 새 지시문을 여기에 추가할 수 있습니다. 그런 다음 사용하려는 conda 패키지를 지정합니다. pipeline을 가능한 한 재현 가능하게 만들기 위해 가능한 한 구체적으로 지정하는 것이 좋습니다. 그래서 conda 채널인 conda-forge를 지정하고, 그 다음 cowpy와 정확한 버전인 1.1.5를 지정하겠습니다.
원한다면 cowpy만 쓸 수도 있지만, 그것은 pipeline의 다른 실행에서 cowpy의 다른 버전으로 해석될 수 있습니다.
좋은 점은 docker 지시문을 전혀 건드리지 않았다는 것입니다. 이 Docker 이미지는 여전히 존재합니다. 지금은 두 가지 대안을 제공하고 있으며, config 파일만으로 켜고 끌 수 있습니다.
1.3. workflow를 실행하여 Conda를 사용할 수 있는지 확인하기¶
Conda가 이제 활성화되었으니, 시험해 봅시다.
좋습니다. 실행 중이고 여기에 Nextflow의 메시지가 있습니다. Nextflow가 저를 위해 conda 환경을 생성하고 있으며, 이 캐시 위치를 사용하고 있다는 것을 볼 수 있습니다.
백그라운드에서 Nextflow는 저를 위해 "conda create" 명령을 실행하여 원하는 패키지만 있는 새로운 격리된 conda 환경을 만들고, 그런 다음 프로세스를 실행할 수 있도록 해당 conda 패키지를 설치하고 가져옵니다.
환경을 만들고 처음으로 소프트웨어를 설치하고 있었기 때문에 약간의 시간이 걸렸습니다. 하지만 이 환경을 캐시했으므로, 동일한 Nextflow 명령을 다시 실행하면 동일한 conda 환경을 재사용하기 때문에 훨씬 빠를 것입니다.
이것의 멋진 점 중 하나는 이러한 지시문을 전체 workflow가 아닌 프로세스 수준에서 지정할 수 있다는 것입니다. 따라서 원한다면 서로 다른 프로세스에 사용되는 기술을 혼합하고 일치시킬 수 있습니다.
2. process 지시문으로 컴퓨팅 리소스 할당하기¶
Nextflow 구성 파일은 소프트웨어 패키징보다 훨씬 더 많은 작업을 수행할 수 있습니다. Nextflow에게 pipeline의 단계를 실제로 어떻게 실행할지도 알려줄 수 있습니다. 한 예는 호스트 시스템에 각 실행 작업에 어떤 리소스를 사용할 수 있어야 하는지 알려주는 것입니다.
기본적으로 Nextflow는 많이 제공하지 않습니다. 각 프로세스에 단일 CPU와 2기가바이트의 메모리만 제공합니다.
이것은 아마도 우리가 변경하고 싶은 것일 것입니다. 실행하는 데 오랜 시간이 걸리는 프로세스가 더 많은 리소스를 가지고 더 빠르게 실행될 수 있도록 하기 위해서입니다. 하지만 프로세스에 무엇을 할당해야 할지 알기 어려울 수 있습니다. Nextflow는 이것을 도와주는 멋진 트릭을 가지고 있습니다.
2.1. workflow를 실행하여 리소스 사용 보고서 생성하기¶
workflow를 다시 실행해 봅시다. 이번에는 추가 인수를 추가하겠습니다. dash with reports입니다. 이것은 핵심 Nextflow 옵션이므로 단일 하이픈입니다. 그런 다음 제가 원하는 파일 이름을 입력합니다. 이 경우 report config one html이라고 부르겠습니다.
workflow를 다시 실행하겠습니다. 이전과 정확히 같이 실행될 것이지만, 사이드바에 나타난 것처럼 추가 도우미 보고서를 제공할 것입니다.
이 파일을 마우스 오른쪽 버튼으로 클릭하고 다운로드를 클릭하면 GitHub code Spaces에서 로컬 시스템으로 다운로드되어 웹 브라우저에서 쉽게 볼 수 있습니다.
이 보고서는 모든 Nextflow 실행에 대해 생성될 수 있으며, 많은 정보가 들어 있습니다. 맨 위에는 어떤 명령이 사용되었는지, workflow가 언제 실행되었는지, 얼마나 걸렸는지에 대한 메타데이터로 시작하지만, 아래로 스크롤하면 pipeline의 모든 단계에서 사용된 리소스에 대한 더 자세한 정보를 얻습니다.
각 프로세스는 서로 다른 작업에 대해 여러 번 실행되기 때문에 각 프로세스에 사용한 리소스의 변동을 보여주는 상자 그림이 있습니다.
조금 더 아래로 스크롤하면 사용된 메모리와 작업 기간에 대한 유사한 정보가 표시됩니다. 또한 디스크 읽기 쓰기도 표시됩니다.
오래 실행되는 작업이 있는 큰 pipeline의 경우, 이것이 요청하는 리소스의 구성을 미세 조정하는 방법에 대해 매우 유익할 수 있으며, 과도하게 요청하지 않지만 빠르게 실행될 수 있도록 충분히 제공할 수 있습니다.
보고서를 계속 아래로 스크롤하면 workflow에서 실행된 모든 단일 작업에 대한 자세한 정보를 보여주는 작업 테이블도 볼 수 있습니다. 여기에는 실행된 해석된 스크립트와 같은 정보가 포함됩니다.
좋습니다, config 파일로 돌아가 봅시다. workflow에 실제로 많이 필요하지 않다는 것을 보았으므로, Nextflow에게 workflow의 모든 프로세스에 1기가바이트의 메모리만 필요하다고 알려줍시다.
이제 이와 같이 프로세스 수준에서 정의하면, 이것은 pipeline의 모든 단일 프로세스에 적용됩니다.
2.3. 개별 프로세스에 리소스 할당 설정하기¶
논의를 위해, cowpy가 실제로 많은 무거운 작업을 하고 있고 다른 작업보다 더 많은 리소스가 필요하다고 가정해 봅시다. 여기서 with name cowpy를 사용하여 해당 프로세스에만 적용되는 추가 config 블록을 정의할 수 있습니다.
이것을 config selector라고 하며, 여기서 서로 다른 프로세스와 일치하는 다른 패턴을 정의할 수 있습니다. 예를 들어, cow star를 할 수 있습니다. 그런 다음 중괄호를 붙이고 1기가바이트 대신 2기가바이트의 메모리를 제공하고 2개의 CPU를 제공해 봅시다.
이제 Nextflow는 workflow의 모든 프로세스에 1기가바이트를 제공할 것이며, 더 구체적인 이 요청은 제외됩니다. 따라서 이것을 재정의합니다. 그리고 cowpy라고 불리는 프로세스에만 2기가바이트의 메모리와 2개의 CPU가 제공됩니다.
Nextflow는 리소스 활용에 대해 영리하다는 점에 유의하십시오. 따라서 이 숫자를 더 높은 값으로 설정하기 시작하면, Nextflow가 모두 병렬로 실행하는 대신 작업 제출을 하나씩 대기열에 넣기 시작하여 사용 가능한 리소스를 과도하게 요청하지 않는 것을 볼 수 있습니다.
2.4. 수정된 구성으로 workflow 실행하기¶
workflow를 다시 실행해 보고 이번에는 새 보고서를 저장합시다.
좋습니다, 이 파일을 다운로드하여 살펴볼 수 있습니다.
네, 예상대로 이것은 기본적으로 정확히 같아 보입니다. 왜냐하면 이것은 실제로 아무것도 하지 않는 더미 workflow이기 때문입니다. 하지만 이러한 반복적인 접근 방식으로 제한을 정의하고 이런 종류의 보고를 통해 실제 workflow를 수행하면 적절한 구성을 설정하는 증거 기반 접근 방식을 허용하고 사용 가능한 계산 리소스를 최대한 활용할 수 있다고 상상할 수 있습니다.
이것에 대해 정말 영리해질 수 있습니다. Nextflow에는 실패를 재시도하는 내장 기능이 있으며, 이와 같은 closure를 사용하여 config 파일에서 이를 활용하고 사용 가능한 리소스를 동적으로 설정할 수 있습니다. 여기서 저는 Nextflow에게 해당 2기가바이트를 재시도 횟수로 곱하라고 지시했습니다. 따라서 두 번째 재시도는 4기가바이트를 받고, 세 번째 재시도는 6기가바이트를 받는 식입니다. 이것은 이 교육 과정의 범위를 약간 벗어나지만, 관심이 있다면 동적 재시도 로직에 대한 좋은 섹션이 있는 Nextflow docs를 확인하십시오.
2.5. 리소스 제한 추가하기¶
이제 이것에 대해 알아차릴 수 있는 한 가지는 이런 종류의 것이 실수로 시스템에서 사용 가능한 리소스를 넘어서는 것을 매우 쉽게 만들 수 있다는 것입니다. 사용 가능한 것보다 더 많은 리소스를 요청하면 Nextflow는 구성에 대한 오류를 발생시키고 실행을 중단합니다. 이를 방지하기 위해 리소스 제한이라는 것을 사용할 수 있습니다.
workflow의 프로세스 scope 아래에서 배열을 취하는 이와 같은 리소스 제한을 정의할 수 있으며, 이 시스템에서 사용 가능한 최대 메모리 CPU 및 시간을 지정할 수 있습니다.
여기에 높은 값을 설정해도 요청되는 리소스의 양이 증가하지 않습니다. 여전히 요청에서 1기가바이트를 사용할 것이지만, 이러한 요청 중 하나라도 750에 도달하면 해당 상한선에 도달하여 그 이상은 요청되지 않으므로 Nextflow가 계속 실행되고 사용할 수 없는 리소스로 인해 충돌하지 않습니다.
따라서 이것은 특히 리소스 할당과 함께 동적 로직을 사용하는 경우 사용하는 좋은 안전장치입니다.
이것이 정말 유용한 다른 상황은 공개되어 있고 여러분이 제어하지 않는 pipeline을 사용하는 경우입니다. 구성 기본값이 함께 제공될 수 있으며, Nextflow는 시스템에서 실행되도록 모든 리소스 요청을 임계값으로 설정하는 올바른 접근 방식을 자동으로 취합니다.
좋습니다, 훌륭합니다. 소프트웨어에 대해 이야기했습니다. 리소스 할당에 대해 이야기했고, 모든 프로세스와 특정 프로세스 모두에 대한 서로 다른 config scope를 설명했습니다.
3. 매개변수 파일을 사용하여 workflow 매개변수 저장하기¶
좋습니다, 다음으로 매개변수에 관심을 돌릴 것입니다. Nextflow 스크립트에서 이전에 했던 것처럼 config 파일에서 매개변수를 정의할 수 있습니다. 따라서 params dot greeting equals hello 또는 params scope를 사용하고 foo equals bar를 설정합니다.
그리고 그것은 workflow의 기본값을 설정하는 데 좋습니다. 그러나 pipeline을 실행할 때 JSON 또는 YAML 파일에 매개변수를 지정하는 것이 좋을 수 있습니다.
이와 같은 파일을 사용하는 것이 dash dash로 명령줄 옵션을 지정하는 것보다 훨씬 낫습니다. workflow를 실행할 때 많은 매개변수를 지정해야 할 수 있으며 단일 CLI에 모두 작성하는 것은 지루하고 오류가 발생하기 쉽습니다. 또한 사용한 모든 매개변수를 기억할 가능성이 낮으므로, 파일에 코딩하면 미래에 동일한 매개변수를 사용하여 workflow를 다시 시작하기가 더 쉽습니다.
여기에 test params라는 예제 파일이 있으며, 이것은 세 가지 다른 값으로 workflow에 있는 세 가지 매개변수를 지정합니다. 개인적으로 저는 JSON보다 YAML을 작성하기가 더 쉽다고 생각합니다. 따라서 작동한다는 것을 보여주기 위해 Test yaml이라는 새 파일을 만들고 이것들을 복사하여 따옴표를 제거하고 저장하겠습니다.
이러한 JSON 및 YAML 파일은 더 익숙한 구문이기 때문에 작성하기가 더 쉬울 수 있습니다. 하지만 이것들은 매개변수에만 해당되며 이와 같은 키 값 구문만 사용한다는 점에 유의하십시오.
3.1. 매개변수 파일을 사용하여 workflow 실행하기¶
시험해 봅시다. 이전과 동일한 명령을 수행합니다. 보고서를 제거하고 dash params file test params yaml을 수행하겠습니다.
아니요, 이것은 핵심 Nextflow 옵션이므로 단일 하이픈입니다.
좋습니다. workflow를 실행했고 명령줄에서 모두 지정하는 대신 해당 YAML 파일의 매개변수를 사용했습니다. 이 간단한 예제에는 과도해 보일 수 있지만, 10개 또는 20개의 서로 다른 매개변수가 있다면 수동으로 입력하는 것이 고통스러울 수 있으며, 코드 편집기에서 편집하고 재현성을 위해 보관하는 것이 훨씬 쉽다고 상상할 수 있습니다.
3. 작업을 수행하는 데 사용해야 하는 executor 결정하기¶
좋습니다. Docker와 conda를 사용한 소프트웨어 패키징에 대해 이야기했습니다. CPU와 메모리를 사용한 프로세스 리소스 요구 사항에 대해 이야기했습니다. 그리고 workflow를 실행할 때 매개변수를 지정하는 방법에 대해 조금 이야기했습니다.
구성의 마지막 부분은 실제로 실행, 기본 컴퓨팅 인프라 자체이며, 이것이 Nextflow의 진정한 보석입니다: 동일한 workflow를 여러 다른 컴퓨팅 인프라에서 실행할 수 있습니다.
실제로 잠시 서면 교육 자료로 전환하겠습니다. 교육의 이 부분에서 서로 다른 executor, 이 경우 HPC 스케줄러가 작업을 제출하는 데 필요한 리소스 요구 사항을 정의하는 방법에 대한 몇 가지 다른 예를 볼 수 있습니다.
Slurm의 경우 dash dash mem과 CPU 번호를 정의하는 이러한 SBATCH 헤더가 있습니다. PBS를 사용하는 경우 다른 헤더가 있고, Grid Engine을 사용하는 경우 다시 다른 헤더가 있습니다.
클라우드에서 실행하려는 경우, AWS batch, Google Cloud, Azure 등 더 다를 것이라고 상상할 수 있습니다.
이러한 기본 컴퓨팅 인프라 각각을 executor라고 하며, Nextflow는 올바른 구문으로 작업을 제출하기 위해 이러한 모든 다른 executor와 통신하는 방법을 알고 있습니다.
좋은 소식은 이것에 대해 알 필요가 없다는 것입니다. 해야 할 일은 Nextflow에게 어떤 executor를 사용할지 알려주기만 하면 됩니다.
3.1. 다른 백엔드 타겟팅하기¶
config 파일로 돌아가서 프로세스에서 executor를 수행하고 local을 입력하겠습니다.
Local은 실제로 기본값입니다. 다른 executor를 지정하지 않으면 local이 사용되며, 이것은 단지 Nextflow를 시작한 호스트 시스템을 의미합니다.
대신 Slurm을 지정할 수 있습니다. 그러면 Slurm 작업이 제출되거나 AWS batch라고 할 수 있으며, 그러면 AWS batch에 작업이 제출됩니다.
일부 경우에는 추가 구성이 필요합니다. 예를 들어 클라우드에서 실행하려면 특정 자격 증명이 필요하지만 실제로 이것이 핵심이며, 완전히 다른 컴퓨팅 환경에서 workflow를 실행하기 위해 한두 줄의 config만큼 간단할 수 있습니다.
code spaces 내의 간단한 시스템에서 실행하고 있지만, 여전히 이것을 가지고 놀면서 Slurm에서 실행하는 척할 수 있습니다. 그런 다음 workflow를 다시 시작하면 Nextflow run, hello config를 수행합니다. Slurm에 작업을 제출할 수 없기 때문에 실패할 것입니다. 하지만 여전히 작업 디렉토리로 들어가서 Nextflow가 무엇을 했는지 볼 수 있습니다. 따라서 이 작업 디렉토리로 이동하여 Command Run을 보면 이 파일의 맨 위에 이제 Slurm 작업에 필요한 리소스를 지정하려고 시도한 이러한 sbatch 헤더 줄이 있습니다.
4. 프로필을 사용하여 사전 설정 구성 선택하기¶
좋습니다, 거의 다 왔습니다. 이 챕터의 마지막 부분은 구성 프로필에 대해 이야기하는 것입니다. 여러 다른 시스템에서 pipeline을 실행하는 경우 매번 지정해야 하는 이러한 모든 다른 Nextflow config 파일을 갖는 것이 짜증날 수 있습니다.
대신 Nextflow config 파일 내에 구성 그룹화를 인코딩하고 프로필 플래그를 사용하여 해당 그룹을 켜고 끌 수 있습니다. 어떻게 보이는지 봅시다.
4.1. 로컬 개발과 HPC 실행 간 전환을 위한 프로필 생성하기¶
여기 예제에서 두 개의 프로필을 만들 것입니다. 하나는 제 노트북용이고 다른 하나는 더 무거운 HPC 시스템용입니다. 조금 속임수를 쓰고 교육 자료에서 코드를 복사하여 여기에 넣겠습니다.
profiles라는 새로운 scope가 있고, 각 프로필의 이름이 있으며 무엇이든 될 수 있습니다. 그리고 그 안에는 우리가 이미 작성한 최상위 config와 정확히 같아 보이는 구성이 있습니다. 따라서 다시 프로세스 scope가 있습니다. Docker scope가 있습니다.
my laptop이라고 불리는 프로필에서 로컬 executor를 사용하여 실행하라고 말하고 있습니다. 따라서 내 호스트 시스템에서 Docker를 사용합니다.
여기 university HPC 프로필에서는 Slurm을 사용하여 작업을 제출하고 Docker 대신 conda를 사용하며, 사용 중인 HPC의 노드 시스템 크기와 일치할 수 있는 서로 다른 리소스 제한을 지정하고 있습니다.
기본적으로 Nextflow를 실행할 때 이 구성 중 아무것도 사용되지 않습니다. 이러한 프로필 중 하나를 사용하고 싶다고 지정해야 합니다.
4.2. 프로필로 workflow 실행하기¶
nextflow run hello config를 수행해 봅시다. 그리고 dash profile을 수행하겠습니다. 핵심 Nextflow 옵션이기 때문에 단일 하이픈입니다. 그런 다음 제가 지정한 이름인 my laptop입니다. Nextflow는 이제 해당 구성 프로필 내에서 지정된 config 블록을 사용하고 Nextflow를 실행할 때 적용해야 합니다. 다른 config 블록을 사용하고 싶다면 해당 프로필 이름을 전환하기만 하면 됩니다. 훨씬 기억하기 쉽습니다. 훨씬 사용하기 쉽습니다.
4.3. 테스트 프로필 생성하기¶
참고로, 프로필은 모든 종류의 구성을 가질 수 있으므로 실행 환경과 관련이 있을 필요가 없습니다. 예를 들어, 일련의 매개변수가 있는 새 프로필을 여기에 만들어 봅시다. 이것을 tux로 변경하고 my profile로 변경할 수 있으며, 이제 profile test를 수행하면 workflow의 최상위 수준에서 지정된 매개변수를 덮어쓸 이러한 매개변수를 지정할 것입니다.
Nextflow를 실행할 때 여러 프로필을 체인으로 연결할 수 있으며 순서대로 적용됩니다.
4.4. 테스트 프로필로 로컬에서 workflow 실행하기¶
따라서 이전 명령을 가져와서 comma test를 수행할 수 있습니다. 그러면 my laptop config가 먼저 적용된 다음 test config가 적용됩니다. 중복되는 부분이 있으면 오른쪽의 프로필이 이전 프로필의 모든 구성을 덮어씁니다. 엔터를 누르면 무슨 일이 일어나는지 봅시다.
좋습니다, 여기에 새 results 파일이 있습니다. 옵션 중 하나로 지정한 My Profile을 볼 수 있습니다. 그리고 cowpy, my profile도 볼 수 있으며, 확실히 tux가 있습니다. 따라서 작동했습니다.
마무리¶
좋습니다! 놀랍습니다. 끝났습니다. 과정을 끝까지 마쳤습니다. 작은 축하 색종이 조각을 받으십시오. 이 챕터를 마친 것을 축하합니다.