From 40941b3cb1dafe7dcafed65e34f4a200faea83a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Sun, 22 Mar 2026 21:35:14 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[=EC=A3=BC=EA=B0=84=EC=8B=A4=EC=A0=81]?= =?UTF-8?q?=202026.03.15~03.22=20=EC=A3=BC=EA=B0=84=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=20=EC=8B=A4=EC=A0=81=20=EB=B3=B4=EA=B3=A0=20PPT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentations/weekly-report-20260322.cjs | 295 ++++++++++++++++++++++ presentations/weekly-report-20260322.pptx | Bin 0 -> 230842 bytes 2 files changed, 295 insertions(+) create mode 100644 presentations/weekly-report-20260322.cjs create mode 100644 presentations/weekly-report-20260322.pptx diff --git a/presentations/weekly-report-20260322.cjs b/presentations/weekly-report-20260322.cjs new file mode 100644 index 0000000..cc49f79 --- /dev/null +++ b/presentations/weekly-report-20260322.cjs @@ -0,0 +1,295 @@ +const path = require('path'); +const fs = require('fs'); +module.paths.unshift(path.join(require('os').homedir(), '.claude/skills/pptx-skill/scripts/node_modules')); +const PptxGenJS = require('pptxgenjs'); + +const C = { + white: 'FFFFFF', bg: 'F8FAFC', cardBg: 'FFFFFF', headerBg: 'F1F5F9', + title: '0F172A', text: '334155', textMuted: '64748B', textLight: '94A3B8', + primary: '2563EB', primaryLight: 'DBEAFE', + green: '16A34A', greenLight: 'DCFCE7', greenDark: '15803D', + orange: 'EA580C', orangeLight: 'FFEDD5', + red: 'DC2626', redLight: 'FEE2E2', + purple: '7C3AED', purpleLight: 'EDE9FE', + teal: '0D9488', tealLight: 'CCFBF1', + border: 'E2E8F0', divider: 'CBD5E1', dark: '1E293B', +}; + +// BI 로고 base64 +const biBlackPath = '/home/aweso/sam/docs/assets/bi/sam_bi_black.png'; +const biWhitePath = '/home/aweso/sam/docs/assets/bi/sam_bi_white.png'; +const biBlack = fs.existsSync(biBlackPath) ? 'image/png;base64,' + fs.readFileSync(biBlackPath).toString('base64') : null; +const biWhite = fs.existsSync(biWhitePath) ? 'image/png;base64,' + fs.readFileSync(biWhitePath).toString('base64') : null; + +function addFooter(slide, pageNum, totalPages) { + slide.addShape(slide._slideLayout ? 'rect' : 'rect', { x: 0, y: 5.18, w: 10, h: 0.01, fill: { color: C.border } }); + slide.addShape('rect', { x: 0, y: 5.19, w: 10, h: 0.435, fill: { color: C.headerBg } }); + slide.addText('SAM 주간 개발 실적 | (주)코드브릿지엑스', { x: 0.5, y: 5.22, w: 6, h: 0.35, fontSize: 8, color: C.textLight, fontFace: 'Arial' }); + slide.addText(`${pageNum} / ${totalPages}`, { x: 8, y: 5.22, w: 1.5, h: 0.35, fontSize: 8, color: C.textLight, align: 'right', fontFace: 'Arial' }); +} + +function addPageTitle(slide, title, subtitle) { + slide.addShape('rect', { x: 0.5, y: 0.35, w: 0.06, h: 0.4, fill: { color: C.primary } }); + slide.addText(title, { x: 0.7, y: 0.3, w: 5, h: 0.5, fontSize: 18, bold: true, color: C.title, fontFace: 'Arial' }); + if (subtitle) { + slide.addText(subtitle, { x: 0.7, y: 0.7, w: 7, h: 0.3, fontSize: 10, color: C.textMuted, fontFace: 'Arial' }); + } +} + +async function main() { + const pres = new PptxGenJS(); + pres.defineLayout({ name: 'CUSTOM_16x9', width: 10, height: 5.625 }); + pres.layout = 'CUSTOM_16x9'; + const totalPages = 6; + + // ========== 슬라이드 1: 표지 ========== + const s1 = pres.addSlide(); + s1.background = { fill: C.white }; + s1.addShape('rect', { x: 0, y: 0, w: 0.08, h: 5.625, fill: { color: C.primary } }); + s1.addShape('rect', { x: 0, y: 0, w: 10, h: 0.08, fill: { color: C.primary } }); + if (biBlack) s1.addImage({ data: biBlack, x: 0.6, y: 0.4, w: 0.7, h: 0.7 }); + s1.addText('SAM 프로젝트', { x: 0.5, y: 1.6, w: 9, h: 0.6, fontSize: 14, color: C.textMuted, fontFace: 'Arial' }); + s1.addText('주간 개발 실적 보고', { x: 0.5, y: 2.1, w: 9, h: 0.9, fontSize: 32, bold: true, color: C.title, fontFace: 'Arial' }); + s1.addShape('rect', { x: 0.5, y: 3.0, w: 2, h: 0.04, fill: { color: C.primary } }); + s1.addText('2026. 03. 15 (토) ~ 03. 22 (토)', { x: 0.5, y: 3.2, w: 5, h: 0.4, fontSize: 14, color: C.text, fontFace: 'Arial' }); + s1.addText('R&D실', { x: 0.5, y: 3.6, w: 5, h: 0.35, fontSize: 12, color: C.textMuted, fontFace: 'Arial' }); + s1.addShape('rect', { x: 0, y: 5.19, w: 10, h: 0.435, fill: { color: C.headerBg } }); + s1.addText('(주)코드브릿지엑스 | SAM (Smart Automation Management)', { x: 0.5, y: 5.22, w: 8, h: 0.35, fontSize: 8, color: C.textLight, fontFace: 'Arial' }); + + // ========== 슬라이드 2: 주간 핵심 성과 요약 ========== + const s2 = pres.addSlide(); + s2.background = { fill: C.bg }; + addPageTitle(s2, '주간 핵심 성과 요약', '2026.03.15 ~ 03.22 | 7일간 개발 성과'); + + // 상단 KPI 카드 4개 + const kpis = [ + { label: '총 커밋', value: '541', sub: 'MNG 160 + API 160 + Docs 221', color: C.primary, bg: C.primaryLight }, + { label: '신규 기능', value: '121', sub: 'feat 커밋 (MNG 50 + API 71)', color: C.green, bg: C.greenLight }, + { label: '버그 수정', value: '174', sub: 'fix 커밋 (MNG 100 + API 74)', color: C.orange, bg: C.orangeLight }, + { label: '문서 성장', value: '+32%', sub: '205,490 → 271,525 행', color: C.purple, bg: C.purpleLight }, + ]; + kpis.forEach((k, i) => { + const x = 0.5 + i * 2.3; + s2.addShape('roundRect', { x, y: 1.15, w: 2.1, h: 1.45, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s2.addShape('rect', { x, y: 1.15, w: 2.1, h: 0.06, fill: { color: k.color } }); + s2.addText(k.label, { x: x + 0.15, y: 1.3, w: 1.8, h: 0.25, fontSize: 9, color: C.textMuted, fontFace: 'Arial' }); + s2.addText(k.value, { x: x + 0.15, y: 1.55, w: 1.8, h: 0.5, fontSize: 28, bold: true, color: k.color, fontFace: 'Arial' }); + s2.addText(k.sub, { x: x + 0.15, y: 2.1, w: 1.8, h: 0.3, fontSize: 7.5, color: C.textMuted, fontFace: 'Arial' }); + }); + + // 하단 주요 완료 항목 + s2.addShape('roundRect', { x: 0.5, y: 2.85, w: 9, h: 2.15, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s2.addText('주요 완료 항목', { x: 0.7, y: 2.95, w: 3, h: 0.3, fontSize: 11, bold: true, color: C.title, fontFace: 'Arial' }); + + const achievements = [ + { icon: '✅', text: '바로빌 전체 서비스 이관 완료 (12/12 영역 100%)', tag: '이관', tagColor: C.green, tagBg: C.greenLight }, + { icon: '✅', text: '생산관리 자재투입·문서양식·현황판 종합 개선', tag: '생산', tagColor: C.primary, tagBg: C.primaryLight }, + { icon: '✅', text: '조직도 관리 API 이관 (8개 엔드포인트)', tag: 'API', tagColor: C.teal, tagBg: C.tealLight }, + { icon: '✅', text: '온보딩 가이드 시스템 구현 (Driver.js)', tag: 'R&D', tagColor: C.purple, tagBg: C.purpleLight }, + { icon: '✅', text: 'BOM V2 범용 멀티테넌트 아키텍처 설계', tag: '설계', tagColor: C.orange, tagBg: C.orangeLight }, + ]; + achievements.forEach((a, i) => { + const y = 3.35 + i * 0.33; + s2.addText(a.icon + ' ' + a.text, { x: 0.7, y, w: 6.5, h: 0.3, fontSize: 10, color: C.text, fontFace: 'Arial' }); + s2.addShape('roundRect', { x: 7.5, y: y + 0.03, w: 0.65, h: 0.22, rectRadius: 0.03, fill: { color: a.tagBg } }); + s2.addText(a.tag, { x: 7.5, y: y + 0.03, w: 0.65, h: 0.22, fontSize: 7, bold: true, color: a.tagColor, align: 'center', fontFace: 'Arial' }); + }); + addFooter(s2, 2, totalPages); + + // ========== 슬라이드 3: 프로젝트별 커밋 상세 ========== + const s3 = pres.addSlide(); + s3.background = { fill: C.bg }; + addPageTitle(s3, '프로젝트별 개발 현황', '커밋 유형 분석 및 주요 작업 영역'); + + // MNG 카드 + s3.addShape('roundRect', { x: 0.5, y: 1.1, w: 4.3, h: 3.9, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s3.addShape('rect', { x: 0.5, y: 1.1, w: 4.3, h: 0.45, fill: { color: C.dark } }); + s3.addText('MNG (백오피스)', { x: 0.7, y: 1.13, w: 2, h: 0.4, fontSize: 12, bold: true, color: C.white, fontFace: 'Arial' }); + s3.addShape('roundRect', { x: 3.6, y: 1.17, w: 0.9, h: 0.25, rectRadius: 0.03, fill: { color: C.primary } }); + s3.addText('160 커밋', { x: 3.6, y: 1.17, w: 0.9, h: 0.25, fontSize: 8, bold: true, color: C.white, align: 'center', fontFace: 'Arial' }); + + const mngItems = [ + ['feat (신규기능)', '50', C.green], ['fix (버그수정)', '100', C.orange], + ['refactor', '6', C.primary], ['chore/style', '4', C.textMuted], + ]; + mngItems.forEach((item, i) => { + const y = 1.7 + i * 0.38; + const bgColor = i % 2 === 0 ? C.headerBg : C.white; + s3.addShape('rect', { x: 0.6, y, w: 4.1, h: 0.35, fill: { color: bgColor } }); + s3.addText(item[0], { x: 0.8, y, w: 2.5, h: 0.35, fontSize: 10, color: C.text, fontFace: 'Arial' }); + s3.addText(item[1] + '건', { x: 3.2, y, w: 1.2, h: 0.35, fontSize: 10, bold: true, color: item[2], align: 'right', fontFace: 'Arial' }); + }); + + s3.addText('주요 작업', { x: 0.7, y: 3.35, w: 2, h: 0.3, fontSize: 9, bold: true, color: C.textMuted, fontFace: 'Arial' }); + const mngWorks = ['문서양식 R2 이미지 프록시 전환', '절곡품 기초자료 복사·코드관리', '재무 계정과목 관리 개선', '온보딩 도움말 기능 (Driver.js)']; + mngWorks.forEach((w, i) => { + s3.addText('• ' + w, { x: 0.8, y: 3.65 + i * 0.3, w: 3.8, h: 0.28, fontSize: 9, color: C.text, fontFace: 'Arial' }); + }); + + // API 카드 + s3.addShape('roundRect', { x: 5.2, y: 1.1, w: 4.3, h: 3.9, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s3.addShape('rect', { x: 5.2, y: 1.1, w: 4.3, h: 0.45, fill: { color: C.dark } }); + s3.addText('API (서비스)', { x: 5.4, y: 1.13, w: 2, h: 0.4, fontSize: 12, bold: true, color: C.white, fontFace: 'Arial' }); + s3.addShape('roundRect', { x: 8.3, y: 1.17, w: 0.9, h: 0.25, rectRadius: 0.03, fill: { color: C.green } }); + s3.addText('160 커밋', { x: 8.3, y: 1.17, w: 0.9, h: 0.25, fontSize: 8, bold: true, color: C.white, align: 'center', fontFace: 'Arial' }); + + const apiItems = [ + ['feat (신규기능)', '71', C.green], ['fix (버그수정)', '74', C.orange], + ['refactor', '5', C.primary], ['chore', '3', C.textMuted], + ]; + apiItems.forEach((item, i) => { + const y = 1.7 + i * 0.38; + const bgColor = i % 2 === 0 ? C.headerBg : C.white; + s3.addShape('rect', { x: 5.3, y, w: 4.1, h: 0.35, fill: { color: bgColor } }); + s3.addText(item[0], { x: 5.5, y, w: 2.5, h: 0.35, fontSize: 10, color: C.text, fontFace: 'Arial' }); + s3.addText(item[1] + '건', { x: 7.9, y, w: 1.2, h: 0.35, fontSize: 10, bold: true, color: item[2], align: 'right', fontFace: 'Arial' }); + }); + + s3.addText('주요 작업', { x: 5.4, y: 3.35, w: 2, h: 0.3, fontSize: 9, bold: true, color: C.textMuted, fontFace: 'Arial' }); + const apiWorks = ['바로빌 구독/과금/카카오톡 이관', '조직도 관리 8개 엔드포인트 이관', '재공품 STOCK 자재매칭·자동완료', '재고 거래이력 API 추가']; + apiWorks.forEach((w, i) => { + s3.addText('• ' + w, { x: 5.5, y: 3.65 + i * 0.3, w: 3.8, h: 0.28, fontSize: 9, color: C.text, fontFace: 'Arial' }); + }); + addFooter(s3, 3, totalPages); + + // ========== 슬라이드 4: 문서 성장 현황 ========== + const s4 = pres.addSlide(); + s4.background = { fill: C.bg }; + addPageTitle(s4, '문서 성장 현황', 'sam/docs 저장소 — 1주간 +32% 성장'); + + // 비교 카드 + const compareCards = [ + { label: '3/15 (1주 전)', value: '205,490', unit: '행', color: C.textMuted, accent: C.border }, + { label: '3/22 (현재)', value: '271,525', unit: '행', color: C.primary, accent: C.primary }, + { label: '증가분', value: '+66,035', unit: '행 (+32%)', color: C.green, accent: C.green }, + ]; + compareCards.forEach((c, i) => { + const x = 0.5 + i * 3.1; + s4.addShape('roundRect', { x, y: 1.15, w: 2.9, h: 1.2, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s4.addShape('rect', { x, y: 1.15, w: 2.9, h: 0.05, fill: { color: c.accent } }); + s4.addText(c.label, { x: x + 0.15, y: 1.25, w: 2.6, h: 0.25, fontSize: 9, color: C.textMuted, fontFace: 'Arial' }); + s4.addText(c.value, { x: x + 0.15, y: 1.5, w: 2.6, h: 0.45, fontSize: 24, bold: true, color: c.color, fontFace: 'Arial' }); + s4.addText(c.unit, { x: x + 0.15, y: 1.95, w: 2.6, h: 0.2, fontSize: 9, color: C.textMuted, fontFace: 'Arial' }); + }); + + // 파일 통계 + s4.addShape('roundRect', { x: 0.5, y: 2.6, w: 4.3, h: 2.4, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s4.addText('파일 통계', { x: 0.7, y: 2.7, w: 2, h: 0.35, fontSize: 11, bold: true, color: C.title, fontFace: 'Arial' }); + + const fileStats = [ + ['전체 md 파일', '700개', C.primary], + ['신규 추가 파일', '202개', C.green], + ['수정된 파일', '98개', C.orange], + ['docs 커밋 수', '221개', C.purple], + ['일 평균 성장', '9,400행/일', C.teal], + ]; + fileStats.forEach((fs, i) => { + const y = 3.1 + i * 0.35; + const bgColor = i % 2 === 0 ? C.headerBg : C.white; + s4.addShape('rect', { x: 0.6, y, w: 4.1, h: 0.32, fill: { color: bgColor } }); + s4.addText(fs[0], { x: 0.8, y, w: 2.2, h: 0.32, fontSize: 9.5, color: C.text, fontFace: 'Arial' }); + s4.addText(fs[1], { x: 3, y, w: 1.5, h: 0.32, fontSize: 10, bold: true, color: fs[2], align: 'right', fontFace: 'Arial' }); + }); + + // 폴더별 행수 차트 (수평 바) + s4.addShape('roundRect', { x: 5.2, y: 2.6, w: 4.3, h: 2.4, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s4.addText('폴더별 비중 (Top 5)', { x: 5.4, y: 2.7, w: 3, h: 0.35, fontSize: 11, bold: true, color: C.title, fontFace: 'Arial' }); + + const folders = [ + { name: 'dev/', lines: 132717, pct: 49, color: C.primary }, + { name: 'projects/', lines: 38870, pct: 14, color: C.green }, + { name: 'features/', lines: 25041, pct: 9, color: C.purple }, + { name: 'plans/', lines: 17356, pct: 6, color: C.orange }, + { name: 'frontend/', lines: 14055, pct: 5, color: C.teal }, + ]; + folders.forEach((f, i) => { + const y = 3.15 + i * 0.35; + s4.addText(f.name, { x: 5.4, y, w: 1.2, h: 0.3, fontSize: 8.5, color: C.text, fontFace: 'Arial' }); + const barW = Math.max(0.2, (f.pct / 50) * 2.2); + s4.addShape('roundRect', { x: 6.65, y: y + 0.02, w: barW, h: 0.24, rectRadius: 0.04, fill: { color: f.color } }); + s4.addText(f.pct + '%', { x: 6.65 + barW + 0.1, y, w: 0.6, h: 0.3, fontSize: 8, bold: true, color: f.color, fontFace: 'Arial' }); + }); + addFooter(s4, 4, totalPages); + + // ========== 슬라이드 5: 주요 기능 상세 ========== + const s5 = pres.addSlide(); + s5.background = { fill: C.bg }; + addPageTitle(s5, '주요 개발 내역 상세', '이번 주 핵심 작업 영역별 세부 내용'); + + const areas = [ + { + title: '바로빌 이관 완료', color: C.green, bg: C.greenLight, + items: ['전체 12개 영역 100% 이관 완료', '구독/과금/사용량 API 이관', '카카오톡/SMS 발송 API 이관', 'CEO 설명용 서비스 출시 계획 PPT'], + }, + { + title: '생산관리 개선', color: C.primary, bg: C.primaryLight, + items: ['자재투입 dynamic_bom 자동 생성', '검사완료→WO→수주 자동 완료', '작업지시 bending_info fallback', '문서양식 R2 presigned URL 전환'], + }, + { + title: '절곡품 관리', color: C.orange, bg: C.orangeLight, + items: ['기초자료 복사·코드 관리 기능', 'Canvas 이미지 R2 CORS 프록시', '품목코드 BD-XX.nnn 표시', 'LOT 재고생산 API 명세 작성'], + }, + { + title: 'R&D / 기획', color: C.purple, bg: C.purpleLight, + items: ['온보딩 가이드 시스템 (Driver.js)', 'BOM V2 범용 아키텍처 설계', '특허 변리사 브리핑 자료 작성', 'SAM 슈퍼 솔루션 비전 문서'], + }, + ]; + areas.forEach((area, i) => { + const x = 0.5 + (i % 2) * 4.7; + const y = 1.1 + Math.floor(i / 2) * 2.1; + s5.addShape('roundRect', { x, y, w: 4.5, h: 1.95, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + s5.addShape('roundRect', { x: x + 0.12, y: y + 0.12, w: 1.6, h: 0.28, rectRadius: 0.04, fill: { color: area.bg } }); + s5.addText(area.title, { x: x + 0.12, y: y + 0.12, w: 1.6, h: 0.28, fontSize: 9, bold: true, color: area.color, align: 'center', fontFace: 'Arial' }); + area.items.forEach((item, j) => { + s5.addText('• ' + item, { x: x + 0.2, y: y + 0.52 + j * 0.32, w: 4.1, h: 0.3, fontSize: 9, color: C.text, fontFace: 'Arial' }); + }); + }); + addFooter(s5, 5, totalPages); + + // ========== 슬라이드 6: 다음 주 계획 ========== + const s6 = pres.addSlide(); + s6.background = { fill: C.bg }; + addPageTitle(s6, '다음 주 계획', '2026.03.23 ~ 03.29 | 주요 예정 작업'); + + s6.addShape('roundRect', { x: 0.5, y: 1.1, w: 9, h: 3.9, rectRadius: 0.1, fill: { color: C.cardBg }, line: { color: C.border, width: 0.5 } }); + + const nextWeek = [ + { priority: '🔴', category: '이관', task: '바로빌 서비스 출시 준비 (테넌트 온보딩 절차 확립)', tag: '필수', tagColor: C.red, tagBg: C.redLight }, + { priority: '🔴', category: '생산', task: '재공품 작업자화면 종합 개선 운영 반영', tag: '필수', tagColor: C.red, tagBg: C.redLight }, + { priority: '🟡', category: 'QA', task: 'QA V2 점검 계속 진행 (현재 72%, 목표 90%)', tag: '중요', tagColor: C.orange, tagBg: C.orangeLight }, + { priority: '🟡', category: '재무', task: '손익계산서·계정별원장 서비스 이관 착수', tag: '중요', tagColor: C.orange, tagBg: C.orangeLight }, + { priority: '🟡', category: 'BOM', task: 'BOM 트리 3단계 React 프론트엔드 개발 협업', tag: '중요', tagColor: C.orange, tagBg: C.orangeLight }, + { priority: '🟢', category: 'R&D', task: 'HTMX 버전 통일 검토 (CDN 1.9 → NPM 2.0)', tag: '권장', tagColor: C.green, tagBg: C.greenLight }, + { priority: '🟢', category: '특허', task: '방법특허 청구항 보완 및 변리사 제출', tag: '권장', tagColor: C.green, tagBg: C.greenLight }, + ]; + + // 테이블 헤더 + s6.addShape('rect', { x: 0.6, y: 1.2, w: 8.8, h: 0.38, fill: { color: C.dark } }); + s6.addText('우선', { x: 0.7, y: 1.22, w: 0.5, h: 0.35, fontSize: 9, bold: true, color: C.white, align: 'center', fontFace: 'Arial' }); + s6.addText('영역', { x: 1.2, y: 1.22, w: 0.8, h: 0.35, fontSize: 9, bold: true, color: C.white, align: 'center', fontFace: 'Arial' }); + s6.addText('작업 내용', { x: 2.1, y: 1.22, w: 5.5, h: 0.35, fontSize: 9, bold: true, color: C.white, fontFace: 'Arial' }); + s6.addText('등급', { x: 7.8, y: 1.22, w: 1.2, h: 0.35, fontSize: 9, bold: true, color: C.white, align: 'center', fontFace: 'Arial' }); + + nextWeek.forEach((n, i) => { + const y = 1.62 + i * 0.42; + const bgColor = i % 2 === 0 ? C.headerBg : C.white; + s6.addShape('rect', { x: 0.6, y, w: 8.8, h: 0.4, fill: { color: bgColor } }); + s6.addText(n.priority, { x: 0.7, y, w: 0.5, h: 0.4, fontSize: 11, align: 'center', fontFace: 'Arial' }); + s6.addText(n.category, { x: 1.2, y, w: 0.8, h: 0.4, fontSize: 9, bold: true, color: C.text, align: 'center', fontFace: 'Arial' }); + s6.addText(n.task, { x: 2.1, y, w: 5.5, h: 0.4, fontSize: 9.5, color: C.text, fontFace: 'Arial' }); + s6.addShape('roundRect', { x: 8, y: y + 0.08, w: 0.6, h: 0.22, rectRadius: 0.03, fill: { color: n.tagBg } }); + s6.addText(n.tag, { x: 8, y: y + 0.08, w: 0.6, h: 0.22, fontSize: 7.5, bold: true, color: n.tagColor, align: 'center', fontFace: 'Arial' }); + }); + + // 하단 메시지 + s6.addShape('roundRect', { x: 0.5, y: 4.6, w: 9, h: 0.4, rectRadius: 0.06, fill: { color: C.primaryLight } }); + s6.addText('💡 일주일간 541 커밋, 66,035행 문서 성장 — 꾸준한 개발 속도를 유지하겠습니다.', { x: 0.7, y: 4.6, w: 8.6, h: 0.4, fontSize: 10, color: C.primary, align: 'center', fontFace: 'Arial' }); + addFooter(s6, 6, totalPages); + + // 저장 + const outputPath = '/home/aweso/sam/docs/presentations/weekly-report-20260322.pptx'; + await pres.writeFile({ fileName: outputPath }); + console.log('PPTX created: ' + outputPath); +} + +main().catch(console.error); diff --git a/presentations/weekly-report-20260322.pptx b/presentations/weekly-report-20260322.pptx new file mode 100644 index 0000000000000000000000000000000000000000..4b95066cd4c0ff064d5b406b250e49a4046e1720 GIT binary patch literal 230842 zcmeFa31A!5xhSlJ04BgCq0rKnmO&I67F(J{n~4LmY(YvEH#S?#HkQV=h_-5E$6;xc z;Lt!q36L}a5^74y(idnT2_$8wy{~<@d;i<*y|NT~+gnR!Y3XtcZU66_Gc%eak0eVz zwqtwJ%1E=EIrE+K?OWSLhs~MmK>x0Z_FaL$Xn&4?|6ZL@;;O5yn?veB93oDI#oOZdA=v1Q7ShBm^*!pA>N;D>y zc`1DkYCINImdLA9y=ABTA#D!S<&`E*J!7e?W|d62sZ-C;FR%0r9q4#s%M3QT0ie-jw<~QkPeH$9Wp?@lEY$!OFep2Q99)dctj2f8-~x160uG z18~o0L#bp|NoKF^Se;hXD;xR~@rCEXAFdCUEtX0)Ir#>+lT(tB6xxJM&Wk(3^?oO( zX60m5j;E4JlXJDAI?r2l?A(QT3=Zy2s!h(GY&PBKa;Xu3rK~oj(n=D}bfq#0ISW5C z-LAA8St)lbF2U{gx*}vA^;t9z=c0uzN|)Rl&vLE(Fg-F8xZTNV^F@zpa?0s+JQk6& zFi{se>$1ELk&H4o_9df5v#Zx;)&O_n!PTBvT0Oh;6Ru4w-9=A`CD5zk6V|i3HeKqL z?h@~z_F3Nn$IHwuowU9S9k-rYcdX0uWzcc!I}%b~(H(uTUsJ9`S}Ju1oT1mU(j9$e zSKne0Q(axLhyu)@Hvt>G0q$?f$g5xzmzYw2TV-hls$ z9<>}$DFfi(+JHkWlM}FSU5K;5)hbL3Z!m;+V|uoEFnGB6XG21cCG`zbYBCgQGX3CL z&&)J-r8!~hu2Waj59V_+jXkP4sV;oS_{?KeGq8Y)zgv$8LqgJShhX_>0XCAde zMLI;FGCuRD6)K)X1S;b*k6NMPJw%`~KJ%yq6~sufGRYbW#=wjT zna`*&bZrx2E(DBqLd^N^SSQ4s^^J8x%(>23C&ZlKkC+f=shb(*!$>NlR8M|%+X1?} zJ`HwAC6kRQy7i#KBSGP;{)t73u7WHkQ6)O^;R{{ZLbHgrRK5M{@BZz|*$xN#Aj29l z8zI|=TDvJ|h1qgaqe+OezBm`nJ?f~1=3%+T(I#hRag=v*#2QrD;zS_TqL~DU;fZ>R z%K~^XyqxJ)vQ187XXwl1Dmf`(^pm2@VDxMfN>+}_SsAQj)Mm1nlCfD!&q*BpoGJr~ zzM?Q8OUnkClgqq%YSAt{;ov=~mk)P1&xVrV@Kq;5`qO?)FsDN1s-7>Kx2aW4eWbuax9}_%BUD#NL<>%i{j zb#k4ust|I~Cud@EGK&ezQ47(ffO$zUFbWGoU=xI8ikl{^gPfcV$?;fcCRXyih6}|2rUxOQApj-A7WM!+M;6rj zoM?J@@qJR6bDlEi2*k7^vgmZVh!s3{&I4Dy4Z;ZeAP1gKBQY05;!%yf03I4iHzGz^cr;-N zjgj&J6QU7g$aHTejy+z{h)anBrUO-R@eRDosXaa#0WWEy;50MefX|q& zOvJL-_oeY0^QF-UIcZ$ouf~i?tXj3IVU>ud0S-6bb=lG-?btV0A4?){UPK`xRy5L> zMKq$Yl{hmGSm-h?K>HGYsJ)%n0+B6uy?%*y2e26#h;rc$Jg9yYT?FeC2iNgZa5{Fy zlxQ=xu}7ZNZpkQpG2|*-1egpL89&KmF(4c9QSLmO^9+M zm6!xmnZ3*;h{2}BB*0ZmM5fwg+)+b<7->pO!ZSgWAcmO|lK=s7LLfnmF(oG9o1jS$ z15AlYKnw^wNMOrMG18h2sxH%yvPcW!B)e%LdWu8^h#t{R0LCF~rYQj%9wKJg&BCzL z7iM7`Dmx3Nh7oMHFU$b{bm6~c*MnzDMNP(g(^Lu;eH|QSEe*?Ozx?nIIEMp$PSE&g z@$1wmVJ?&#@kp9jCmX_7nJB0z2}()CiIo8bYdE4c@9rkmx`pp20$# zLfwI{jjrU;73yj=6wh#da=gh2!7tI&stzz@I5{L&r7LnJ+HeE!%iX-M6^q~Jy*W-)G^`O-QT+QwWHEi{zu`gD>hq`q+r8-5#$P(%;s&q$?G_(DL$tM+*A{ZScZX z09j*qp+|IqEu_?5OUT!zGRRnhE<_=7NiGXYN|zh~ql>1Yb4y~~J+SdWO--qA*e$rj zZV~>X|4H~8UQxMGkxh4_dBIH75r@!xIIvj7(qMf16pZRLUGlpF2i{n>?~Qd&y>Zh` zZ>;-<_G~;9b>D@c$(rxWJ#wy^*-tG5~-tzlzK3{Hlc;mw5 zzx(o@-|yS=yX{~4!~fc1F?ui~cbYFpMnIKYrmW&tq!RFg7V}p+Gu7SE(IdyqcLX7_ zSWe35DHh|mW_zfsm#voLvc+}H3Ju3gGC*pqF1(=kT57`WJ(=EY%woigdJ@!yOH-+M zb1GvAg^SR$OknQlO?F#9Jkx8wZiOuOSv@->C#h9#?M;JyE@m}ks7Ilu*%k+rB1C>B zl`MzOrB*76#oJvTi&1bb*lsV6am{kf5+oh5PHHz5Zn_YnP2=)vs|mt-Q?OZj3D=y8 zTfKFQ(nntjxFO@1T7vurvUMnN3XB)Xy;(V7HDrg3!Ws+ve~Fy!v6^K2>P*CZT`L%0 zk&P*y;#wi@S+%-nc?RCsH1CYVW3Bo>=xEk@ zT&P%WtWU}GUPZr?5KhZs;btVAToO~ME!(bir%KFc>FOfFvsz9jlNm%*x=VcrVH z=!DeeN$1^dqj|IxHk$S8Lrbt$m@=hs|a$%8_Q|h{6*(L=3(%7Ld+O){M$u(_rO=g=HLO;br4I0@8L43?4_}64@4fI{7xQQ zGP_l6=x&uur@%|@#)mD(#s;X~1UQa~$&=@G>n1!=Mh<1|xZ9&y?7*rD5mMx+*Hq|9a7BDqq zRY2|LKv{2cdL+07ZURFAi0BZUso$@!E(RgXl`aL$xOoSFm`&cqywU+Q*OISS)k;&7 zFl{$_5*RXAz*Bob8P<29ewguE2MS9{O%H(rzcy^G!Zdt-?WpA}YF%r%ub4K(lV(a0 zPjaguCQtOhmWjv^fzt)1WB8g#!`@Mm<|W6wAp<><%@BmIg|ehGYPLmIdkDZW(IIj+ zgvuxxE*?uXInnDIyCI&$Gz8C$7l0rfvXct{Svk}u2a8TGveMNB!9nI_HyuHcCO?6~ z6SiP^7T;d`#pq5bb)jV1d!nnj&UkNTg$!HF6iA-08kT1G)CCjjTo#Ms1!FfxCWU+ zNv>P@CIqp*fr;vS^?aIq8=Lz1`EU+?8Zp?b*+VTnPwpx!45LQwJr{jE~)Moo-?Hz(vn zg9U&W1GFf7aJRhhqn|m};Xoff{Gm8-u*UEQC;^jhG>1csNodpJDBh#g z5xge^Uh+wP(JMhvRi+UwJWgvu43WCHaJzY^#ZfYd2ZGa#yRknX-)x+QurcGbi1rM9 z+Wc(nh^J3OV3lzf`=2X?vOj%uhX9kZ<~d98@NP~mn54rEAb}5ff3qIIEA9ngk0({6$v*FVhM?lfwBNgDoi$30K zZyAVKiM2C_*I>>vac4M08z!Ls^DsSyNtvqDs)i(Pi_=9f;H z1!-LH(My%0%W={H3T9`eh=EK=RH@oS(hogV%vA)Ro!Fpe7s~1@)g!*Q;2)To}N+_ts^`tV_HOrZHD8LDx#)RA- zOF)f)D5zN|b5w==R3*AZfocj^8S{8~tX&n(b)?exR6z1Vz7NsW%?}{@H6$aF=b@jG z_IOl#x|)|UXCfiVj#Fx?8O^h7c#ds@{o7Hp&R4+lp zB>OJNq}wr12Ao^g2gr`l3~W#&tqScsd_ubn|4hPVWLHqPck3g`js0Dj1j0J7`6ARY zZAff?#v2U|qD`hDVx$K$xJFzX>1hQUH8N6}uLf%^c>wHanA}$cKDoVUI24;c#R|m+v8#7ry*^@7+jzw z?I`P?LlgrM2J)9EEtD;^C}|I6Fk-d`th5kY0NB#mtqJtgm$V?tg5Z?w8%Zezol@d3 zEDo8T5&1!s6vKTPzQ-V&_$;EI+82F5Rnr?sLpXgR?}5h_S?dj=D1#QIW+7Q60ZawC z>oX8k0Mml(&pvGXhbs%;^lPzH@Yii{4&^f`7y6*4`V5q$?o6mH3)`RFjP(Q$MqY_M!b$wqq6#zV1BE8xjw zJ&Y5Gx)?)hn+x5Ekpz#S$rm2U@0Eyx#sHg-grXIZpC`oQWx5icCRK(8#DhvyS@BoT-CSjw(lIk8t{G8rp&}D_Zo<>ly z)R%!`Ij1c1ZAw&T3<;x-j!48eD z&2)qyPL58j{f!bW++p4)1U2|k*i-CEueeinx@9hCQ1K>~Xpw*5nV~%c+|ZsKxjj3$ z{Kj4R!L?j&?>;DSPz8n%AR6GS5knyU#4H|3VhgI zHgImSf#W^gg5jG7&*VOje+mNmSp|(Ll3Z$}F%YF@!VvGcVTdRMcz-b$rZEKjj~UUJ zDUTu8{BAIinIo32I0LGOoZAA7w;EKSp;aR)pdxf;e(Ph43@|z{QqUkgKJY(LoPsh+ zhykC^i{nYh)hZF@!=7+JLpPeN)@IBBcb}P*_}N0wq~S_Fu-kZXRBJ)Q#ikq-eS)PG zo0JqZTpac`N=g!d@cCvEFI=PtPd#3{07UsS^UrR{-L)fkU{mhF=kpJ($#1(Of9o!e zyMg17{=1+Z>;_pb2(jqUV-@Nkb4#JJS2wOVeP$K(hX!#O@`Kf4;&nqNIpm%Kqmjw+ zgo>n~2EY}4Q$=2>MJv?P| zg@v1#vc|-*NX^IOFVy^4ZsUBA|?gGt^El&Z(QU9B3q;HUuX7NRCr zIIPu_#g`b_Zs9G#ufTpAXZYJDKeHj zwNMZ&)#=yZi5Jaxq*)#wU}a{vHk=#M1ip({jYnZSHs1!aE!gp4ZdF)}4WAcrUN7rS zbiyVuLsHAqGT>yfAu2->)*OZ=?g8Yb0CubcmRQl5K(-5_3~1i+FgGa@v7T-W&iNh${h-fTnuuj)W<<^^92v8)h2p==@`y^HHv)3d6ebC9?ZRED zRNSwG>bpX96VQ4Ena9=JH-P@eSehU)J|o2mJ@y9!i~P_93V3Pyt@YVKtOL8*VKk!V zg^!pch=7Ko1t=@uY`bWW_pX$~fj(BDNVrGDSfm;tMblWO(XB0*yCaWy6`@G}a4;Mi zX}tiXw?mQ4Ml8mmNG3B3$@f7^P_V+_5Dd)*qlaK19y3;_DrKJ~r(w4=|BD75Og&fnYyafzmKw+jlg5cy`L&HKuxirz7PH{}w zr3xNZaHwKeDtJ!VLK?&o${(#YA#fU1_ zgBr?jL8=)JwNp(+?#d6*Dzy5;`U_D*peb0CumdttZG^HBq(&BS{6cW}iVH|&D>mW) z1+DRwr;H#b%q|#*;CKR(h$`uTJjL^VKNL|Z!T_)20VE(2DJgMK0Rf8kK5Uuk8TSgM z(;#Gg=7qiH_wD5JPw&d@*;oZLpn+8*FQ8-57)RQe5kca8pqrIJ1Y5H(1%M0HYZhhl zV5VFcxJNRXiz{jn1Xu>ys1XzBm@~#x|2USi0;2 z4ytEyXLG@}#o9M;l&hQ|RD&Bd_-aIr;uti>QB**=+=w?|fvKXzX{!uKMyOV0D8#`L zogo0a6!JwaW0MS8-4afW(!hIzqGX)_Qe!Nkkx)ylu#BzPf;Rw(T(;goN@R9clP^b$ z!sQk8>11ZgZyX$YY6mxTU{CJWuT8Y-z!y0s7<(lsbg;FDYS5tu?V${@oO0R&UzLQ! zMtk6C2L#k%V#{C6yunr=szC-?0-ia%p-Yjono)^cfV2sZu1xs&YQo5A_|>XG6!{#0 zcQC~d$?Js(FI$BGpcc8<*m)gLjX84=2avo;T*HacAzGnLgWDpaM^nIR(8FlY1JBs? z0Q!R)m(;L*58!LIb%>(+9#E4&cTE~4H*!x53_W##%Wv48AKW_OIt1;1020HNq?pmc z)*-49n`+P@$`H$`r$hLpDsX|34neyhc*Z^miZ|FgL^a4j%fK^8hlur4Dg=~s)f^H& zX~J~~I^%^Ed6xuiFC*JNFYULenXyn9#2YXXdnX3TP5r zyf86yuh;97EJ={f%xz|F#Cu|`Jb(Y5{6lMVw?j`U!q8EYv8InN@B_o<^4n02`r+Gm z=XV}}Mr;$Wi=)PL=5Qb2FlKY0@|Y2-Jl0Zra@h1c@yHGV$(!*DnPu>5t93ZQfnPySG0K ztsiq+kYc?Ccs8(UXbHIkEb7DSAs2lAZcxCv1udCapOR^~R-FXSZFr)H6&;uhTf{MQ zlRyA!sTH+dI)piQYfEc@t>SICEC}ZwPmcu?SlgU?6r6iHg~4gf^Cp~o)9xjawR@?+ zy(IyfWk{AZ$mZTQ_olgb^YW$KB?6awVoUy>N4VT0Ylb)O8D76BH?Rq`Y%afbV0azy z@!RrGYzI&IuA#jHRp1R9yE#gurxb724k#1*mV|)MTil}f5N6-uaBEA8b=%+CYD!6l zlY+4Car9BJfwj%PN5Q_QQzmTHREUWaTr&JgM27&P#8ig>8VBnrLDO4MA85B7)%Ob8`p=Y(}P=&lD+K`AoM)7>~I?o*Z5jYp;9S?lK z>DuGbJNt`5{bN6brjF=Sx_372<<|hc6xG@r`kA{fGV10?b%@k^B{J>gh&v;)>R1i3 zCc7?-SVprRANtu-)pV>LvxsAN ztX6wsXaj@3x%wmVki zWJ*RtQ;(chIL78@lLgT3SdClIU~#$)I1B!wi)U&Y9U37~o08EBspf@34FtN{@@t?* z?5Qx0-VT&QUz(hm(c18*d_!Jr0GhFd8iuzFKr(uMa3}cMb9)V2D#=(Yh&%q9|`8omS0+ za05~NY<&wR zehlmH@q@dWLKiV0qQ2FdN6zE*f}^2=Te!O7O^|7)`4WvxoFlph1jl_EfLpO($xEdM4+wBwK}u%0!(T=Pt=4D2xyxk4Mr3n1V(p`k=@v zqEgI*#wgK+3S12HVNW=~P{Jv+DaIlW<7j9SK~x%q0;b*L0m3OS;?O!=d8K$d)iA_e z6c>;_yQIx-RniR&wi=}yXeMfoMg=;9%}dOBcL$(evEFyuin8$TfDcN!j{{|yOtfGc zS4WISRoPXiQ=vSMd+70fRq)#)8(Xb-Q55A4%!4Unm^p61%?CV1i2{?taj~q%lH<}= zXx5F3%`DdnhBnIuqda5?+G&zTnq(I=9a})UQj(^WlfZEeYcm!@S$8WI%pBJWD{PLd z`F*h`t_*rq#c`)oRvvKBNnyD~R(#eypiL}S5Tw9}lA4pka+xc+v>l&y4`>t1wS=L~ za&4ANByNM{W|S^Dl1*hMUW7L+_k__hw%nT;ttBqljCMR2Z5gM-l=E(RCxy)#UKZle zV%-Yb%x0kvmA|<3+@!Es)|zdhUofF9jLVpq*{l@|Z8mGO*&;R@=}Bc2mzrH2S0Gta1G%2{5KgVh6Ndd8GZ<)Sm)pIMgOa=X!L37k zpMfUMdUu?vJJ`{bhe$6~=Le2+yK@toNDwvaAz-ojij5{pSu`=)PeA*q{Jm>(4{b&q zCU@)CYHT{e23HK9DzTWeZhtQMz-F!oN!l5LP)I5qi^q`|iZbY1WVMIuljBWJ94oGo zSDfXB5}>uT{!01K(8hx*JkGlNc6DnwRg(mv&8azBm~~riDIoe#>K{plvhxI&rIL!q z-$|*8G9gPdJ5La`7+jDa*pWLpFeyobg}&Mvi(u^#^!On}SjUX1l_ppw7`?VM!9w$8 z>~3P+d)dbv)^?)cDEb=MiGs*0F;@F}p;tB`M68=-OMb})3upyG1Hy= zbV2AXN?`@#%3KuBwZaOU=Z*)@olfb3zDWtL6pIY{z&)5I=$m=2WqQw~@LcAKE^W|f z-N@L?b1i{r^IV(f7V+Fk%NIoTtw?WTqTRAK;hVHuOI)xy?Raq7>69<%nGEH&&_!BP zZW(9yP>j|pyJu1uEo;st~W3gsMxl4^0|JADU?A3s%iWW-7+y@86SuXf5P)=t)n0$a>=P+fbU|@a?Hrxz57v$ZF|S^&_x`i*rFuD zhj!%;J_;GOkZ^nZ-TAu*AnkU-d5qzCBN{wo$D3IyvvUV+sjR6Qgc;<99^aF@Z#ydB zF!(hNrG@05+%mLh;sr6ou}ZAw660=0BzRcziC#~jsC0aQm!L8bT!3nvpdVVw+*m7| zly241Dzy5;dg3#6S&hx;JccVygC1jFoDMx`%?NP=U>7Z9CR5N81CWn4{_tbo>c+!U zu1txw%fo7j+351MX|P=&(6+9q8XR(Y`ANFRgR^aF)Y? zJ{%lNr?V~%;G5U)Q;6@cyi^j zQ(axLh|-dZ^d^*K*5VQ5?U%@_Q@vRjR?c)IWw4>ad|U$&xrj%ALR{8rWX(B9j_mjFU|8(i}u1rN8j-8n~!if(B~9wFBHZYF<$LkA>D|FC7Ym8 z9?eokGx93fVu?6erGy+yI<@;Vqq)E0QtP9oM>ASFqo}ZB@Lr^*gt1b?P90(4ZTl|B zq}#DW7cg>JAN2Z(!Dcn2KeRIVgmxMJnS{#-4pX;x>m$jHx~2f{#`QNj3Ck)fbfvK= z?P#QDxy7}Sp4R>>7a>C+ZA8}*$OC|G7!O5c2+cLwH}Z81wv2Zrw>SZ4%eBSjh|-ga zN0ki68}CVO25~99Bo$eya>*3DIRQv&MG8<1fhHB|k(1p@P)$Q(HabM00r1nGjX;EE zlkVZN80CS!ElzZ67m~9u`@&>ZSOYRjr9vb|X6Z77XVhz8Jq|Bd$=9en)6P_MwG(y$ z09}8v((_F>X8W7r2E<6wjrb+x#<-eoM}?%}X;6a&{jn}QVVJY=g<0SWawGYRuUC@M zHaR1&DDFUIz716l!~8^_2x2C9CzRd~hO3158i{EZN6s18C)EM(l)9L$)g(#W;I?*yk2_$-~$4qTg39g@WFCKkp6K!>>R% z;A{4TnnO1_jr|DpISI4Fi&F$(Z8gNga==5-g(VgQfuh7R;ME}FLAp`t&n{76eepN0 zHxp}eUfVW{EeH zK3jN&h(}|{<&fKGpqPRXI83%@?#~l|r z2g6}0mLNxp6XdwY|H%(s&M7%Nrm_weNU3?@BWB?gC<$5sS2_9Sw^C~NFE%*DbwB)pA9ssU0ojb$25=_b@1d92foo!#UwDSJd2Kj5Wh(%)iDWLzFFuag?gJP`bZRn7;r%0$okQ)#xe02*Y7Ux+TIGE@+89MZ zNS$&nKk#_|zOQk^+o2-)BLyk1tk8|5SOPs};x~5x3P7)sh_y^pnKUg5wkstbTgu5u zCe=xTrfZroL;DIN6)=Mw(=eleIv~F4j_}6rrlh30E`)xRoDV z16Yy2c@y{gnk^i!xf{+Fh0`^JsRmPMXcFREwW4a2BG)pf*rJMw2lH+ZKcd%#;Pvph zoDQvx{Es-QM`e)%CmU`_I1#dZszcY;V<7(1q#qms*xY?Kz2yU5h7qR4s#TR z0Pjcg4^{wd6=6IYOYnxXoh%{aP|NC;aAK4M=C)Se@bF_!09e7)rX)%NV5^1(ww^Fv zDLB(fBobYMz%2j+E9BfvxR$^hF(L#V7&{**bg&hLYS5tuMWGC_oO135!N;HD5j<5$ zNo*7a-iY`i2*KFrKp}*!D^!CJv=nUX3L}Hvkl&4lQmwi|kv9Rj1XC%=%L`t~=t5^J z3*(|J6gd=tuub9`PK>s|y!{hT`xJP_P6e;v6~WC+lxAC7u(<&p17g+UH~-*HNHNYm zIZ%aU#D*u(4h5dEM}a~GTT`e86>88F$`HyarzxE6^`7GvCqYx7eG0%T*z#91Z?H9m zY7l~^cQZ;;;1-}DqzN}8p)P%9=K{~zyI_hx(w%9PzgY~3JhZvfqA&P>q(vx|3D&DF z{s^kW_%xs0G>tzJ4Cewdd@yz{n1U?@$?Hcw$f*@1Zc%Lo3vu3M7O*IG46d|ZnW-Kz zz(Xs&v3&x?;qM*jnGTLHrBWSh^M9q8_*c0T%MFK!3v<@7bT<& zQfNUHq=!zPUbkMQW2`~Qr6YEkmxvK)Cj(F#rZ6PME=t2taPv?$MrRHzVK~)EO8^x= zGEk(vpd^YC^pDkeAhmg>UTy=#^&$0ed1p)S?v(iF&Qw66-ZlL3efQ-mPN3b3>g zi(yGssOm3Fsmf$x1k>s-H8eM!PVP6K+YMz?tH2939UFuq#{+NwVz(k_pQZ+<0%Lyw#cr)I z!e+PQ!EUEhEAas83o_vfu4s5!G;Yh-&0^-ZzJR2a!zmQCm=t?5YXw&{jPh8)1zN*Y zVli`DD;V0`*5Nh>|EDrSCbi4r!y9S?r%ZV5ZG6l5=gB?h(y&C%^07}h=s_;LkU z&y*aE>Py9!*&9NYS5rnq2c!J@$XA$gBx!5*(D_yDI5K@MCdKCng( zY(*McEu1UjN}u&o`BX=UFpwqk$&j001+p+$rJK;p&uG?7;E5FX)?mRS1wd?qvCcv zjLr8t^q_F7=%pnW3VLF|=kty~{Fs+C^cW^zLWUVzd`*pz$l`TRp`^4spn-@0p}qjo&B?H-5_Q{jcAlIf(!0&S?onQ4PIOzR%b zRQ!=R7v~)hd~l^3)pSQjQOH(rk4G0ROgBd2nWb`ic^{6WO2}$f$%OEsbS&A8R1NA9 zGzQ$)cF|#T<~q>7YodKu{NkEL)5pO`h z7oG>-xIQJL#!|^9C*J^wq9h}!C_J&rd2vU$9>jh%D<`9JJe5?MoU0YpdETO9=Pq2K zAbOZesy(r^%E2f}waM9&&88b&E;Z7l!2BChX(b6~x>A{hoQ0p6ZdY24tdzSIm*94L zT`+^f7=ZTXF}cOjCTC`G6ig}|tJCo0%44Uxx?&NfB^BvSK)krcBgoq?kyodBvoNfj z=|*~ULxcIa1|o71j{t=v6|0$nhRbed$y8QR+tEr<6Du56U4`#>{jhv#o|js*7y8s4 z|Jrg3!4^xz$toq}SkkH8pBc^l6_;8c zEj^mi(hwj3I|lDXYDyR@HSE+87T&h+f=s#{hg<+gF6)D`jxpG*hVc)r3_hVPU=w!ax}z)39dU;GksV_eO)XIIA+ zcp6wV(I4x8T0@Y<7iNJkpyFQWFTNhEeQk1PWFtWHZE!6-0AQ(41Tho56H0@ypjzYo zu&g)H37f#YA;iiXqB105&0%O#8})O&at4^74p_YF@diNq#A+uLUI@~I%0ad(9>q9& zec0y~c*(=p^AJK)FNK2MdOzC`GE zlTO7jFXi1XLZ$oUIBaq^G??;x0|9-v!z}TV=(B}ah-iefYOw}$lOksJ{HHb@{XGzB z(B~`*W=5o&0(%>?h%@)7qbRP=NXCI->2b$J&cSe4iY3UA;siOa@qh9|mvc(aj;XAJ z1yX8Wnuv=3qYF1^0bJ$eo2~!v;ZNqTayZcEL|WFx19_0}HWsM{NYONwX>?N`rshcL zPB(UTlfNXLgED?l4verr91MprU#4s%fb^Z+8f_+H&0L|WM@}moW2cwN0$4Cq6zce4 z1E6O9^Ln&0f52mO!4g#hxIjrIIP?XStI;OnmEH(t64q+-WEpZAwxF{1V}XHQFA-rR zDi**;psUHu8mI}A9xDK+dh#@1eImtl>NW+Y()>MJIL(BbTemO2?NKg&)7t#Nfr7AC zR`y0Ya0H0Vq;QNNjNMzNer(!TEYyNbhh1Fcn1&#Bbpexup{Pam<5xZ$n)^BZ?_`TOq3Z(Gmhx32{(K_xi=OL9-H;Sk!~ z^GG%Lg1xC@#g`(NCS#ALi6O%l@IY`PT2>QF;duy=)-VR5R7Avo%JY=!DiL^ilJ)^y z-n!9Y>1~J$@P;k7VUk;lFY-L`~GMQCMoR<0S@JYH`AAc!Jccph4r75h|q$t${1Jqw)23JpY|S|rQ$<0Zk5 zUEwt>U`r?*YSkN%QtKSAP53Hu#2xC89lhQ*+Y4Q^uGiENC8VhQD$ z&2&m=&F$HeyMIUS;3f{(&d|O!T>kEX+yk4c;3;$yXoAR98$#(68^#$nCJ_u+2QQAu z>hno~0zopg7zSG2WTFW(+%Uw2@>nsQ`c}Ta=Bpg1HLv7Rw;)aS;y@xfeR46yNW#I& z3hNY{f;P`XI8>lGq>S!rU}K7@_C7OoV1p~aZZ~Kpxv$*9 z1=|*D$THFVga`4`ls?5gd#Ygca(lfV5|~<0QEW5;t-!i7<4i`A{K0+b|J!#B-+aHT zeQ7%f(S!M$@1IOGG2$yQH({JxWsG2u+55Wa&wQNU!F8cxjhwr$hb_|)6x z4R08+eesO_VG>kMg+%r#YW-?%4Tf8-&6hZ`1{=XpSd(T8tQ6nG8v#zl_sH0{G7iAD z4PaolMRcv4jk=7Bdg^&wZrYh&w+Ad=xd(S6cVvEGaKibD;ZPx1!rGx?>H%QezpAQm zKBMKZ{C%7A_w63uuseU>dM>&e)ah8{>P`rCffKpg?*?!E&iugR6OJr~^NJt~>x4iv zve+iD-er)XqS^F`vk!axY~9}EugAvXp(oZLyBBtzyngeYmoA4ts5dk?@pW{W6vqlr zJ0N++nSkc#$HHM1eg#IP+36QZmjoe!~sNh1Q?=})f#4?%9)<4Kunp8J!GaB zFwre~MpTkIlw-ic;ntQG4?`=MKzmsLeVCe!*~8j4f{nrmHl4~k<_9+n?Y)2a&J7$f zgiW;Y1;Nv1cRf%irWj&!M2eD|9}$si`|E9gJ@#*aT?1LZvx|sMe_&63-v*?!&?S&_wNKvf5P#Ec0U4_88EVkXt4*V)AbWz$lzy0Cd-hH_(k3c-+ z8l=wOg^FD7fEfJY^*gu)Etwb;w{5sqJ#(V*MKrut1Ya0Ct;{}p(KdY9KKfDm=$n@> z-JE8#;mCTmtm`^n8YyK2xg06qZPw&r;%GX z4BrMJ#5ZrrJ@9aT{dNxJLJkgaBrI&g`HJCpBnA|bvEvcMJJ3LWPQ`Di|3aTn9JyToROo>)dKnf_~hOytmZUqJ13!v~b z5Z{EHS)%98+W0dHDaSMAT0y;ixaTXCTS4I>`F1O)DccGPuOE*8F4rpIw+AlukFFKe zn42cx))UjXZ2~GZJ9E1l*sY*+bBkVBm=qm0HLbE+K|xz6yA>1!W_t=Y54#mqZ5=MH zT0#Bu(+;JYR#0OWaqL!5sL7|^s0s|w?Al(IZv~|bHx*k!b-nuc7nj`OaG;M>D=4qs z3aVUtOWo9mxjTw|vRgsnh9{sXqq_fe%LeE^P-Xv2yA>2-gw>|~8uoiqJBO{G%M|Nf zXk=5!h9LG;ZTU50D@j1t`$yE;OKYlES)bvppmG~`<#&Sb7fR)j+MWdw&u##v1whx* zVs6T#1>LNud`ZIT)Bs9w3*H8|*dU19=Q;G>0LR?`{Rl|QwEXrB`N6F?RASruYEXp+ zXN|Q#3?H24!(_`sOg=cv0=Rxb2zd40Pa+gP;JvgULDB`x*iv2ZC#Y_&wMA!bUQCy-Ed>H5V@Bxq%Q6oj*rIx(H;Cpvw(P5drWC=cM)|YQ?udAN7$kr{YkWnH65pn%Q(g3?`bHXY}l0I^lt-5qojR z!~Cu_koLzd7+$|AH?V2=R;YnxRA_+8z4<*4bHjIU%{};RRRtL+IM>QvirhiKZuD4A zR7o}67+Kbbf;wUNbR&uCgisID7d_&Wbd-}D^-zFRR~HBF1ao!??}0wM#r_0cszu72 z;O2R+zk)TqI(HB+dPyo>E&ia^R-sk*ZqTwzZEgo>Nny_9f!=zDIIKsjAWS3a)`zgF zD#f`aBzU1V*0d0Dhqn$u&!Z}MIR;lWmdOJ8>SBHx@9J!Sb1J$Tf34VLvZ$;Z>mEls zjX^T5-|G>J%OOvS=8R4Amb<1#;zIjxShv41YtB|Mv^D3-MRSWZ!t(Jjw&pxmszSSN zppP0;ZcAy-Rv2Mx&Xq9&tAbT=+v%h+kkYtSa9bvtbD?t((VQ9AV52l=E4;8Z=aLnp zDUGf?dze;ufC@$LN6l+c`KWE{p<&1H-CJ^x?BnuZT|c}PRWU?eow@uy`|{h@a=AU* z;Xl=&4F%U4HRVDNC=xiyx(O7eDF;Nq2g>ilR14wvx)eJTH05z_C&V7swx)~~!16T9 z)|AJpDMNP$%EipOaga`9kTFh>0umI-r)bcmXv(a8%JgY^j2CGw~)vvjkd4X6*RUX$;blyUdWF)H zt?_4`EVu4Lo$iPB zt>N-}9;q(sF~Gv14DBx{IhA!U7D|EhxxLl98d8FDK?UJ`8#?w?dI4 zS#EgCK<@rQIF;YF1@(@H`0L!B9o+DC6rEiS-Y^kSi~KpjT$mz`S$7lN0XLL4rDarI zhMfs|GAc$#TAUKj%{V!PJ*;g#+18UMKu?wo_m8G0Gxq=JGzRI(lAHICG6>VmsVvdO zy@1v*CFEv3*$RfXo?KZgDANCClvDYuRY*2PaH>&HmJAmF=C(j&m?8wFCtG2JttVH; zh?%V?uQ)?aq|a@s0yCKC$`YNT1B`<$VwmbKTe4eQSGIL!*m0)l>kB)UUdH8~08jD& zH+=K{{7&d~^u(Isn+LfCp_XMF-w@zlzxhsXS=&-hXmC$>>;Qmw}ir>Rv*&oVL@5c@sjA=5Fl2EIIL|Yc@#=A?+uDl&~lqhxeg*jPi}%p zmnyh66KAqyxP6F{3`B`3V(2smDak&+2YN@*hPp|Kyk?!9EYWTPpfyZkXjYP~U}!7J zl~sZw<@C~Mng7PO@;f1Xu+d4ArIFpW?+w(~7iLC@1xcn234(;DPy!BBow|8Iu?g1#< zbvt}r1K#HRy4{e+yd(eQj%sj*g)iAt;XN9>eQH)MOw^Oc6s@;b1W(!3}92MW#Bs2lHrJS5#SZ-&1J$Blj&) zvzSYyGinyKbuOyJ^nA*x>duUGr&?Kg?HmTE=u=e@Aq8|m-Ac8NB2G%o> z2th+BfRIreulx>y2H#?HDdFi8cgo?f!x=g;qp5M^AEwP z?L$ut=5O7f+qfaOaaThXl2*}j)Tp+5iaZiP^_XHF>=;Dge1KGeqJX^sFG+YyA*4e; zGuGM>|@ZO2fTvxM=69F zQP2|uKA(5|;m5p>pvN#pW1|slMy8w3%wl~Yh+2#JI@!1T_7<|%{8f-FAlly!q?z6x1!&wdo`fzY8ozA+{cr2=@uB$UjTqQre4gHCD1Ny!2Jov`-DH%1E zN28A(zS(?Y> z7Dqu!S{w!AS;y)$Jh}4N(EcqJQCd=w-h`6OT0DZh{StX~sy7S6%9(BjM6rej^KlJC ztpL6G(Co=3Xp~2@RMCvQ3bt4xPF5))$C6I%{>*6Zuej9uXz9_6md+?D z>=?WksVQNs)UZ=WSk#H|f=pWPK?uDHAyGaCo7FJ$qLsl-47JPfPt?AU;4pQ2w?5K{ zE`~%}E;6HNY)U&C=~+%X9#YpvdRqIlTm%{+ny&_%IZ;J`ZWs?mWQa6b9QitiAr64o4sCe~jmeUf$K;P{!ODv%1vqiFsMmS9}i`+OGu?BOK zB4*Zf!gl}>r z0wN+@p?%ShzCY&O`HVj#wZf*$jADl&%iB zvmNS35j!u;CJRgi23O=I$>t2aD?lCTf=TTsoI=tfs0eMnNg^&HR;s2W%}ST{tqqC> zU}i+*0`u9<-esVzVvY>YMwP5k@hW7XcXBJ04AOK#0mW>bGVx)>RRN`&3=BI0fg0E} zbrqf{774mQ8g6o)ow&9>o<&yzvzLobC^9(_QHxGQRBdcBL;M&Gb^uq{sAj+doROqx z0p^69S%UI+1sva{TYKvD17sEAbe@l4Ybv&ZtNk$76t4+zZ-51|M#6zP{$G1cs)y6w&&P%UUK&t!1*l#9Ain%dVw{ z6aqpDvRXb^EfiT~td`*S;9&Uav08VHSSB^(1h>bBx7)N_ zu9u!3NeidKYM})(R?BNzEe|hY(l;$v%SzBdg3Tc>XrL7`mdj^au7Hontk+(yXgC&+ zW6c3Mr)rS#8A=*xg^cC$7nX|%?UZ0R-6f5wfL&;XjO7ZLmdo$=PG?EOLNJ^P%Y{~m zXwW8=85HPLwnxdBG-%K!+u%x2+BLn>TY^h@xBRHW{rh==}W@WrEfkmyYmKM$_!o>b;Kh+ahbTTtN>dMI+!y(&}Rn%Y_CT z(X=gcmW~N#5=Jj`xnD>bFVp#Om zyTg*FKF|u`q&_hi3I};n5Z#6N*C;G^HkMGrvF_fCvK*2q&=O>d0+jI{&Mxw~1kuF@ z3h6U7hr^cJibYY$Bcs$u5tIzE=?tRO$(F?kP!;j=Ldh27VuBs3M;c%V>U4}$Z-EPN zei{VbLaMZe^7`i2sgz}IF`*9nC1}BtDdY>m4~ZwaRVWzB2Vq%{J!mVB z71bb))e6%{oq_75O+V0W0VEB){yME5DRb&2pbudjGpK4OO;Zs+(1c3E*M*Kvy7+07 zStyx_glqJUb;FQYXsbPg_hVJm*({gN#GNyCK{eFsX$^!ze0>PoiX%ZaP#+Lly!EXf zA0G;NT3dtua8-#~udg|H+Usk+Ss>Om%cq#Sk!L5DgX$(>Is0%0kkmn32@X;1pr}3Jpqt8 zWOZWP^iu&q*iDc9OvtpS$%{y-Lq9ED^B-0pJNhhe%cGC(nm1jomsm0#!mi#!&oy6M z+hAO35RA$PUNOmk@585M=O5*8pwEZ2aEJt0@?=*G6{M+$!W|9iWcMv?%Pu%}?nh7| ztYa5n*s=ot`yzZ^sDs)^j%Po9WB~qiRQkfpRfpr~sNCx>2P$cc{%v-HGf#s7R=ABJMr5cdk!3SU~~4P zm%jGw+e_M>S+Vex-#>GTdf%(3f8vKNKfUX;+g`c*Pebp#^Xc=y_s`$l=vd=(p8ux} zjvt&hTe`jO#|umS*zxG4_xf@_``y`Zz0vdG`Toy*!|S{A^Iy(hQ1|((_)jIias7+W zZ+rKx2mW<~EB5qx`9*&}`QoQHyl~lvUf8+o8_VB+>&T|{Z-4O*LC=?-3f+8F-T8Mm zy!-CY|9k(hf@|w`XI=SocOEx*LEZn}@WKll9M|1g_v*#xF1Vq2&eo3|p637f)KwS$ zz4zJwd&Sm8XWa0my0hT1pIv(NYrj0V`QeRqXZ_)-1E)x?HLpDV=WGA;;0r%`@u(fn zM+c97?aKA1+z69+?5y{H{ov!rpKuB9Sp4_<-}~~151$_l!W%p~boh@?8+fVz+>Q(X z`qKL^zI}W2`(K@R$-3Dm&)$6BbLus3Kjye(-G{&Vq1SHPmHOCmH=QV-aml({zVy2_ z3lH1;&#UI2w0HZ4t=FuZbyND|+t1$#Uw8faTJ@3sSr;Dj%F^(h)3UBT=bhkMbJZy? z{rtW2g;Uq9?KY)qJ~#Ns zlQ*A!#9Pm;+4|b1!w={9)Vr-M>6fnC|38brcN9RT`|ZB}{_sNq?xN=xf3x%Zucunl zyVg3c`~F8icIxaKKXOz5|MJfM@A=IS{ZHMxAI`e`;I?;P{^y?e{=fImU+DQ*@QqpT z-gC+`EB}(8H|vI^lcg_FANdtR-o~`>qYg#(;-Q~Xz-SWHUpMK%9C-3b!Yu&D! z(m%iFUf;E6tb6l!Pp)#VIrW~o_uo?Y%}>62>HHT?dh46--0|<9egDj#u0Qsr)t9|L zXXvY!u6y&0C+E0-^!kx+eemhyCF#iMe_is^dr$w;<>v^qXFuF^$DhI*uRpiNadG`0 ze}4PM%a8hD{@6{8AKdRer}K3GJ%|0rNiV$h%8~9De{ttOulSGct$(k(^SGB@e)G7e zAKkU`t;6oVhW}Iek<+&C@m%|fU;N{L{`wDj)oIP?yZ#~u{}>p|y}ABhcYpf}4;|Tb zi&U*Lw zFLI}U?3s&B4F2ZXwe^4A=6>ba|M~YT>%Q^l>{-IS+3On~`ky76`{yP9=y~R7|DSsQ z>&AJZU6&no{E=^O>$>9GuiW_I{TKi6#8ZFp+LeE++w_+s9{bHzKg}In^*R6C-#m5v zk;*x(b@#veZ>QgP*w=+iUU=iv7yNSTnoqv}uim#FPhIq{D-OH=$hTg4bWZRuN8I-x zzx@{Xuk*K@coF!A9KpP*-P{1{^+Lkl}FVLZhEtI-^I_Z zeqi494Ntdj_OChe@VSHEdF|zF!~9RY^3enTI)Bw0*Pryz$JTHD-1lFqpYx|5&Drsj zhi?}XZ)|^T&YWv*dhzMcecyTEGrqT<-Sxe5X1!Y{`|o-xbi)tcI{TeBQcwIo^XIzb z&zrTeZty#QN?*0V?#{Q4edfFO{^36TVvhLNhU)|pN&b(Wn z`Piox9{GvGcO3S_x7ACpIsLWZ_iuag>ATT{{}%k|^Pf3x@E6zB-E|twEB*BVclOI~ zeD0AQkq_?u%N6&%d-t05`1iKHf6S}9+JF7PrR%--nyy!Wj)Bd?$P%58uDH@RcZQKxKqwbilr6F2$%W(=04{UK0J_fy>`aF)k4!-KYQrHqaUsN@?C>hpZVj@f97)KIv_xgbT8tbg16uQ z&L?^vzU{xB7`pGTSD*3EzP(@g+xH*)6r=IZRmwyz?Z(sih5BK1QezxhD zQ(xjvKJ^55=9TZh?_BVwv%h!5&96P_d;6$?wijNQcg16~vj?B~74fA(A7 z`tZ7WbN{>fZ{df2f7`DcZt8vdfB$Vs-5p2%rtbbVB5cB|j(qdF`~UIjy5sJA?zofB zzkS}^e(&0$&!0BuPxV(Uzx*5CZ65E{+dH5Azwy&=?ElR+{^^bvuG@cb%ey~$FI;!3 zb3^o+Ime%RPWb4*e(dY(p9&uxob#u7FU_9!;td0vPoBReSa-|(U|?YL3G=tK)*UrJ zxO!moG4uZuj?N1<4Q!q>|3BgAyx@%k^G=@sOK#wW4KMuLsdHNAJXv=t=iGBa-HY?q z9@ktqQ1|}4=6NlzZJalooBf4>*EZF4a&srR{>{P;lIQS*P>TzBHU;G%)Hlji@nr4D$?RRe8x z^M4zzJAB@Y;>&N|8uFcd`fB zIZxtZb?2={`be z&ULq}TYtVoocH1}LD&{|Z@A`+-@}%5I2XKd=A79J2I}VW|F+gK*ST)pCOG}lhQU4m zaq7JD4{vD;ehn@=-udvZblse``SUwE7R;Ib@TR)6?)~uWStoI`5BorfbDY+4O*C3J z=b8<5#~gdiTF0jOYajnmGv_$6<+azA)XjNqpl-*)qt`l4e)hT>Zg_Xm%?~13;Lc>- z3&+hLT>Z?)nnxi%{P>xF&D!{}PyBu8_G7*XGLB<$>#~-|ny*>ccG0ZaCpZd)LD4z= zACig4zj@k!Nla!`DfEF z`w`G9(4>icTMkI{oSU`#aJ?&15~%!RkswX}p;!K#)$NsEoSwsj=0S+|RLvZIW_5ez zInawfcQ#ex}X&wao zQ_D}`gZj-FTTVWVKpek;cDMBmZoB#;KY1Ot4ElV)7z2H2gE2lEf-*r+Uh8U9P*=SY zRoyKHWRhQ)4q;YUAntiypm^av{!lM#w1Qar+C z_ilda6hKz=q2ck$C4~_%W3Yn9FaL4d?N7pl(TCm!=Uk?}g50T<6H~1QXqh*6ksEdl z`q0n+z~y9szL>JA!hoA@AfuUyK;gUP)Shk(&M{Z>EDUz}O(O>*^D7$C z5^CEn+T*<|<#3=64Yl}s>Xq>t2v!^Hi$eWl<_hYCsR@6khA=@54`ex^U%l|uY-^}3 z`s>ISExe-T)cQa4v!|?~cJx0-4pt1c(vv*%t@=;40^HGuhT6v+v#>;h!KLjr(F$sV zm)5zgq4wpQs3A;H!vk4D?V_V^_;+ileRVw6g@|9kk8`Kufb^r4~Fe>(Nb7-}9XsJ(r-=PTAw z+crQAVS*YS$P#M5J#eYt8fp*RJn}^g5VV}yKR@kItf7{^ZRB9ZP%Ayju2=v5;*vZ5 z|1mItFlwkZ_oH|j9BSaRkI~C-^qV0NNNDToe_rJ*2FXnJ=AbJ68(T+gt_muk-QA+t$@Q0!ogZ;q3_H@73HN=4JxC WS-~R?HVifl-M|*OWGS%i#sB~t%pDd0 literal 0 HcmV?d00001