프로그래밍은, 검증 과정마다 자동화되었다
프로그래밍에서는 만드는 과정의 자동화가 한꺼번에 진행되었습니다.
AI가 코드를 작성하고, 그것을 검증하는 과정도 기계가 맡게 되었습니다.
- 린터(Linter): 코드가 정해진 규칙에 따라 작성되었는지 확인 -
- 유닛 테스트(Unit Test): 코드를 변경할 때마다 예상대로 작동하는지 확인 -
- AI를 통한 리뷰: 변경의 의도와 내용이 일치하는지 읽기
이 세 가지가 변경될 때마다 자동으로 돌아가기 때문에, 사람이 한 줄씩 검증하지 않아도 배포 가능한 코드가 매우 빠르게 만들어질 수 있게 되었습니다.
프로그래밍 작업의 90% 이상은 이미 자동화할 수 있습니다.
Anthropic은 자사 블로그에서 사내 코드의 대부분을 AI가 작성하게 된 것을 언급했습니다.
Uber를 비롯한 선진 기업이나, AI를 능숙하게 사용하는 스타트업에서도 이것이 일반적인 근무 방식이 되어가고 있습니다.
문서 작업은 아직 그 단계에 도달하지 못했다
반면, 문서를 중심으로 일하는 사람들 — 계약서 작성, 보고서 정리, 규정 수정, 회의록 기록 등 — 의 업무는 아직 그 단계에 이르지 못했습니다.
법무, 회계, 행정 등 분야별로 도구나 스타트업이 나오고 있지만, 어디도 아직 탐색 단계입니다.
그 이유 중 하나는 문서가 일정한 형태를 갖추고 있지 않다는 것입니다.
코드는 컴파일러가 읽을 수 있는 형태로 작성되므로, 기계로 검증하는 시스템을 만들기 쉽습니다. 반면 문서는 사람이 읽기 위해 쓰여졌으며, 작성 방식도 분야별로 다릅니다. 그래서 자동화하기 어렵습니다.
하지만 프로그래밍이 빨라진 것은 AI가 작성할 수 있게 되었기 때문만은 아닙니다.
작성된 것을 기계가 검증하는 시스템이 먼저 있었기 때문에, AI에게 맡겨도 괜찮아지게 된 것입니다.
검증 시스템이 없었다면, AI가 빠르게 작성한 만큼 사람이 읽고 검증하는 작업이 늘어납니다.
문서 작업을 똑같이 빠르게 하려면, 문서를 위한 린터와 테스트 및 리뷰가 필요합니다.
chaff란 무엇인가?
chaff (npm에서는 chaffjs)
은 우리가 만드는, 문서를 기계로 검증하는 도구입니다.
프로그래밍의 린터와 유닛 테스트를 일반적인 문서에 맞게 재설계한 것입니다.
계약서, 보고서, 사내 규정, 매뉴얼, 회의록, 블로그 등 일본어와 영어 문서를 그대로 읽습니다.
문서를 기계로 검증하는 도구는 이전에도 많이 있었습니다(후술할 '관련 도구와 chaff의 위치' 섹션에서 비교합니다).
chaff가 목표로 하는 것은, 이들이 개별적으로 가지고 있던 기능들을 AI와 함께 사용한다는 전제하에 하나로 통합하는 것입니다.
- 매번 같은 결과를 반환한다. 판정에 AI를 사용하지 않기 때문에, 동일한 문서를 여러 번 실행해도 항상 같은 결과가 나옵니다. AI가 다시 작성할 때마다 이전 내용과 비교할 수 있습니다. -
- 왜, 어떻게 수정해야 하는지까지 반환한다. 지적 사항마다 왜 읽기 어려운지와 어떤 방향으로 수정해야 하는지를 알려줍니다.
npx chaffjs fix-plan
은 이를 규칙별로 정리한 '수정 계획'을 JSON 형태로도 출력하므로, 그대로 AI에게 전달하여 다시 작성하게 할 수 있습니다. -
- 재작성으로 누락된 것을 찾아낸다.
npx chaffjs compare 이전.md 이후.md는 AI의 재작성 과정에서 숫자, 날짜, URL, 이름 등이 누락되거나 추가되지 않았는지 확인합니다. -
- 보지 않은 것을 숨기지 않는다. '지적 사항 없음'을 '모두 검토하여 문제없음'으로 오해하지 않도록, 이번에 작동하지 않은 규칙들을 이유와 함께 목록화합니다. -
- 의미 판단이 필요할 때만 AI에게 맡긴다. 의미를 읽어야 결정할 수 있는 검사는
chaff test로 분리되어 있으며, 무엇을 보낼지 미리 보여준 후 판단이 필요한 부분만 전송합니다. -
- CI에 통합 가능하다. 종료 코드를 반환하고 지적 사항을 SARIF 형식으로도 출력할 수 있어, 프로그램과 마찬가지로 변경될 때마다 실행할 수 있습니다.
chaff는 문서를 재작성하지 않습니다. 수정하는 것은 작성자 또는 그 작성자가 의뢰한 AI입니다.
검증의 예시를 들자면 다음과 같습니다.
| 종류 | 예시 |
|---|
| 가독성 | 한 문장이 너무 길지 않은지, 같은 단어를 두 가지 방식으로 쓰지 않았는지 |
| ... | |
왜 AI가 아니라 기계로 검증하는가
AI가 작성한 문서에는 AI 특유의 오류가 섞여 있습니다.
수정했는데 숫자가 하나 빠졌거나, 같은 것을 중간부터 다른 호칭으로 쓰고 있거나, 인용인 줄 알았는데 원문에 없는 표현이 되어 있는 등의 실수입니다.
이러한 실수를 또 다른 AI에게 읽게 하여 검증하는 것도 가능합니다.
하지만 AI가 AI의 글을 검증하는 것에는 약점이 있습니다.
LLM을 평가자로 사용하는 연구에서는, 평가하는 LLM이 자신에게 익숙한 문장을 높게 평가하는 경향이 있다고 보고되었습니다 (Wataoka 외, 2024).
같은 편견을 공유한 채로 '문제없다'고 말하기 쉽고, 같은 문서라도 답이 매번 조금씩 달라질 수 있습니다.
반면, 이러한 오류의 상당수는 의미를 읽지 않아도 기계로 검증할 수 있습니다.
숫자가 수정 전후에 일치하는지, 용어가 통일성 있게 작성되었는지, 제4조 다음에 제5조가 오는지를 말입니다.
이러한 것들은 정해진 절차로 판정할 수 있으며, 판정하면 매번 같은 답이 나옵니다.
그래서 기계로 검증 가능한 것은 기계에 맡기고, 의미를 읽지 않으면 알 수 있는 것만 사람이나 AI에게 남기는 방식으로 했습니다.
chaff는 그 '기계의 절반'입니다. 프로그래밍에서 린터(linter)와 테스트가 AI가 작성한 코드를 지탱하듯이, AI가 작성한 문서를 기계로 지탱하기 위한 도구입니다.
관련 도구들과 chaff의 위치
문서를 기계로 검증하는 도구가 chaff가 처음은 아닙니다. 오히려 chaff의 많은 생각들은 앞선 도구들로부터 차용하고 있습니다.
크게 여섯 가지 계통으로 나누어 살펴보겠습니다.
1. 문서 린터 (오픈 소스)
- textlint는 Node.js에서 작동하는 문서 린터입니다. 규칙을 추가하여 사용하는 구조이며, 일본어용 규칙 세트(textlint-ja의
preset-ja-technical-writing 등)가 널리 사용됩니다. - RedPen 역시 일본어를 포함한 기술 문서를 위한 교정 도구입니다.
- Vale은 스타일 가이드를 YAML 규칙으로 작성하여 Markdown 등의 문서에 적용하는 영어 중심의 린터입니다. 종료 코드와 JSON을 반환하기 때문에 CI/CD(지속적 통합)에 포함될 수 있으며, 문서 팀에서 '스타일 가이드를 코드로 소유'하는 방식이 정착되었습니다 (Datadog 사례).
- proselint, write-good, alex는 영어의 문체나 단어 선택에 초점을 맞춘 작은 린터들입니다.
- LanguageTool은 품사 배열로 오류 패턴을 작성하는 규칙형 문법 검사기로, 많은 언어를 지원합니다.
chaff의 '규칙은 YAML로 작성되는 데이터', '팀의 규정을 설정 파일에 작성', 'CI/CD에 포함'하는 방식은 이러한 도구들, 특히 Vale와 textlint가 먼저 보여준 방법입니다.
2. 일본어 교정 서비스
분켄(文賢), 아사히 신문사의 Typoless, Shodo 등이 있습니다.
오탈자나 표기 오류, 단어 사용법을 사전이나 AI로 찾아주는 서비스입니다.
Typoless는 신문사의 용어 지침을 기반으로 한 교정 규칙을 가지고 있는 등, 언어 자체의 정확성에 대해서는 chaff가 갖지 못한 깊은 지식이 있습니다.
3. 법률 문서 교정 (Word 애드인)
영어 계약서에서는 PerfectIt이나 Litera의 Contract Companion이 정의어 사용의 일관성, 상호 참조, 번호 누락 등을 검증합니다.
'정의어를 정의대로 사용하고 있는지', '제4조 다음에 제6조가 오지 않았는지'와 같이 문서의 구조를 기계로 검증하는 생각은 chaff보다 이 분야에 더 오래전부터 있었습니다.
4. AI 기반 계약서 리뷰
LegalOn(구 LegalForce), Spellbook, Harvey 등은 AI가 계약서를 읽고 위험한 조항이나 누락된 조항을 지적하고 수정안까지 제시합니다.
의미를 읽지 않으면 알 수 있는 것('이 조항이 회사에 불리한가')을 다루는 도구이며, chaff가 다루지 않는 영역입니다.
5. 기업 문서 거버넌스
Acrolinx는 기업의 스타일 가이드를 디지털화하여 사람이 작성한 문서와 생성 AI가 작성한 문서 모두에 동일한 기준을 적용하는 서비스입니다.
'AI가 작성한 문서를 팀의 기준으로 검증한다'는 문제의식은 chaff와 같습니다.
6. LLM 출력 평가
promptfoo 같은 평가 도구는 LLM의 출력을, 정해진 절차로 판정하는 검사(문자열이나 형식 일치)와 LLM에게 판정시키는 검사를 결합하여 확인합니다.
정해진 절차의 검사는 빠르고 매번 결과가 같다는 정리 역시 chaff의 생각과 같습니다.
chaff는 무엇이 다른가
각 기능들은 하나하나 어느 곳에 선례가 있습니다.
chaff가 다른 점은 조합(combination)과, 정밀도를 측정하는 방식입니다.
| 관점 | 기존 도구 | chaff |
|---|
| 판단 방식 | AI 서비스는 매번 결과가 흔들릴 수 있음. OSS 린터는 매번 동일함 | 매번 동일함. 의미의 판단은 chaff test로 나누고, 보내기 전에 무엇을 보낼지 보여줌 |
| ... | | |
| 반대로 chaff가 가지고 있지 않은 것도 있습니다. | | |
Word 안에서 직접 사용하는 메커니즘은 없습니다. Typoless 같은 거대한 용어 사정도 없습니다.
조항이 불리한지 여부와 같은, 의미를 읽는 판단도 하지 않습니다. 그 부분은 위 도구나 사람의 몫입니다.
가장 큰 차이는 마지막 줄이라고 생각합니다.
문서 도구가 빠지는 것은 피할 수 없습니다. 중요한 것은 어디에서 빠졌는지 측정할 수 있고, 고친 것이 돌아가지 않는 것입니다.
그것이 이 기사 후반부에서 chaff-corpus에 협력을 요청하는 이유입니다.
어떻게 사용하나요?
Node.js 24 이상만 있으면 설치도 설정 파일도 필요 없습니다.
예를 들어, 다음 article.md에 실행하면,
# 캐시 사용하기
## 캐시 메커니즘
캐시 메커니즘에 대해 설명합니다. 한 번 읽은 데이터를 손에 두고, 두 번째부터는 거기서 반환합니다.
화면에는 이렇게 나옵니다 (출력의 전반부입니다).
article.md blog/tech · 일본어 장르는 기본값
─── 5행 ───────────────────────────────────────────────────
캐시 메커니즘에 대해 설명합니다.
...
지적된 문장, 무슨 일이 일어나고 있는지, 왜 읽기 어려운지, 어떻게 고칠지(→ 행)가 나열됩니다.
마지막 줄은 이 지적이 팀의 방침과 맞지 않을 때, 규칙을 완화하는 명령어입니다.
문서의 종류(장르)를 지정하면, 그 종류에 맞는 방식으로 검사합니다.
계약서와 회의록과 블로그는 좋은 작성 방식이 다르기 때문입니다.
npx chaffjs --genre legal/contract 계약서.md 계약서로 보기
npx chaffjs genres 장르 목록
npx chaffjs init 설정 파일 chaff.yaml 만들기
설치하지 않고 시도하려면, 플레이그라운드에 문서를 붙여넣기만 하면 작동합니다.
이 기사에서 전하고 싶은 것
여기부터는 두 가지를 작성합니다.
자신들의 규칙을 chaff에 적고, 자신의 문서가 좋아지는 것을 체감하는 사용법 - chaff가 빠졌을 때,
그 문서를 chaff-corpus에 풀 리퀘스트(PR)로 보내는 방법과,
왜 그것을 요청하는지
문서 검사 도구는, 사용하기 시작할 때는 효과가 좋지만, 시간이 지나면 빠진 것이 눈에 띄기 시작합니다.
올바른 작성 방식인데 지적된다. 찾아줬으면 하는 오류를 무시한다. 어느새 지적을 읽지 않게 되고, 이윽고 빠집니다.
chaff는 사용하는 사람으로부터 도착하는 '빠진 실제 사례'로 고쳐나갈 전제하에 만들어졌습니다. 두 번째가 이 기사의 본론입니다.
자신들의 규칙을 쓰면 효과를 볼 수 있다
기본 규칙만으로도 작동하지만, chaff가 가장 효과적인 것은 팀의 규칙을 적었을 때입니다.
'서버'와 '서버' 중 어느 쪽에 기할지, 미정인 상태로 내보내면 안 되는 작성 방식은 무엇인지 — 같은 규칙은 팀마다 다르기 때문에,
chaff는 기본적으로 아무 말도 하지 않습니다. 리포지토리 맨 위에 두는 chaff.yaml에 적습니다.
# chaff.yaml
genre: business/report # 보고서로 보기
prefer: # 왼쪽을 찾으면 오른쪽을 권장함
...
이 설정으로 다음 보고서에 적용합니다.
# 3분기 진행 보고
## 개요
이번 분기는 서버 이전을 진행했습니다. 이전 완료일은 TBD입니다.
출력의 일부입니다 (chaffjs 0.36.0).
보고.md business/report · 일본어 장르는 chaff.yaml에서
─── 5행 ───────────────────────────────────────────────────
이번 분기는 서버 이전을 진행했습니다.
...
장르를 business/report로 했기 때문에, 지적 전에 '보고서 가이드라인'도 나옵니다.
머리말에서 결론을 제시했는지, 다음 행동을 담당과 기한까지 적었는지와 같은 질문 목록입니다.
지적을 수정하여 다시 적용하면 해당 지적은 사라집니다. 스스로 결정한 것이 매번 똑같이 지켜지는 것입니다.
이것이 chaff를 사용하면서 처음 느끼는 체감이 아닐까 생각합니다.
지적에 납득할 수 없을 때의 대응 방식은 세 가지가 있습니다.
| 경우 | 대응 방식 |
|---|
| 지적이 가장 옳을 때 | 문장 수정 |
| ... | npx chaffjs relax rule-id --why "이유"를 사용하여 규칙 자체를 완화 |
여기까지는 자신의 손에서 해결할 수 있는 이야기입니다.
그럼에도 불구하고 chaff가 틀릴 때
곤란한 것은 네 번째 경우입니다. 지적 자체가 잘못되었거나 (오탐지, false positive), 혹은 나와야 할 지적이 나오지 않을 때 (누락, missed) 입니다.
relax나 stet을 사용해 무시할 수는 있지만, 그렇게 해서는 chaff가 수정되지 않습니다.
똑같은 방식으로 작성된 다른 문서에서도 동일한 오류 패턴이 계속 나타납니다.
chaff는 정해진 절차로 판정하는 기계이기 때문에, 오류 패턴에는 반드시 형태가 있습니다.
"제목을 문장으로 읽었다", "정의어가 별지에 정의되어 있다는 것을 보지 못했다", "글머리 기호의 각 행을 하나의 연속된 문장으로 읽었다" 등 —
하나의 오류를 수정하면, 같은 형태를 가진 다른 문서의 오류도 한꺼번에 수정됩니다.
따라서 오류가 발생한 실제 사례(실제 예시)를 제공해 주시는 것이 chaff에게 가장 감사한 보고서가 됩니다.
보고하는 경로는 두 가지
chaff feedback로 초안을 만들기
간편한 방법: ```
npx chaffjs feedback 報告.md --rule preferred-term --line 5
해당 지적의 앞뒤 몇 줄만 추출하여 보고서 초안을 `.chaff-feedback.md`에 작성하고, 전송할 명령어를 보여줍니다.
chaff 자체는 아무것도 보내지 않습니다. 다시 읽어보고 공유하고 싶지 않은 부분을 삭제한 후 전송해야 합니다.
Wrote a draft report to .chaff-feedback.md. From the document it includes only the lines around 5.
Read it before sending, and delete anything you do not want to share.
To send it (either):
...
누락(missed)의 경우도 `--missed --line N`으로 동일하게 초안을 만들 수 있습니다.
### 가장 효과적인 방법: 문서 전체를 chaff-corpus에 PR하기
또 다른 방법은 **문서 전체를 판정 결과와 함께** isamu/chaff-corpus로 보내는 것입니다.
chaff-corpus는 실제 존재하는 문서와, chaff가 그 문서에서 내린 지적 하나하나의 판정을 세트로 묶어 놓은 리포지토리입니다.
행정 안내, 법령, 계약 양식, 회의록, 유가증권 보고서, 사내 핸드북, 보도 자료 등,
일본어와 영어 문서를 수백 개 보유하고 있으며 계속 늘어나고 있습니다.
지적 하나하나에는 다음 중 하나의 판정이 붙습니다.
| 판정 | 의미 | chaff가 변경되어 결과가 변했을 때 |
| :--- | :--- | :--- |
| `correct` | 올바른 지적으로, 지속적으로 나와야 함 | 사라지면 CI(Continuous Integration) 실패 (퇴보) |
| `false-positive` | 잘못된 지적으로, 사라져야 함 | 사라지면 개선으로 보고 |
| `missed` | 나올 것이지만 나오지 않음 | 나오게 되면 "발견했다"고 보고 |
| `unjudged` | 아직 아무도 판정하지 않음 | 판정 대기 목록에 나열 |
앞뒤 몇 줄만 포함된 보고서와 달리, 여기에 올린 문서는 **chaff의 수정을 그대로 시도해 볼 재료**가 되며, 그 이후에도 남아있습니다.
## 문서 전송 절차
자세한 내용은 chaff-corpus의 CONTRIBUTING.ja.md에 쓰여 있습니다.
흐름은 다음과 같습니다. 필요한 것은 Node 24와 Yarn 1입니다.
### 1. 공유해도 되는 문서인지 확인하기
* 재배포를 허용하는 라이선스(퍼블릭 도메인, CC0, CC BY, 공공 데이터 이용 규약, 정부 표준 이용 규약 등)의 문서는 본문 전체를 올릴 수 있습니다.
* 공개되어 있지만 복제를 허용하지 않는 문서는, 본문을 올리지 않고 출처 URL과 본문의 해시값만 올립니다 (`redistribute: false`).
본 문서는 CI가 실행 시 가져와서 해시가 일치할 때만 사용합니다. - 직접 작성한 글은 CC0이나 CC BY 4.0 같은 라이선스를 붙이면 사용할 수 있습니다.
-
**외부 기밀 문서(社外秘の文書)는 발췌본을 포함하여 보낼 수 없습니다.** 똑같이 틀린 짧은 문장을 직접 작성해서 보내주세요.
틀린 '형태'만 재현할 수 있다면, chaff가 고칠 수 있습니다. - 개인의 이름, 이메일 주소, 전화번호는 포함하지 마십시오.
### 2. 문서 배치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
docs/<lang>/<genre>/<id>.md 본문
docs/<lang>/<genre>/<id>.yaml 출처, 라이선스, 언어, 장르, 본문의 sha256
`<genre>`
은 `npx chaffjs genres`의 목록에서 선택합니다 (`business/report`, `legal/contract`, `docs/faq` 등).
id: q3-report
title: 제3분기 보고서
language: ja
...
yarn install
yarn validate # 메타데이터, 라이선스, 개인정보, 크기
yarn run-corpus --update --only q3-report
chaff가 내는 지적이 모두 `unjudged`로 `expected/q3-report.yaml`에 작성됩니다.
### 4. 오류에 표시하기
잘못된 지적은 `verdict`를 `false-positive`로 하고, 이유를 한 줄의 `note`에 작성합니다.
나오지 않은 지적은 `rule`, `line`, `what`, `verdict: missed` 항목을 추가합니다.
id: q3-report
chaff: 0.36.0
findings:
...
`note`에는 **어떤 형태의 오류인지** 자신의 말로 작성해 주십시오. 이 한 줄이 그대로 chaff 수정의 출발점이 됩니다.
`rule`, `line`, `text`는 변경하지 마십시오. 실행 시 같은 지적을 재발견하기 위한 단서입니다.
다른 지적은 판단할 수 있는 것만 `correct` 또는 `false-positive`로 하고, 확신이 없는 것은 `unjudged` 상태 그대로 두어도 무방합니다.
### 5. PR 제출하기
PR 템플릿에 라이선스, 개인정보, 판단 확인 항목들이 나열되어 있습니다.
마지막으로
문서 전체가 있다면, 수정한 chaff를 같은 문서에 적용하여, 오류(outlier)가 사라졌는지, 그리고 다른 올바른 지적이 사라지지 않았는지를 기계적으로 확인할 수 있습니다.
**두 번째는, 고쳐진 것이 되돌아오지 않는다는 점입니다.** 판정은 사라지지 않고 남아있습니다. `correct`
이라고 판정된 지적이 사라지면 CI(Continuous Integration)가 실패하므로,
누군가의 다른 수정이 당신의 문서에서 고친 것을 조용히 망가뜨릴 수는 없습니다.
**세 번째는, 당신의 판정이 같은 종류의 문서의 기본값(default)을 바꾼다는 것입니다.** chaff는 규칙과 장르 조합별로,
chaff-corpus에서의 판정을 통해 정확도를 측정합니다. 오류가 많은 조합은, 그 장르의 기본값에서 규칙을 수정합니다.
회의록에서 계속 오류만 나는 규칙이 있다면, 회의록의 판정이 쌓일수록, 회의록에서는 처음부터 움직이지 않게 됩니다.
당신의 판정은, 당신과 같은 종류의 문서를 쓰는 모든 사람의 기본값이 됩니다.
**네 번째는, chaff를 고치는 주체가 AI라는 것입니다.** chaff 규칙의 수정은 실제로는 AI가 수행합니다.
chaff-corpus의 오탐지(誤検出)를 읽고 오류의 형태를 찾아내며, 최소한의 발췌문으로 테스트를 작성해 실패를 확인한 후 수정합니다.
그다음에는, 코퍼스 전체에서 아무것도 퇴보하지 않았는지 확인합니다. 이 과정이 반복됩니다.
AI는 고치는 것이 빠르지만, **무엇이 오류인지는 그 문서를 쓰는 사람만이 판정할 수 있습니다.**
그 판정이 사람에게서 도착하는 한, chaff는 계속 수정될 것입니다.
chaff가 'AI의 실수를 기계로 포착하는 도구'이기 때문에도, 그 기계의 판단 기준은 사람의 판정에 두어야 합니다.
## 요약
- 먼저
`chaff.yaml`
에 팀의 표기법과 고유 규칙을 작성하고 자신의 문서에 적용하세요. 정한 것이 매번 동일하게 지켜집니다. - 지적에 납득할 수 없다면, 문서를 수정하거나,
`stet`
으로 무시하거나, `relax`
로 규칙을 완화하세요. - chaff 자체가 오류라면,
`npx chaffjs feedback`
으로 초안을 만들거나,
문서를 판정과 함께 chaff-corpus에 PR(Pull Request) 하세요. - 전송된 문서로 chaff가 수정되고, 고쳐진 것은 그 이후에도 지켜지며, 같은 종류의 문서를 쓰는 모든 사람의 기본값이 좋아집니다.
오류가 있는 문서를 기다리겠습니다.
### 토론

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59