From b63074546cb65e32c5b45556909a14e0a981b992 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Fri, 15 Aug 2025 09:51:30 -0700 Subject: [PATCH 1/7] updated emoji processor and workflows that use it updated README and example --- README.md | 19 +++++++++++++++ .../cover_letter_your_name.md | 5 ++++ src/shared/processors/emoji-processor.ts | 24 ++++++++++++------- workflows/blog/workflow.yml | 2 ++ workflows/job/workflow.yml | 3 +++ 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a4d95ba..07eb041 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,25 @@ wf format job collection_id --format pdf wf format job collection_id --format html ``` +### Emoji Processing + +The emoji processor converts shortcodes like `:rocket:` to Unicode emoji šŸš€. It uses GitHub's standard emoji names with convenient aliases for frequently used emojis. + +**Examples:** + +```markdown +Looking forward to working at DoorDash :takeout_box:! +This project is :fire: and I'm :thumbsup: about it! +More info available here :information_source: +``` + +**Naming Convention:** + +- **GitHub Standard Names** (preferred): `:rocket:`, `:fire:`, `:thumbsup:`, `:takeout_box:` +- **Convenient Aliases**: `:thumbs_up:` (alias for `:thumbsup:`), `:info:` (alias for `:information_source:`) + +The processor supports 100+ emojis covering tech, food, emotions, and professional contexts. For the complete list, see the [GitHub Emoji API](https://api.github.com/emojis). + ### Migration & Utilities ```bash diff --git a/example/job/submitted/test_corp_senior_developer_20250806/cover_letter_your_name.md b/example/job/submitted/test_corp_senior_developer_20250806/cover_letter_your_name.md index 03b3f0f..7eed9bb 100644 --- a/example/job/submitted/test_corp_senior_developer_20250806/cover_letter_your_name.md +++ b/example/job/submitted/test_corp_senior_developer_20250806/cover_letter_your_name.md @@ -62,3 +62,8 @@ Thank you for considering my application. I am excited about the possibility of _Attachments: Resume, Portfolio_ _Contact: [your.email@example.com](mailto:your.email@example.com) | (555) 123-4567_ _LinkedIn: [linkedin.com/in/yourname](https://linkedin.com/in/yourname) | GitHub: [github.com/yourusername](https://github.com/yourusername/)_ + + +Looking forward to helping DoorDash deliver amazing experiences :takeout_box: to customers everywhere! + + diff --git a/src/shared/processors/emoji-processor.ts b/src/shared/processors/emoji-processor.ts index 3657ae5..a556856 100644 --- a/src/shared/processors/emoji-processor.ts +++ b/src/shared/processors/emoji-processor.ts @@ -1,6 +1,11 @@ /** * Emoji processor * Converts emoji shortcodes like :rocket: to Unicode emoji šŸš€ + * + * Uses GitHub's standard emoji shortcode names as the primary mapping, + * with additional convenient aliases for frequently used emojis. + * + * Standard names source: https://api.github.com/emojis */ import * as fs from 'fs'; @@ -11,23 +16,28 @@ import { ProcessingResult, } from './base-processor.js'; -// Common emoji mappings +// GitHub standard emoji mappings with convenient aliases +// Priority: GitHub standard names first, then convenient aliases for frequently used emojis const EMOJI_MAP: Record = { + // === BASIC EMOJI (GitHub standard) === ':rocket:': 'šŸš€', ':star:': '⭐', ':fire:': 'šŸ”„', ':heart:': 'ā¤ļø', ':thumbsup:': 'šŸ‘', - ':thumbs_up:': 'šŸ‘', ':thumbsdown:': 'šŸ‘Ž', - ':thumbs_down:': 'šŸ‘Ž', ':warning:': 'āš ļø', + ':information_source:': 'ā„¹ļø', + ':gear:': 'āš™ļø', + + // === CONVENIENT ALIASES === + ':thumbs_up:': 'šŸ‘', // alias for :thumbsup: + ':thumbs_down:': 'šŸ‘Ž', // alias for :thumbsdown: + ':info:': 'ā„¹ļø', // alias for :information_source: ':check:': 'āœ…', ':white_check_mark:': 'āœ…', ':x:': 'āŒ', - ':info:': 'ā„¹ļø', ':lightbulb:': 'šŸ’”', - ':gear:': 'āš™ļø', ':folder:': 'šŸ“‚', ':file:': 'šŸ“„', ':link:': 'šŸ”—', @@ -77,6 +87,7 @@ const EMOJI_MAP: Record = { ':store:': 'šŸŖ', ':restaurant:': 'šŸ½ļø', ':pizza:': 'šŸ•', + ':takeout_box:': '🄔', ':coffee:': 'ā˜•', ':beer:': 'šŸŗ', ':wine:': 'šŸ·', @@ -154,9 +165,6 @@ const EMOJI_MAP: Record = { ':heavy_minus_sign:': 'āž–', ':smile:': '😊', ':electric_plug:': 'šŸ”Œ', - ':bulb:': 'šŸ’”', // Also mapped as :lightbulb: - ':mag:': 'šŸ”', // Also mapped as :search: - ':information_source:': 'ā„¹ļø', // Also mapped as :info: ':question:': 'ā“', ':exclamation:': 'ā—', }; diff --git a/workflows/blog/workflow.yml b/workflows/blog/workflow.yml index 1b440da..2679452 100644 --- a/workflows/blog/workflow.yml +++ b/workflows/blog/workflow.yml @@ -100,6 +100,8 @@ workflow: converter: "pandoc" formats: ["html"] processors: + - name: "emoji" + enabled: true # Enable emoji processing for blog posts - name: "mermaid" enabled: false # Disabled by default for blogs, can be enabled per collection config: diff --git a/workflows/job/workflow.yml b/workflows/job/workflow.yml index 9d64d9d..778a108 100644 --- a/workflows/job/workflow.yml +++ b/workflows/job/workflow.yml @@ -151,6 +151,9 @@ workflow: description: "Convert documents to various formats" converter: "pandoc" formats: ["docx", "html", "pdf"] + processors: + - name: "emoji" + enabled: true # Enable thoughtful emoji usage in job applications parameters: - name: "format" type: "enum" From f111a3b2812218d6b8ac85c502ddfa01bcf1b9d1 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 10:23:29 -0700 Subject: [PATCH 2/7] fixed job and presentation workflows to properly handle formatted output filenames --- README.md | 25 +-- example/.DS_Store | Bin 6148 -> 6148 bytes .../assets/architecture.png | Bin 26845 -> 57317 bytes .../assets/solution-overview.png | Bin 19169 -> 36599 bytes src/core/workflow-engine.ts | 161 +++++++++++++++++- src/shared/converters/base-converter.ts | 14 ++ workflows/job/workflow.yml | 7 +- workflows/presentation/workflow.yml | 23 +-- 8 files changed, 189 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 07eb041..6a7b791 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Tests](https://img.shields.io/badge/Tests-145%20passing-brightgreen)](https://github.com/nickhart/markdown-workflow/actions/workflows/ci.yml) [![Node.js](https://img.shields.io/badge/Node.js-20+-brightgreen)](https://nodejs.org/) [![pnpm](https://img.shields.io/badge/pnpm-10+-blue)](https://pnpm.io/) +[![Turbo](https://img.shields.io/badge/Turbo-2+-red)](https://turbo.build/) [![TypeScript](https://img.shields.io/badge/TypeScript-5+-blue)](https://www.typescriptlang.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -99,8 +100,9 @@ Available processors: ### Prerequisites - Node.js 20+ -- pnpm (recommended) or npm +- pnpm (for package management) - pandoc (for document formatting) +- turbo (for monorepo build orchestration) ### Installation @@ -110,7 +112,7 @@ Available processors: git clone https://github.com/yourusername/markdown-workflow.git cd markdown-workflow pnpm install -pnpm cli:build +turbo cli:build # CLI is now available at dist/cli/index.js # Use with: node dist/cli/index.js @@ -325,25 +327,24 @@ rejected rejected rejected rejected declined ```bash pnpm install # Install dependencies -pnpm cli:build # Build CLI (cached with TurboRepo) -pnpm test # Run unit tests -pnpm test:e2e:snapshots # Run E2E snapshot tests +turbo cli:build # Build CLI (cached with TurboRepo) +turbo test # Run unit tests +turbo test:e2e:snapshots # Run E2E snapshot tests ``` ### Quality Assurance Commands ```bash # Quick validation (essential checks only) -pnpm preflight # Build + unit tests + lint + format check +turbo preflight # Build + unit tests + lint + format check # Comprehensive validation (includes E2E tests) -pnpm preflight:full # Build + unit tests + lint + format check + E2E snapshots -turbo preflight:full # Same as above, runs via Turbo +turbo preflight:full # Build + unit tests + lint + format check + E2E snapshots # Individual quality checks -pnpm lint # ESLint code quality -pnpm format:check # Prettier formatting check -pnpm format # Auto-fix formatting issues +turbo lint # ESLint code quality +turbo format:check # Prettier formatting check +turbo format # Auto-fix formatting issues ``` ### Testing @@ -415,7 +416,7 @@ Get AI-powered code reviews on your pull requests using Claude: 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality -4. Run quality checks: `pnpm preflight:full` (includes all tests, linting, and formatting) +4. Run quality checks: `turbo preflight:full` (includes all tests, linting, and formatting) 5. Submit a pull request 6. _Optional_: Request AI review with `/claude-review` for additional feedback diff --git a/example/.DS_Store b/example/.DS_Store index 2a8035ad49a562aec64731957118e9f08730369a..5b8faf153c07aa76e1e3fde69c143cce2b47f0c2 100644 GIT binary patch delta 187 zcmZoMXfc=|#>B!ku~2NHo}wrV0|Nsi1A_nqLpDPSLq0<}Lmq?fW<}=Z%$gu6AqG8$ zT!uu3B4lZxqI|GO8bc09%VZ6v1`b0LBOL`}L&M1%nCuOS(pDB+l$VpAmkx5lW*(;7 hOqB)qu~2NHo}wrd0|Nsi1A_nqLn=caLkUA75NB>IT+TSzK!jzpKI;vp kjSULSo7p+|Ie?lr3vzsCp3E=e$N|&_(#NtnLSzjy02Qne`2YX_ diff --git a/example/presentation/draft/test_mermaid_presentation_20250731/assets/architecture.png b/example/presentation/draft/test_mermaid_presentation_20250731/assets/architecture.png index fa80a66d9fbe68dade2ea1ed0cbcc906ca70ad5f..9ef48aa56ef142241ba69b1461643e0b3c2ee61e 100644 GIT binary patch literal 57317 zcmeFZcQl;ezc2ozA`&H95-mbV2!cc}i3HJwD48)t@10RbOAtv!iyk$R5WSAhgbELeRMm2)aN|dKP@sB9o^CE@xac6=b3OE~Z5Yx(O*hef+{BX$6P!?%FwN-XN5P z*fE$3F^*gle$bKd?Ae`9N%`~GkBt-NkIDoRR8FViFJ3ml2d>Z^ zd(xrP&&Gka;POa7Rv28;uCXzKi^j)@E8ucRzU3mg(6XDJ1D6lf#b>~!>3{Q>iUt0x zzXD8NUe?;W0-Xb1-ZC~;sb9G?kbm~hoj}{0{5?IyFxFIaJU19>bJKb}yZ@ez?ipHI zSz$+qu(15uHtjMb9i*XRYM#N#6%4Dsl=h0c_%&*4+jihv>rHSg)b!NVb>jF)C>L=- zqtIi68cgY5nC?L9MM$rCe=DxsVVo=QhsKw~M29+KyfgIZHV}Z`Fh<6)E&4m5w?y;% z2bshBB@;Z{Df#+jh8W*!ss)x9~&EKZFDyZ-vqF)tk~ApO64I) zq3EX_trz{LIB!n;`T3faupr>IHulH{dltG)%RU4}#C=zm;nU6Uz;(s)A+jCYEBSMD z9mM>OKb#8dYABGpXBHe=ZaY-{7VL_1lPfiJ=g!@`SsNSg<ze0`;d6>7(Ny1NyQfr4QrjZ&qV zA9$>D@ETQDh(5Gkn8)M4xan2zmh;!Oe2<@)Amue`m$1ov^CsVZtfu|zN%{D(abzJF z$;HX3iWp7>eK;pyeC8&<6sk@)J9<_o28k?_IjLFa(qWzPIWqIpCrwV3 zJ=u(X%!xGp)vGUStKz7PXIi9X-_`jvw=S|idAq&PJ0Fx(-qzC6ha7QocTav`rPm&N zWwv>JeW5ifE=8J|BXF={BRq^b)pDRiW}exL;OqO-KMtYaM$X2ExWxR>x~gN@(64q8 zjZNwO>;3H6%%|Hn=p6Gd?*c^i91@9iZccR{PmY}LW`RE3|7W29IcTl5ymNo~7J{c>eMy<)aDxl(Oy9Zpi+FZuY?;&2Ev z2~JM7`P-g@rFSJ(DOpBqm15fHEtr{B(0`Jay+($WlRoR@-LSzA4lWl{)4IBi*R9|j z-%{XTrpwcXrljPAtRv)_QBsPCDY8pTZ%EfEmCejB4rgpoQwuPPtac2|r~1j7 zKFR-+i5+LZlGt6O_UzfGP~|vTbU*=SZ1$MvyuY#kKW0;}N6av>$HTL7-s^Cw-*ISt zy~PJ7uB&U2$4p0ul3^Pes!X!I7P_y86zAa3w6S?I?Ag**<<=cxSNHW@*~PM5R8XAm zZQ<=R8h=mM@uF=%_8Tp0s#M+bOf+ir0V}`yvu9oC@F4x*ji67uL}MuS7mmRO}zVP}PterS&qe*67z^b!e_~SsCT0 zY2MKq&v0J0wcSKAh!$~JeGv+(9~pVV_t&CmKSUm7ct2c>OR4Y2vKB0 zetco!j~diimD!!N8_-YKseK4~teo`v^}LW!i8JyK{nVdjW_14si>9WgQddAqiu={W z*XJ%&;EnsUhn8bGI5YHXu4y__0v}BU{QRXS)4$zJ*?D<=u=&5}EvBbwfaBpE370WA zVN3n4N=il%*5Rp>*^9R9c~pkY9pY@pk~f%y_x~9tXE@e)q<+RW+|GsD*Y!w`d99#AzUu21#?!&~hur6|G3m{@4ln@YJ)3VE0caDfT8wnRE? z9W0{j)53P2rFZp0ZLm}BYtmos%ExMnCDPK`tecPRMug$jyCOrYz4O1ilHntRgNJK= z3~1a$jxNEAfU6^?&y6)AB)d!J0bAIdnVpxXs;9S|r8R_sY7Ul!c9yZe6$PUTBSBm@ zCo~@Y{9@jD$fKJdA02I6CqW6(%7BpR4u{+FfPUet(Y+1BmS?pNhH1i-@TIY%A@^}S zah=k7pyQ-+e)#a1D82909CkFE)zNXU(#5pEpc_|{P-on9(ev zw3b^}5`jwjD^4A5aYZH8*kGpD$9_ z{Ny}U(%S_b4|mbuitavBa)!xGkHPTlMyR^~2`lOULgpF)5Kl zcMNPx^D3bkTBe%)y$!3ny5!FfuAAav8l#O(2n>>Utf!|A_OM&?yAoX^yP%+8KmdDj zvAy;Wjj_(WH*#;V*Dk+(_bwisZaVI0!n$KSkq}5?{@?~XyUEnlRUU2Uycex#|CBek z*u=#hPmZq}7~tXP&t`a-|Cxo@M^LL^yDx3&r^RV~E< zhmT}yO92ylXMyC*&vgIATOcg_FAZ(~XGEM)f;TboTkd)oXLtOADdGWn$LAax9 zSR1O~5424?58`ZDQX_U-+g!vYe{TV@C`D45limv-F3SpQO!e6>>z6;d0OHu2tXCTZ zck@0LgK&5Awb*}oDE^;};Qx<2_K#5gjqixxI{YicAX{Ki?C!XoZ;<|3otLtJdw}l} zbcvFU@e#G-;rg+hkW37|V89;f=-PoEA@IbWw;ksW^vE>`*yuH9un(nN$Xvthbp1Vw`!E;Ds5aco+{I^TDXTCihs`DZ4 z;;L}Z6k~DuT#aeEAal^%l+4^d>PtNnJT4 zJhZZ#_039Bv!pL{=O!>j8i%)U8=SaJSNVg3SoM&dEJ>q3ms;)^6R>z@ zrVdn!ByunD_Er#8zWr*H1;4oG%6f`S8LL!haG7nCLG$27)e|qP2A& zslMV$5C(XhdUgMI@_D2^aW>V(qTxxvEVV*yU6@~bri9dZ#*vUa(F&Ni@p4;97s2(m zCi2ZI&lPHqi>h{x7$5qS*@$FrcF`ZDv$G55@9#Dw^ggFH+I;6=hk>~*?JR6%*vOR= zkCh>R5`~tF8XXArcdSwiS9lGS!G4qc*S$Afjt z1VjELDLY><6RkCj)T@p_^%3L>NBFnQ?^Z=S+7Z{PFUzy@_eBD~Xnwnhv88?#ha4r*e#@l>clvm~BUlo-qx{AlUnnBDT(^5G8pDn>zAG}n~YfXM&I5N6cRLr7w}KRN4onv5faPr5p|+g zz3twBsbJ^l!${AD-8{T*Z$W;#0l$nv$cLo$Rd`P%wOELvno{3YWT#*Aj)WxP4I<1m z_pWw!=|KL9cK>1YzB{!nlSHWlP;>gYRG^NvUwk@gkgAv}*f)CFXg<5ONzeH*a1h2M zjZiup`P1VXC=DRFxGf8&K^n($>obq&Kte)m0VLDd^Q0L6vI(_YtZmj78^hC?r~jb* zc?mtNyW`_!I}D?)2w`$fy>B2PER57p)FoS`N}|lxYcq>thf$<`$B8Dh+h(8`O?7K; zv+2@O#_ec#HoSDBNy!2DbcFzUp%`@TG>{aAx?$9vE1#|2WcXlHjFS?|1OC&>&$ z=^8vF$I4QboNq$|Nv*ZH(u}`Q~Rh7;c{UZ2gW2nQzllp7)hD>oN|he4x3- zHT*HuIpEOZ|5V!O=;(B-<(Z`}hUoNdI9NJOZt)Wi&5o?QxyR1E z4b9%yLy#yar1yA;uP?mmmWjlW`c&K2YcWgML}`OvqVG=0Kpg-6X@oOa*2;cySB(8| zrsv6W9lXb4qR@G^y`6&Eh%G0MKNc^(!&obX^rl-|+MLdsR+#e>R+Ki|Sh1qV zA5G8Q=>qR7ec7O1>I37nWqazD`Z=`=K8#08!@5!P;YnRgDXwlELITbt6A`ddpF ztft3De2*1p=8n{*$SETaj2@1C-6SXhLBS6%aVW&JPs*iLmG`ugj%*sO9$gE^G-6{#;s188&Ir% z1L@sRLg8$XDqLF3Vu%|rayz}J!gSZ77!MzD0EZ0LKrj2idce4C^!BjU?%MIzar;Go zl1IP}C5efOTYGN*Oo6sq2ZV)%=X(9zkE?^)YacZ%aMvVXZhW?CG+7dyn+?pP$WMpRQ&kLmItrqhxZ@)%=0OI z2mv6(g}eS()hfXWb+;ld*JqhTASec8Luv7-;~4CK@7DJuYsnhF?t1odhofyFda@OH z=VD<8BJ4%u8eDj`MtyzO&y<~wPZ${e#QJ*=E&q=G{+)3X)9hDqC=nxxVQjHsAOEgA zGVe{&BkQ5(*cA}ouU+Uq4XjEy%OK-*7JBL%-aLU{Ms*7$^vl~o`xEgabDZfesg_UCc(3kuY-g#ya}@n*aHf$ z3>y)<)yGdg-VGRz&`DC3+nb4fI0;-)VllX&K}5v3w50^uw$0z_9cBz{ReW#A8=v5A zfzMM4O*be|<@dbLrptd)XuP=bi`Yr|+3&$<)osR}$jRZyTUhlqPRSXy7K1uRl$vI}2FE>Wa_ zfdZaLa)_0{S`D~QPg;rDWw=@qNl^K&v&MfE*e_Z|4nHq&=*yKOs&x}ZtUs5O>~C`B z)8Sl@g;dw+ox7z!bC30}VuT<`=+tfrlsho4B9$1=qcyT$WSuY`s>Q{j>~V!i;N@oO zZJtN6)@{u-I1E&4XX}^gi{)*7)t0H!-E2vR5=ZGr?{FvaRJ6Spz^8cH55|XYuIh6) zm(B%8CPWH2ZNrBzN7S?bMtUFLMiE!~j>rDg4eLmJ+KtVoy2XpnC<|=CMIX7lVroj- zH{IZyt4YnD1E930)W_-<{6D3uBnZObtA+77g?@x5cfYrr=?|g5j`$m;(|gzIz$e6{ zc=2(pm^dDD5cD)R4@rp5Y;espy2(AeG7c-IreTgDU`yQ{TilN7NRXD}hOma?h2EFl zn7>-egO!`vUKWL7yRa85Qn%M`)D^S&g|rZJq&lh-AxD{0#emdHYTS1F-s=-bpQ#P( z3Kh&vqsrmhgslCcLw+=tzB^g^ZlGhqN|qa`q_YNMa==yS;lugIyzdP}QQ~aUe*CJ^ z-+TdR?e0CQ<*ZHk+x!7*cU0h@F?{{?NFvcEMpqf_xYL8H+owIL= zk>EWsE)%wjbtCK!eLhpR% zqW6_UL6poI%9P7%#6st5;k5erSFlz<(F)}+VQJzW%3{DR1&_d`ToFd zm5{Bq;({KWB*_RN^-d6CNP80hH$T5UfaHE9u6>mDTq#VlPfUsyJ({L8eOi~`^#ncz zyCLP9oih|WSM6@Etfr(di5dn8%$|t#r-VqWx>x$`!s_kvz&9NQhr-Y+ z3=wPA4{dGj(r-2JCyCvzcJtbZ@y0vpwIsDkV6(=b>7ZV9=f5lb1M_v8o;FrzmN=}R zS#+*W@_nMfB2l4!{0C_}v`t9G5Jha4mgZuUqFpx{US3D)@}-D)4#=X>5ADY^N4C5> zBBVRv=#8xX!T$CWCW(q}?>@2hmiol3tj)aUr8=~MXYE?|vQ9f@yZbjr7Y)0T3JV_^ z8j=ePGN^IXG5DJ^{z_NGeP4L~HRh}-y$p(b9e=WHfN?5OVo7-mFF%c$PaYQu+Ny(?OTcf{w_Ciy$;M;qoyr()E1tG+wU3xAr6=Gi5Q?rzY~#*HA?+uG=hwCGC<% z*zFu52z1fm2t!Xi+BcvyJT9PXZESxef84MCY8lln!9$sV^zbyWIcex81qKv@b=vvV zEYzQ+L=j!BR>0Nudt0}KgE+RC0zXo;GyeqTZu6^kl1(>8z5K`X5@dJXIdt&qmBGrT z_8`vmBHFAk<*fG7)y;%gVfZo@KjrO zi{;K!$89@aHQzmszWWFaG{@t3?$H_0ExIGPBw}B-5}ew}9#_dVTxPg?#JLrHFYa}s zB&vtTZUpWcoA^OJxukKd{;|Z5-bI5o8Pnqrtl%N@9?WO;&MyAigZ|-8yo8j4@94mQ zTJ>&yT{QAbax%_u^>9rg8Nug1&^4#8URb5xS!tNpRf$qw3XPWV@wVyQ->e1^RNI+X zs-6~c@~3fv*XZAV#?JE6(vo&xrLp$ci3Re;8*bmQL`qMKmGfKdVO~BUPP?a9S#|uZFaiw*Jd+2ajzX7bM=m&%(!gPnal(% z?TM@mxlfcQ`WEc0Z3;pfj*-i818xqI_;)u(D(8i3L9}~Et=qDWx2=kj^Vc3rSC@j7DVPA3 z_J_c=%OFRx|HdI9q3f8l@|;%JJEWGLnU%rBVQpe*&R}e4*1o!K{F!1UJ)M!@4XJDo znHl>qLMv#Q1qPX#f75l%dGY0IqNfqqEf6A7goV*lzZAR?D$w)%J$4$8XXdWbb>?16 zBIxXbJQ~~qoR>aN6nn=8{qm zvHK!4I5=4G!qF{j!s{dsh_LNf&WGT*S^Br`>Aj2D9=e$Duy8&?8_R0U*08n$_x#L@ zt}G1&q?za8P8r_LC{8}3j0D>$MUK)r+$!Ra>8mMr2d;{hF|Bs&R z|B;H$zuGwdFPUWT%W4P;0tHE!*Qa_=k826;c#w`(h9W?{HmyqsOZ^hb9nrLQeaO`VoBZ*I@#BF^{|!8(+v7~ChP>`n088X8l7 z)q)!3bUbszGr9cQp;u-#d!#`8|8k%Fe_1Xahl|?3V*&o-t@i)r760!sunYeJ3gEv2 z>+ql4fK!MB1nm#xzNCz5v zL1z`*C1}*nktc9si9h|@Ez@(4dW1Y2-P3zarS+3}qFPN&OnQsWel=v1LlLJi0y*{h zt~>-H+0M>xEukcc>Q^v74(ku+!PZsAVpX5Wee^lz<7rOD%ue+Cqi&r(+p` zu^f?n7B)8f;gzkXUPL@L?*%P%+S8Lu2naYDalqIM;$8~D^Fwi8p0s=ISi`Etp*xiz zYSt*N-J9yQx90;AniE5T25%mM0gARft;G(zisL|A|D$|VXlQ7wX>myjzAx)xNzs{~ zRi{tR)NX5{92_X&a7MPk9?Kho--6LRXZ=5^o$k&=*vG_MQvJhnw2DZFZ4Z;hzizVc zK+{rG%!Bi{UiH^o&vb`hbT$13Cgu(&cpD4b$%unw6?;KmgOhuwf&G9ADcfb^&W|Gl zd>PNO^>G=*J7A>`Pwy0?FvBx#BLN)dc8guW;_n?e`1Mf{ND$XsvTz-h1~v>fy05R! zc)8AX75qBwFBk_gu>Rj{;{Q1>X?m?KEiG+rHEul1yZDi?u!CZ=_MyQ+z3MyABO?G$ z@<03Ki>^ZGQff*{?AD8>536}Fw9Uxwb-xq&^Y+jkw$oPWB~wrx{|t&P8yiLN^5X}{ zm5FYdlRHvUwSSb`Vhmw&wCKm89h8 z@&g=2-ThQj=v5UdbVujA(nDR{a-|qa>;6rf@#9LXUU~{9QCW#<2Sb1DoO2NE#nZ!4 zks?JD6JIiuxOHpW9{2a}->GR6RZcCoSfp+%r~|ymZlPj&EI)?Unm1+5L+kHO-%Web zaD3RJJLRfuW8+hJQkCo7g*d~3ix-kZKVGJh6%}9d@v#xH?yFG<_obkqn3H1QOY)uT zAY*H6=O?WGoiz&~9&UA4in(x-v#sFq4E)EBNdaz1*sKk8_pTx=wLSo4iD!{IkS4B> z(~F3CZY~Vu$t278iQm2ZoPK&*E5~z-%h0#7Tu$Ki>tM{GbH2W`*}?X0@ZsE9UkTR* zhyAk)gmDKK_kzPeG61TReR>?P3coU>1=ez~ zT#!t|)wR8m^*#9mC}xtA)642(SW>sBMI18PO6JOoMU9UI1Oz5A$-S5(lS^jKD>7Qy0Gowa#0bMWv|l9Cjo{&EM>gJ2DY&G zxT31cs#%q@*CN%&5>%u6H**lx`NHkD#l<&|2*FR~v zr`KMcA_gMrUy1r2{yE&&LbD^P&D94hki1L5tg-E7!NFLIRNmdqHkO&OGP~)oazdu4 zohAO}u;jy6>V(bgDvu4y<}l_YQKxT`w=yGVN^P)6JF;j1nsEE+@7@;Ua#a@O)FP<|{)aPI?hKB)2r=%jF+&xq=%6!>XTZB<% zJvK=99x9qRf05;ro4EKA$>nP)B~LQd_{AlvTaX?e&$=iAE{1+0V}x#QINXA0MHLi| zR)*R;N&Gvp*Q{_=Pr8)#5je1U)vkA+)vf8J%?1VPM_xgpi2nX|p6=i*cX<}t<1Sv% zx&d4wa4H(M+Y8}2FS2425{i6}%1?-fY5Jh2GcBX6U|3C`g~p9?&w8a^q8kk)y(;@u z{w;%LJy?k;J2)AM@d8t2yFh2Av{X-Kq3We&YJM$>A`5CYg(EyT1 zz!L|S`VHH5_JnQqaGBk&Jlnj3s!K}~EBQRQ$^)onX}9zF`1tZSUjkg-bunk}v1H{q zK15m*^l0Pf=}Xd9aVOpF?eH?p$uSQ;uf8ot3N1~a*kDL@3eeyiH%#kil(?bSt5C>;l~eBJ9l}zxAIw< zL+LGKWKLrIAYUWo&d+uBC6NFmMn8A!P8Z~VcpA;rTMrfv33a>1;7csjk2abMWJyU# zg1vTbv<1M+axp%{vL@}3GP^&+ZcC;GxG#A{%(Sk*jqi_GKCs6fq_>0`7|PqsSDBgA zdWDwm#u;{X&J)f-GjD)8U$CF}8997BW9TbJIM_MQ7Fc%6&DC}0a6i@D%*^V@k7(DM zp=x7V?L(X|MW2*2Ovb-W*r4W$Q_$_%vMfmMv~gx&pXrqu?uZ<8f3 z9F(g##zM=Uk9~cN!?)$rod8(Ep{D0HmJTFkl~YX$0Eo!PM>poRT)V#|6VtxWYbfnE zT4A-bEMgB1UnDzmrYsCtH{0Ru_kw0^DH85Wz}yX^hmRl1z7w_+&)2WiuxBa(17MDa zpXYscfDLzo-y)lP+vD7K2@V`>f)-tuwsbkb=q!>R(YqU9wwR+bMdiWaZ_!C_ zDOoeo0RjALgGIORuNP9uChj8glX|xomC>Cey}i9*Ohbebhs52rabAE~yY*n(8U};e zmy(H?j7&EiB?JQWmR>n|>ec zFv3UY_va0hrG4H92gmK#&vn9i;bnZ`5r}m8&ZZE*mP#c>YwHgKyBk>myhQLJ)@cL# zEhpgIxmJKVep!H>KWr06WK~NsKuY%*(aVp{G^seQ&rLUH?jInn|C&aiZSGQstv+DE z8Cn17LZ3!uSj|B}AtCl#vJSX5XLrI6jryIGqo}B;uj%Zdyir{poMY2O^j1<)an;xV zSX=u9#2{T=d?0YIL{>Yo12@oM`M}H5GcFLvRG?t7dMIAw?3TEiehtNaxu@qfkga)`}T0Txi6Zx!$HKbI+Uj`mgzjZG)I^NKyys- ze-NDgpG;W(8$R|=A)wIp?)|${sV`3B=|;zPQ~XtkRs>k_@T6_V@?MA0Q=B;@DJm=M zukh@M%g&qeeklG-=yd?}5H#PIdJoV>xd`RR7ugS{hoERs#PbLgjYT`%v%%l`kegWk zHR|uJWbPaKQn?7F=Vm4#YoKNQc?6B1fw-)+r{{QkX^haiuLOB9*TMV!@`ARYQydz&lx-)I37EXBovRJTMu+>O76 zf^yqGdFD)0KiVjY6Wo5m(U6Hrhct3xO{N2f8yZGK1f4QlI-5A)vSfuL7`QTTsHr{t z=RTzv82?jQv^7Ff3LyB&p=j6tilWZ{tH}JfsmT1R8vFl`BJ&>~4R_@JFyZpcmm-&n zuR%Wpgc3f=zRS&>=}=KP<&(%gTKqd}Yr9GPcI!4Pq1N|kbQO1w{09Z}^NErwo$NcA zla=WeTN6ACN+Y!#KW5a$UcBJCC`pItBopRU7$%1^F z`d>XSdXMoOWKej19+Ya=kq%6m&sk$Cs)l)P5E9H513w+efRpDp_9{H zhdiat*~9(zk@7Vf*%v=FjypvRi;!Z_`W+BC+_`(O%j|x97?actC^&~lHh^_elbWi| z7U#NUeo*B$Vn&S76{nAh@R?QGJJ=ZsqFP~We}4)XH9Ic|TSAsj0z-hKbRmGb!nB0(i1K7KDzq?aY_ zo3~G7W8=);-qR?3vI~$S|0zJ&Y5KQn9)8uJ{xG`!)gb1ivCPgdRmShOu<&CRS0^Xy zp0D+c4z77x%>;Xbii*ndWU$@i$GY7~l^pY5EB;}B5c;$_#og@@AkM8(uJRUhooWmM zt&Sk7D~!^@PE+tXi%|J#e$4rmF`vf6x$DkFvBQe%+GH90xPb#%)sG^-{QZ|`lC(2K-@Jd<8ES-hdQ7a`%c zW9^}*=j!PA6rk3BhbB50XoJyM{g_S#Co=90D=~ivPv`TQ_6AHEP^*vz3!RdE6^!KJBrE1k&5MC4yyaj72=T>(%|! z-ANJ~Z=+C-%}tc?OBy)Yoc%+`BisU}B5F6>0$}#TgM%$j8+IeRr}s9#cW7m={48Xl z{c1vNC`H`uX}Y{yM>n5dA&dvLGI$18EyLrUtD;)F-$1_B;>llMPd)BaZuTc_Rm@=w z$bpRJtp^I#W;H~^>FqSrauP@d2m<#wIEua8_=k8oIGkHQp@+4FEb6fN2p0(n3AV=L zqt|P764P~lgOG--z^5x|97=$Er9LQ2>fq2lGxH*#{#8%O^K@|=Y*z|k=7g(jU$+1) zG;jpHc9w2QoWGcY6$fzG#a>-&R%~v<5MaCUs!NCty048{0aBWKBE%awSZFk#q3YLi z3YSMN{v9}6iDW++soLQmN_n_kYfxKdiE4=Bh5zpFf4RIr8z(d8t+8E?tbV=q z9kz|=%?#jFg>839^g8pM)2v4BB#A8cEh-KHhMBr*r?122QvW)*#}oxbsGZ|AlT&EY z+|`kkklb^+lM8=R=$U;_d{S*ot@|r{h_RmIyquh4Q!P>I!e!Ld*e)>8jF&F`*r={*7hWShM5AT_LZ_Y*eM4hoV} z|6Hn9w&T?dbgu}FW+DM2b2D05EdowYsi;kz{0FLA930usvnc*^Q;>^dMmX66h?BUieXJm6(3z69KLSi|mS z_BODU)kr&wI@mjT##Z0Gm~S#fTTd^qxBHO`3l-kDdT%<6td`)oPy~*zT=c$-V>pPH-?mCaoX=&mT>GJo}zzd}*{2-8Ab^v+>x{vhQ~&xuoRi z3@VmVBcKv^jIC9TY}ym*GybFC*g!*qLM7N(H8r)E&``z_h6BJB!W=Bo*a_5C_l!}0 z3{|b@9=dUZfgv-7C$r3UNCP$Qw6nxJ%wb!3?OmCQn~KVtfPmU2)|ZL3K34kzhUy~o z_~fHHb3MHmV^U~OK?ouTj+ILG-H#u7cEoGE?W;JHzOdKsimQxrP<(em%Uahvm$@2# zE)T%r`9$xMsY-0~)~;`6$zfw8?p^>cSi+Ei@zc&RU-OBIk9XcMes)Ic0`x%yl)_1) zS|7Nta^p=#$~y0f>*acL1y&&OU1vRkn=(r`S9PeBMtN2bm0&tsS~~V~L1;0rUq9?E z{I1q#5mb6xkQ#sbuQ0CW-uj#SQVPG9VAV zaiayWN-8Wp%giICR@@`7(Zks|#2kBbrW)d!=(-6$T{w88HEZR^^P!R-CMGm*FYiA^ zz1I+ToOl|}k`6pqs=IdQ=Y0%lP!&s^PCTah)P@9%3R&bIE@m>%O^*szV~%z+_mi`X zzxW;v=fN%bZJqbl7oDc(5SWy2$)TaDgQbhz!Id&l^!b{SvuTZyBiVqgIXg;tPFmzR zsW62Q`x>>RLxanclu9VtRyO9+92*H~C@B)c~e&uE=^=eWQ zAXbJla*O~ix_F-HlbzoQOvwCW59jx%^1oLGi~P3c5Wtc5nSXgIH|tP@N%Hp2?n>CI z+ofe|+?ciiC9Wq87yXG(0WwW+HSTh*X@D(qk|h_;c~qRPb?&21BPg`L2{N&b)Q`46P?>SLJ<(#7Nzd zNPhm6OAFM8a59LHft47@noeBK`ap-+9DH2sy7<@m4~&;2`0wH(y>i^BTO-FBx^}H~ zV4%!eJDm8ko(f7cI_+6W0R=Ao*d^@wiTWix;yk2bdD<4*zRa|j4bV+Axh{Y=ecHm_ z`v5^F072;gHPcuw4r{pfi6BY!Pxo6Z@AG`GdikBkzw0L}I17C(3)bHoG>;N4UHb5D zs_aG91h?8KipM_W+z-?X`0`kZc8(j*YEVVqx#b@@_E|4V`||vM_)onGp7C_@4!e8v zEQ{#JaY8QxSF7Tt`aSpj(Ml4C^fYbA0v%|RS7|4$t;^>wx*m533_<>vZ-NST*o)F1 zW+P=+Wa!hH>{pDNa$%)E5@)}kfxt>4OgueY6`dAsTHjIo=s5uj;prNZvh|8?NqLph z6Z6~(7^;i#E4H5>=A`SpK@piCP`F95+?$#F`nB(e0Qrj)E59v42jUWFvpe7C$&pnQ zFG0id>gwuheG=$-m+m5%p&7*K{Dv-GUa+-{HzeEuA^Yl>TqTg$>GzYD=pVSa+2w0y zmBR9La_GuEYzNnEzAvBkmpsJ_h#90xM93CV2gaYp?y5!^R+Ft#ao-#avH~yZ65Skqvb;A$E4NMUBx`r z7%8PfZXJ3-6X$>l-cdNUH$5LOPDzL&`mTBCvSpO?*@e*Vz1ZJ7=o%rh9 z6O)78h<4_&j4+RU)nD(SO@I^d@6h}yYi9b@mHH89?|cC5Bc=F%kT)&=mQMd)cu8I7 zSg`VF%qdOE(#bI~nf{t?^5BN*9QFd#Qg=BT{D+TXbbS1v^tomom)ug1)xhv%8v5hn zkdb!_3)gTwswyAz?vaa$4eC1WeKo=r@ZP(`S&6N7f1Z4BnISwgoYkPY(i*lT=C^UM zz2Dw69U!4|jgj&D$-^^{AT!WGO_$A%riF$0Erx>NAj~~uZP6x|QkdPRKweT=SJ#fH zg?O&V>Xa-}50~d-d{D?6gBbYn;r@4;zNJRp$bzQn_`$&k12oJu>^L6KwtZ4S21P7h z10C3`A)oblk9A^}jLf`~Fn&6jfWySYiG?c|p>+Uj-JiyghA6Kl^#n>Y-ZUwNsu2Qcv(9ng`1=G{e z5EIu}tFTOBzMSX6r-#4DEzezPoCZQDT#pl^i?@IO{(W~!uoQ}go|QG#v-_(~&Xd&I zmY-UIK^X6&1G_oe3((8Z$y-oFF-;~vXF^xS$$IPL_-<<)zo8dvwt0U+*x|8s8io{Q zrIq``+st>kWZtNnlBs&iUF$~0Ez&pX0X|3K{V1fBjpd#Z-(1>ShJ4LO+VfvBZ4$fi zpSk?*pkY#ueSIPh<796pCI`@RQC@#lpFi(mEW`Kv&{uzI;)&(K52Qc2P28-ayt;o7 zI{&V9YGd<)7Em1|vncZT?@mN!cM}hP>UIwn8%MN*{O`#DGZl>&pWtEn$a;hym9uH| zT?o;&ujtE57z=KTTYF++WAI01Ku~6KB2r7p7nXA9b>jc%#Q$f2!iiqdDPeM*a(aQQt?F-5q{+Oz zrnZ9&5F->Uf3#qB_obyLC#PR+>`hKjD3-)NTmDY^Mk6PKhK%tM-%m$s=vjR-it;KS7YN~W20Wx9>>CBF?!@%h#mYvbbg$< z_ma5N!B>x0hDEkRe{VOLoFu+ZVdqpPtBwe&Ob@6WHSM3HZD%|ia`8{x&qx5b)1Rz_)}_>eD;D0W3_0=w3J$M?KbzO8yopnsZ3vh z!sEnRLP)cjQq2APEq~vZTgNCp%oZO#CLC8hPjO4ifyFb>o}cWAim=*>{U9(*XsjGV zjQH%!i9M#`9s(Lt)>lgse&MmG>q>Y5w{D*g*lb>(X3O#HA`dD?MvB|ko{XT&uS)&iu;3wkZgBF|cv(U@e zDYnovZgFw*`7!pXBGHw>%BpnNoW4Y&A{iN3u=mNe-Crt;pJP>*+Yu|7s*EBl5rpi4 zPR4g+aH_z+$g-`But+u18lq7@EtZ0}F+hsMFZ}&}H@z6vVf53*ED>bZZ5G?nx;4c= zT1DaBom1B}8|cq}F(pf!CC?b7FQ@1CS`$k$_ROJIrKzsHa`|$$n2vcassHFH7(p>v z(nV1`AJMBwbshlZGOjGY!!n6FZ%(_@(esV3;{q#9IJ?#aUb#k59A$RGIYZM63-rny zy2BFmQI|fvWVjn|d(#7G;a~aHzaO7GruuwzVs`0`vuA1p&`i+N10n&}9U3O|C zB>)pbl46gD3J(+z6m(si=4Kf`Cird+k9xUwOj)Ht5f4u-l%k>*i$tltv8m}D7Ln{V z@2TwzkEzbCNmdXhoc4>qYt|Hqj_~jAlr`m9sNRTaGLdr)l14c#3@$c5R%ewW^E|%w z^+oHHi2X797;P?1ac3uasr}d^CPtTumR6lk{l?|#>1n@{>7$gmyc56KWvs(@v5Orq->P=FzuT~ePc4M$L7KvcFO|x~IlA^Zog5loayTuIwRT6g8)k!0!q;w!6fB0P~sr+m`W|lQ|4+dnBZSy zZ}m4%dJTZ3EeevW=g^(g%C}*K1nKe^A#W;X=IN5PA0DE@OS?F?$4x2sxGfIo#cFN>&o} z&*(i93l?#tcvD1j-qSi?_Aqva^IvqaW$D4Y>eI|{5u2NDR~U?_eUHo2kH;qwEe-na zv~CHSx4%sTCsM_5=4QBw8#T1|==0{DVjWjkt>+eBRQtYu6=R$CNI86XO|SHw*^&4f ziNVPnF?j90%al{_K&V^XAdmf)kx_&UKe6?>AT)FJ)Kj9Wv{+D8WmaQ93^rX>r9B>4 zOj>X3^;IeZH`h6QqnB&S?3-(n>5)~Q4&&7W-{+A}RgE`^NK4$_XpqgDoA07-%1vcY zUOjj2-29EOxPpE1H-(+^u($SK1Xh} zbxwKLkB1$9v2CI7VbQtCePB`!drAKZDa~+xawY*7Ug4|ZK+7$7^=^l9^x$?7n%K(E zU`tm!S~ks;weRSPw_3?uW}O&z|K=g-HC2-(L*bUcVKkj$(funn4`===O~!6?{bQXH z)Dj7T>zkx+sAy<-R6TP|4W*j`d3SNb4lmq6c<|=t9?5y&N)C#IN*<{b1hPh}>=#$~ zxufrz8u8^1h}ew@jz`Vgym0f_m0Vc~viVCdHuZD4n!tLS?9cw@?DA;-&_FWDcbji{ zeQq&)+Qxkob-?#sWwlr!2%Q>bcvWDE(wd^kK|BDa$7fpv0o$Tl_f z?dR`p4%^nd?~=O*GmxuOV<~QrJ-9y%oJi&^oggjmTj$ONygsUSAiy-zv!8rQY>VTa z9sbf(&&=~ZlDpNw17=78&D_hL$y;iE`gAWh+uPR8Pn{uz+ zSuXGUR(Xt;nXzkW`Nly0u4&-^%&b3d>75@z9__B-f{)L<{u|>{h1M#)1GRVpb@Qi8 zsU?ky6{PJ<6wdG-(rnW{4~cSNC?v1($dlj0t@LycT0D} z0?xpFzVm%Q&%g8IJzV?R2t4bVHRhNj?s3mNt!W`5i6{&N=N)){QxI$e$9&R^=~oB= zQ&r#`LLfp(;1B-;zQw#lfumApsVT;S%u=YjNo6No+fT1`*?aY4C^l7zCU=^A70kz1 zaFeO(m!*}qin0@M@7$SPaN?$#DsV0mxYXO35Em1D_pQ8#K#u46X~XG>?C)71?Nce# z9v&HazE>Shhz$FKn7apV<+h#u(V}~ZQCCB4jUy$Oy?VY3*vVi!c^EJsQs6Dbs5 zg=+PgYj5nYovaLQaC#gsPYO0zEqowlrFV0-&zDatMrB+=K7-{i7L)6K!CW|ASGRyq z!1|twgLC*`WiVU2)>LBfYI?FlhAkG+XOG=S2B*ih0Mo2@TpK7etB8+Z<>k>d>$g>^ z;zDpDAh4b32G4YmCe5}mo0h2y;x6~uEKkGU=x6T8&_sxsb31Q_ zkg;F($BvtylKa)z7_s4xPynuo&`%IyEjA45%2tfJDkzt&Bpo-fziG{=Ga<873Qr5wVy3hWigMQd%^jhTJ<^eF_idU}jY1XD{hnsvbTN9N#i^1gn7#Nf==d$x{qm|W8CMaL= ztB5cN7KEw^{2cGkb<(a`WX2Q%hp)=spfgH`)S8*A=< z>J>r(r41VQcwH@Ln>|7(`4f1K23gJA$HukbC0T`qh4$|dUtxZzeB#(Q^0e3Nmcr_( zFo}q+9`CO$E{}{2MLQIJi6gnYSYbB!U8~x!B}8X)d&J}1v%A!!O}SufdU|>!TTwA1 z7bE#8#2&hA_e_6|lvShAmRRrKn3!yJu&+S|Ko_DcFwJ?rd1?uU9n0~Yb`EPJTJPT7 zhOjD7ebrsU;DX3v_fKza3#t&99b~d(6dD9@@(11{%=Zzmso5)Vw5nKWv}w9byORxl zuCaC{RM)|3@}KiWvzql+Ik+7kY(U0^CY3GpIw<<|(WXH5fr9b9gGr|=f{zr^zc!Hb+N1pYC0igP^$xjt z%l(J@5u1%hOv8tclf9L><&pTJL4j)@cSD-JGl{?1EeQ%*rGL~;{;k0E+^bx53 zOQDpoy>3$QU}_iXoj}eHB$}Q5(FCMR zi)fenw{7J>Q}_z^if9WnP$YIem80T@6deh495%a3{>ag&RTjLc!f9g*h75^YdL2H# z;&<`B^{P}>l^!Q&4IjwRr{{OBq`13O>o&R$=Bh|9r6SOxU+#aPlcgBTlC6d|l3h&-p6l4lJyon^otK7HVxB)FV!B6$ zYkjbgG&ou1U^P-YAIDA^{ZuzOJiHbTg+ms=lbtj*H|OirJB^mVw6WQ`iWQ4}_or-^ zK=AaGoNjMsB?vg=EJuB=|DvD>Cu4U!Td%HTV-x<$ge_ot`1Pvo3z*8q?wI+u3V;9l z=TEyghD-K-z8jBub#)Gs#jMNyx#dn9pI+zI$R<>|uaE6b)Q(nFJ3V7FOnXEX2b!f) z8T78pPR(TuN{EY8SoS~DKOP+(exya{eG9}3!oCy5Z)-tA!WX;c7*s1|`Qxnh!vaT0 zWPr}S(A|~YI}3RA=;Ec{p90@geSM;4jy|-iKRaf~2)s;%@!~~zPufXkRk>=Z@$Au# z=L^HUp`zK%5PsLEa%4zg5*8>33r&XX{<$Ca$;`|Q7U9#={ZUJ;>T)EWr6kS1*g$|hrXQG+ywZ2@bRH~ zFO#mseDNUx%e}opouk7i$7d&JFvCa3i5sZ5=@kcfK_Y4PT8JyK43fV7^|4Q8<(TGP{Xxt+Ux!|p-Un` zwlCP&#_G=vT7nz*H~6#rO(P1hkZCZD!GvUF2feZ@@NVmkiSXxdCCtY-jG)r|0@FN2}fJJG=fjsT2%W9zR<{mtIR%G`#Z+|y_dsXc) zN+)u>(oX*TEMa#~jsJ>(0+e8nml%or;{-vxndph?Bp_yzljT4_wsB$h^);)Bx-;64 zFf))a3MT1=w42N76eiW3t2d)%5_z1DwjuEoSz$T8(ldKvF^bcZfo*^dAH?|GLWkb% ztrGOftasi*wYGW=7U;O{n|E9hMVL&lYQ8;KZyK*E`y3c}J|88Wn5fv;sPkBhF!Th* zySmqpKN#~zA$po z)T}`XU#cVmb&)wyS(U=jq};L{AQX_4OHm z+N*UvwLbR@z4$QjWg>$u#}2d11~<;oy@l4gJ7s2B0LKV?_zHo{&}}SqTGw2hl7s4` zERW;Qd;5HlYY||A%w%zb$BB%yt4z?xkM@oQGqWYg)+NadhRdN4k1;H>9B&76Be(w( z7LobkR?7!4DVI{cHQ~HBpi$3v>`4tOF)D=2&groOFftc^5Ei_cAnv7=mD?n!ok1PC zyQF{lUA9r7)GsD$0~M+sQ5`@|YgkxQ6YVtF0a?E9b#-UEOO1ZmEBTQ8v8^8|OJK8% zSN!q4GHG(H&V$a^&+oAoUZ^A-FXq#GD;2Oxok<5!&7xMMXB)?c{j~s7KwBP8SVoP% z0Hc|K@lCq#%;swxz+aHqn8V)NFsBPkobzCU4-6>Bv32BY*A}DhTtaH(mXlfXm3cF7;`J-C4%4tJtax0tdvLIaMQc<1$dC`rV3oOuNczmKpy2k^uvK zgv6iWM*prGIG&j>!V3?Q@Ttdf037J58X5)ato`lnua;~PRF9t-u^Y?1fL7;_l|4Pr zBvh`%es|EHH2b%MD1o-65;E zG+ZX=6MNyuCMoAd_ooW$@9pjaov{m;i16FFyU>vpso2uF{#wANMsNRDt13J&Pr zZlfpPpzUGEcp>fEA}xB2S-=MZItJw`A_S5HLSscGZ^o;5i;8S6-e(5yv-{x7!|ydw z2o9>}DHlDo>&^r=4IJV7e>Drf>WQmi?f=38?1RPiya&7)913*f&!5TQ4qfzh`4v`-&lTI)nK5HFlw0_JWx9f_gXJ^?6LPZV2$C{j_{qU=LKWL0 z_u9S|?d?>1tc@_jDil8k9jR8Jjr}n=IA0+{uP60GM8Q>r0hF$53F3CfSEkxi3$R^u ztSyM_{G$(X1k)A7+`--;&U-5Ko=P&rK!yon=AN)yUb*>xYR;h0o*F^L4@V#z!{=uw zp;t@Z5rPVrN>QeRy)T-fz{!PQd}&Sy!ZrYj>@_U|%ewGl{(&eHNeJhLv{c_$1{G9a zpX!o2f=ZEt%aa=OeLX)lnb@U^CqCb~6uR~-u?UcVT4FWn4e7N6E+FlD|S1VC5SI0V#Lhn zp^I5C;BweH&zst!3a<)2Qteh+5<*ZBsHqZ$R^34?f*G|Pt{lY5$|`>$Ag}af_eU#w z-~|`W3V3cz2>oj~u8tTpdgjFE~3?G-9yr;@jFN5$wLTh1G zv#w zy;tG9MgqsX^H1+i)JHr}1BHb;C4W`G@KUUTISVh%36rtQQmL?Hz3?xit{D)6T*-h* z%cMD^$)lXDL>go`^|L^N_$p$1r9U^QvNEPGCcnp+m-nb2=Ma2IWNY`+`Z$g2MK3g9 zyK#IqDpEyMhJE=0*8!|Sr`$h7TyD;Ua*`64Qx#md+M4|uH)2LidZ&W|G{b^K(ugW) zsg=w7T(cdAmHp=C<{R%#emYc z`$UTKlFOWaF!f;+y;8DC``E~brLlwu8jYfO#dnmETwap5xifO%Tw(93xy5myutaZr z%?ItO)e`x->Ly~Fqk@}-qz!ZYSOaJl}zz+4B zViB>hKb6}){{}<>;0R{5sEA(O{7d6h?Z)0cFaQbj2P;V+39!NsoHMAaeKwWVh!rOxg3^Xr@Z$diYj$G z7yz1eRaL^{X@8Ok25!Tx5+k@kf#%#n`kl!)@td~aor{8(Y7ljZCoh71p<3%Nx$un?tV7*KmzjfQ?1idX{m^-^EH zeCfD87W%d;Ztwp6hWj)+!XkC92kZH$vYIHT3HLcQ(U5h5E7Qm?wK2PgMNs))sPiZN zde>#rpuc}R>QhrEJXU?<*iWHH)R;m7KZ6M9aEvS*-cw-~YS*F{lH#)CzgvusY;F=i zd)8w%$P^qH*w%mwjl(P6s)UO})>i)jLDaJL(u&)g!GaDoWuJF~eEPEo{Ijt!ciM{= zu3GWg)`EF?kKa>l^_AEbaZML+G1S@4zo+1hm5qKXH6hwbYFaij>ek3US$cZrCc7nC zP8bs%E#6{ic(pi(OAyzW+vzNZ*G)5oqQhxbHR_KEIAej={rvnu{i(esx8?K;oGP(j z85kV*_~D$VoZFSeU*^1(7aeUZhzp^xfs~iGX=u`(JZkLjwjTSTHd^kYrgjI&18J}l z@$g}SEWOav4CF~%4yAfc63_V#eXcw0ZyZE!T`Ey^cOUb^ZsT`R|8R33?+cKvYYagc zWQ7~N`A<4$V5c2cQdVYVG~3zi3)W@MMUb3=S<|~H-uik z)UFS14~RWuZnP3}J`9BSwLiW&Ow2nR8nf=p!;qVb+A7k&4w0_=m_iv6uj@`MZNuD} zT3SNxPSbiKq~bXW?U!t4_CU_YDy&Z6(R8-K=H_yl1QDn&Kbi^r4T8PK78oY!=Ac7alE z<3AVhvv`)dJkfFqT-f1BF%z^*9EYvDOZpQvN1=GUywwsdTGdsoRufD|C1aI#Zs(p> zUgu^rNnt@j7N^J3ZU_75p`SHbvOcx7gV(Q&h1St4eS34>M2u7GTB)H<)WiD%BYz(G zFdcV0-EKRcYb>Ur(OHA&-9)Xx_(MUNT!25O^0e9;AJlgrsILbY$RaA%U zwr1wr791ua2C(pzQ3JMcPujSH4!|ncw6yBQ6|_g#)4I*rTYa8M{2Oi*{LTkKrGyCHv;~ zR!VC39R_zspdPXMvQ^#gE70@dXEqt4J3G~@3r@qJ`BH^feur>TRlDr`E$d4TBIlmX zO3K81Z#~_x1f3zGSK?@GU9y;g%^8k9TGV#mqrZRTV?Me5@S&u^k20K6vaiOPs~haZIQ^5@Sa2_w2jyi23kCGAJV9Ab98!1NbO$ z2`;z&-@we09;xG63f+Udeq2u+3n7{t6B`SGVH^?^!_n>ZFJB7J4jT_b_}zi1B$NC8 z!z0BN?XQXJzkI5zWE1AdWvmEdLqn^71dUA1-fmdmKkQ zzp>ir{w6PJ;;>-1z{mS#JsgS@8I-;co>mqLU3FWke=y#D|M5A9_3{}xC=4r@+y`_U zBV}srx}zf_uM1Wm)%r$9FY0(D#LayESy~YZJy+1bf6XlWEbO6VpbF{TImuIxq2jjy z+n-I3HZwPeJ4*I|aYK@BXgC6oU*hxU&-Rl{MGT?`Gsk;v_8M^wAM)vyzDLClKiK%b zyJcW(94+CpWFhnr1mY`x`Qc}jwA045{f?Z1#!6??Zr`e zVPmib;Cy7-r;O)y)7xJ?(1MCc%ag5^7?cTE50ToPQ@>9(45lHijySGb5buz+rX~UIg3pFZ~Y09}O1)5Y^kf{8$8)6HF z*6&Y^O<^@PksREE#9pDij;lZOHO^)@VbyG%D5(dIS}5Vtw75sw8w*a5VzEqe-_h6C zCuWSL)><93`k1@IK2u`M5)0k194@Z%I!~Dyy=uS?u%kFOi!{Je{jkZcb*sR7zj?B8 zy@~%_m#&$H?Qn5EY|3aB6JO_!;A1^t zw$4HwT+!>?;1G&&N{;Vt+eR*jn-c^1W=+ufaGO~}PVPaKY$ZJm+nL`fFZ~@u?s1CO zh~QpfuMpI4cK-2$Weqf^h6Xq6_A+&k#cs>&l+o|Hl`LL8O&QsNlD&H?QEOwB^0-%w z7F=H#K9SLe8-`loKm{9XyYL=~u~7KpSf$Fr`e~EXA?$51JPGR`uMHIyy!2m3tq55P zgSe;wO-R^ekGaJf94n_Wc5n6c^)tql3$^th2ShwpyxlFT>vq=m3BtIX|L)+Thug45e5@Z zQKFoG9LGl9p00%-LeBl@lm{&H%j1Q-V2R7bmCNzqU}GPh9vm!^&l+}C!IOJ$dzS39)n zkjBVm$q$ywx$iWz1=j07>0lo){Ez|T{C}wUz0hd<6_VWSXWzwf_hJL=}WQ!lXvUqzyQ+`zFTlGYdR(GDVizpI!aUt43V&!R)q$! z?SyIl-+cUAz29^jpJ+$izOLd^WJ9G zH77W3fbx#ta$*QabQKM0bPDeO#eyM6@?Ud_X2+f2ZT)n+EXF_DdgUY~w#=l%w=rM#K>QmvHa18`p?26a5;Gx1FRAf@o8?$YEI>ma zIV_<>xgwhn4ZXj7>DgVXUu0?}BsnrY+D_u()pFn$HUL}BxT>?FoGEdiE0CCZYo##G z!9SS?PVqlq(4B^0W(WeAc)6+RuTg(tqA&^(7pMi zR%XsBYVOwe2m!XNe$$Mr3|e3+o*lXGy=FD}jcg6~zeB%CkiHp9RMl8k65SWh$moA8 z4xVAA6v@Mf=3tdvSmI^_%1*5Kl?Hh?uG;s6V;_Nm2C-ZG6NG)E^0m3PD65~|x**Pz zB}Su(yc<~){(gR+?+sf4OeN%%_z-TLMkDHd@Q1 z$-$@%DUc(mZ)a351z3en^I&SVb$^Rva^Lt9X*8ipe@=Kv7wuLo*qGRqeCvVC_q6M7 zO@7ynVR_%(VX;YeVSN;x4jZ4Ixd5G0ggP7F#G^7ZKkQ@_rlFvw+>X6{x4CmJGng1&?X~pIf$mE0$un0)lY=P z;Y7eBDWUElntJ%uTOng&BbtGYS*?6Y+*QZ9HEhEO+t0uLV_=}9N3E$KE)Jz9zc~1g zb8uQ3Ei+Y;SPEUzLi1lb;&t0siruBnuld3}dGg8oF;1(P6nZzz8b}wxWnop=Xy}OZ z+>SsCR@&-(ydK4zL~tM=Q^+!)R_*AcRuU;ejDcZg_-&$3jQeq>>PtPn8E{E|>yMK^ zBxN;y=5d@lw*WU2{;0l9$!V*no~Z8BUB3H7VE^FQA)RG@E8KqeaDm;%7Mra1)b4Dh zkWjf6`JlC0Ng?axHF~5BD~abEl~FPy2zQM=5B;uF>l!mreIbtzb`4${LaMeu=L1UE zq%*Yih8{!(K7QPM(5tDS+42&C!TqM=mUkf-1M2@Hxnx%&Z^!3ja&oheig!0Auz73^ ztg0Qg_+6q{21p19^uZDx9hI*`6LaxC-0os=vdwv15DMUz7zkx7B?$m~hKosgD8vMo zj=_&dAFpVdJY;5IFq3S%pCK8QtDGMRSuN5eF0V5*m|MieS0KtDnyZ`u`PDcyOPP8C z`G67P0g5T)J=JHD7pzUxZ9sTR6qon&r+0F)=nN-`@yu@z%8Xg?tQ`)nwtrX1_#=Vc z2C)a|acp#S`m`rWO7$&yF(iSYSc_Emg*EO_pt@zZw_FzPR7FQiyS%jYFh(xgeJ$<6 z25BMf@Zu6pm%k?{7=n+Fk7709)0cikl|n~W{3#^l;Gmw*X2yD{t+uG>Q)yJnx=_!` zz$v{n0`BaD0^1$1>cjY_hD+#<_bnDy+yq9B=U`W$WGfy@82pL7L(a7us@$krZhrR5 zhp&pP@b~ZE=EKF!y(PKpxV0<;m9BfKcr;`7M(;t_I%K!;*Op*R)_ii`ni+06BM`mm zxZEeXESJQ4((>`+)1~!uw4L1rH}jg0rKAznjyR z_2*}wrbkS4-@Ku6n4#d9VstPJBy-5{oV4UIZiu8iU8Z@t5q7_Zus zc1wV8tlr7lY={qpQNJ=Az?qSP61nx*QX`a0XA%Q+KcAynnQ5op0u!@ba&p{ga(^!I zC-NPrZZ#dWe50>_GWAPqocbQbn$vqiQOlK}2>|yN?_OfhUH#nWx>r(U0%==hes{ix zjt%Ks=ykSYeMt#}VqHxw0CC``G+DxDulV%=OCxio3?pW4f2}^_aR{Tj{o&A~(e3&A z@5S`=Y?^S5FN8J~b#(YKq~kemzp5GpIeh<~!edK#9wLYkM*y1#_)Vps?+d}dJpQ(C zwMBJ(()l|+&dtp=@V%%=T1?D&d+yy2f|Gzd{DaxOa!$dv&A?~t-WJ(Eqhuv3I|v#< zM7Z{3rI4W`u7d3OoPXcOXz^Q7n1z{Jk$?~dK1+5tH-GSk%~)c8{zPm|>a_&#K}f$F zvT0h??+#z+J0D`PS2#K>vy_%T!N=Vk?9V+XF}2;ASpvU8ECK5Exy4WCVL_mzTMdGf zw<#we+P}ZQR+r689{rA%uv-|}yb$o|lMF=@y>cFl^_21T>vT(yePlK6K4|o-)fs1g zF!yO4eY(F^4Q^iA2_}FQzwCDhe0Gm8SeI`Kh#Tk~Wy~yt`7P{!Enaey&muP_P6B z!qxS4RW7|%5A&$K{&uNllV^I;`arKT*j-{t}QZA(AV7t z=agBaTxew=K{knx)|2|iZLgFQ&ykUl;Zbg&aCn6-P$)4R2P6CwdrX|htrv=QeE$mz zaF4@vYesEG_*rHkq)@zUJ=S;GQoNb`0;yMR>_cX7-xXp0-@d#{}!<&Qk#d|ii#zbc2RVbLt{fj24Mf}EEJ-LzPgNm*i4@# ztR}G+#h_a%wzV;-(rrA0$ii~L%mbWid-&NpW$+{3Y?B#EH7iX&s7T-F!8uP!SsC0! z3miIWitdc98Hb&8bhXwV9;XobW!7ALU0JLjW|#BYPP^<+HAK~_RAS>a+T$u3hAR_4 z2vY-%2H0sJ%OGRb78)w!F}x64kU4b`hH4x;JF-%P)@H)%PuNUQuB~A~?tIiIp(3(U|N((Cq@TR?%zq)<7kAqDn(=nH` z?HkoqI=WzX^G@3&il%GLpO}Dv;2xTTj}KONlaB5a-Gc|dA9x|M79o=MSiMwrx_WrZ+WF zdk}uM3u%vA*w}zYi;NV$NnHL%;N$0zklQ$(_Xr3q43&TW$ysbsP7DqX#=-H->o*M` zW{xpP*aka@m{};0h!O172d%YzrViGdvk(GA3u@cVbVUK6uoO)CnutWP5VULzcm z2b}X6MPT^3th?Ry?z0&CQDZhp3uMPK#n>8P`gO#qd}>iv7VeGsehGmz1FXpAyZZCJ ze-SkR2?1fuAQ#ubBb^CtS=kNne`X}ErWR<86T6lqFA`}GT?C3X+3kmDaKZtiT?iqVdt63%Q2GrxmrY7oBOYE+ zSLe?kKVo9tblu%G356X1ekWuj7}QIn0d9{7eE}ehbb$zPI#fW!$0QMqn~$P;HOfH=^{{94b12x1Wv9&)#(gPaTJ)n;^C2b zYO@f$Wp~-067+F>q$Qs?3kcjsKTd$OczRX<5^)pl;tOC&SYzDcFF~(_n{H9^jSe2v zeEQUb${^sjH_o#cc2TOdeaLQ=s8VkJ392i`$C}6MDboR$iMW6%8W2xU7akuZSp$Wi zq+}pA*p=1JZ(bHf=0cI279q$_&WIla%N(J={w<)dwfK(5# z#q)oj6$!ayW;RPk$$-7CZEwH2Ib9M$!JGB3A%G!1f-Hds#x*H0)!*(dM+_Dw0ljp# zy|A;aj*izr-WPxa0%B%+PDiD10)7p>y9FOw1ql30|IW_=0Vc!66WjCQ?HAPwnBv&? zhQK<*gS@KQ;Cdp9i8!Q`{!PSqkuT-fQk&T`ICg-0VSVE5<{KjX);jgF9ILmljdvGa zpju3)-tz>UWq?N0YY`$47nxo;K({1tJFOMJ9aW<5pKJ9I9~#!_h{Yje?<^}V{o&l> z_0wA%61>V)aGm)D{)!NnGU=&dyR6$j8q(c$O@S>XN;)#sOlyF;+TwPi@Yw12F*Rib zXix}~2qQ(5-A<1I|I`cMK;`erF#t!ca>xaQGwRpKh;45sC*YN~hD)s3E4JWxQ2Eyi zjSyS05+pq0MuBm1;{sdkvNI+T@dwbosE+n_`@Lloz;s?E^hB3&Lz5Gq#PH;{uuFsPvz&5+zVJoJ@M`&;Y_Izb$SM;Hng_E*@a z0Vmp@tD;?DX_zAPS3WTg zTdE1XDmD%l&+PtUdU(`AWd$+QSn>r5ACwl<(toK0`boPvBxkW5D8y+Zlk#!IQsOA@4BEVdN87wFF+bGAc~48+SJsQ|&pC_OEk2D;?MDq5J?) z+a3qwXkXte0QE))JcGRxz^H+9hTd@%#LbkY9JnY`YZD|o+HSL58R#hf{>XW2Ca5RP zD1kw$iZAd7E<$-f%7-%2>J$r`k z2_oeLL@uFnae7eH;OA6fEVvb66H20@uiro*72(4z02GgWG7PH=gkCQj{Jt58$Ca5G zsj91MR@&ONMiVn zmnM>r75eZVqWBKSyAdY6k%23^C6Sn6B~WWp>l&M#-5T>kB}-c4jDLTfn=ioB3ga+l zxNdkg^WchtxVPNPh+yn1SMjhO5npM0{i^n3z(J0)4%W>8?VPy! zcI=PGxSU5neG+#?fi332i95ghI`0c^?w!#ep+Miyd3~h-1K~|4fb>%yu09yD>#FUr z8A}zut;c6>EamQA5yI~&o}pkl^gZqz1zhdPW-pO`k=!;j=!Oq%cl|ted)(G5jouH< z3;0KVB|Mq-XZ|x^3^k)3=&de209hlt%W;cSJ`|T=5j}AppSB+JI-hgdS;w!ww|FHi zoIp9xS(`q>^X$k9Dpv`s?;#N0Y`&q`jPlCLM~i8N(Nd8&2t@ey`koZEy_3;LhVlVb zAR+Z!{rRae)IR*zfHE{N{8?ltEu>CCTRS2Q<<=V3(!_L~E2c=_p9el0`8LU8f337s zs;CV(&W#B$hr4+kt37_bAGEW*sjp9?lIJXQ|I0@$JbS)_Nq(2*KC*n}(bTW zoAw_wYV2qC|A8qSo}3h2wM`~SGda$$AlhFi*O8OkUM*2gzlK0mk@}h&=e+cnDOBBJ z6qav`;vcPb`vGsy%2J}AaI>-z@ZLyynFZ<3hyV2kCP+FgNvGJj$2NF2(S7^fFQ0H2 zZxv=j=gGKJQdDdDq-Ql$m-7CbpD8xXVQUZC@S|2b9d=S__Hh>U*$G{s7LNVnPoJJK z*Q4)J&qb*4{WhS1#d=F+(70E-i<0o<`l6y8!|ce|eRbS*1$nX_XI#Ne#N^&)%mN>U zWg>$o9rASQ?G`#;nwHr%1uV?l#z3bBcjv-OT=xPP9%nnxN8J7mplifWY~12$^_y6d zlg_g*gpdq{?O@nmh(K|=LTj8AlTvQPXayytG06X0QFU0MNB%x8e`DS%=USlBp8@Cs z4<4Tp61uGId1NDmjI;8Tmy^5yZ$9$jqKu&9DWBI%OT%BjPbq`63f1#>s6 zJsB`c(z2`=g&6|zod;pj1wO&!^=kffg{AHJF8YX@AQ!S*t0i`6sY1+}$g}M>Rz1L- zBf4#&9|%9)$R|hMxX*$9b!bQo9=)9^htzRf6Bj~8=@h^<3Aq2nmPiQccg_7^oHB}O z-eHA^4Z^rZW|u<3zY+pWfbmvi-S!{<|K2Ku`pfsryx@nuiQOn62Dy;%hv{%xPio)x zxTvu366sajp9IpegjFsj%ezav%yp`qhElM<5C{PkeKwWSy@#>n#n^tS`Yn8BaeB!w zRV#u^MziM(I^P`54m~T%y(G(Oc&oya916~=m2$M6w|Bv6B}l&zDpw%6OX;PfL4+~G zK#$7GIDHs_vRjbpF}AL!`AEx`n4V!#ZJokGm$l)0gZJNLRZ&IIe_xZ4vAH+sXyh*g zhmSD8;GC!4T?e5PhtbJGLDCYZ-QPv~D*kh{V!rY}(GYks)hznsJ}<8aLuO{zkIF__Vq!zl~!2_b%1ooX6W(=oYW=Kc~JclcU6+%`_dYV0t z`6ochB(Q8UpxsSPbE2XKF>dov0pqtrSa`VqZA#0hcRdfMuS0)eb6@i{|F+Yw0(_Aa z&Qq6yL}=hS6`uVeec#X|ue0H4>yJ>?fDllGI}xaT@80rT8?BIh5azZ~tFo$&CP8pox1^GhaV5jGZV9->mg8JSSQl;511#S+6tWPwLbS4p zPaLTc*guvs0H-H~DNET9!( zvw^OW25EMfYyd9Ch|DcdZ=8Vh*bnD_U=tZVm%M3u2#m1g!*-a#$yagvjdZ zPJh56{@2RXF>W#MIQ*28n+qhuVB^7zYPNmEqrs#G6gqJ=E^OVEm&kp4cLNeu)2~Ax z5SrI7yd3-cn8S&|Ay3@hFD)YdaL6TkcRvx(wHube=Mfjrl#9NI>wsizmdUXnnI&#D zk@rfsF^k8^{@c5MyHj5NTTg3p%wdW(_~}U-+?1k|trVbz^>a`6H`pciL>GVh{fWRA z*Ixgn(XV=yqXQVOfT&;STF>EdHx!FA!;qx$fxuOXo>{AE&YI)D5vjw7Mutm_ZcuM+ zZRrtT?p6{P7r)n{RpTtbDg=EixJo^07xDG$-JoXh^KK#iWFAmc3m)QwW=(DsLhft2 zOHI>Y2^jtI+Pb(=2SI*MsC+>}R<=bIZ_yr{KSZ*k06b-4VgkE;2{?G=2m#6de?Rx9 ztBcMTT#Judm;x`52E~vu&h1y%)O_-9t%Cl&UgXBjoA}kZ-hXf4;1Esxgf5W-2;9F| z^~p6K!Q6g5Q)uT<*6-oNhtPY_Dvx~4Z@-p+cTk0z(!H}HxSYfp=&9J+5*1j zi=QuOxe(-(@S2>wya&FACntf>gOa18qZ=E#u!O-ks7GJ+4-DW7)zsEDFK0L_( z^#=Ff`if8+xIN-aHfA9O`7~zZGuWXd1UcoRg@!*QnlIM;8}%$mfgB9kMHkpa5cck{ zK7Y*F2!#4f%Rnkv$j<9nW2F9fkKY!lVp6Mqy2eFQsVRe5G;IFA|I~Dy@PiOFtR7>E z5s6L43(C@kn_?jl*J@|c>iX|@1j-6S!FfXJ3uNGrkV(* zT1b}7-W06?z72Ft_y2h0sN&iG(=jFi&o>MLS&at<7q^NC_<#63pK|ysZ?V-+CLqb< zf=UI!^~Bda#E&|^J9`=%#t84e2qPf8<3QAZ!;<8Z- zcPRnZ%jzNiC(x-ZqXk-4Z{H@6vMzskhv62W6=?LBiLc0N(zYlUgv2%`wiuLonEx4K-S2>ysPs2gcl)SD`hk5RKx+j|@r3PU? z&jal~y&?(@YgFxmxs=y1!z9p0dS5Yj2Qt@zYl~wr1L zdHMVIVa3G~k#EP{{su!D*wo|gTL-(Orebp&o0ws9lekoP6VGM8KyTyw_k|4Ge^~VA z)MHX-WZVJ67cM{~JP&Q07L(>J_dG3tlwU-o@+P;3M;Tz7!7x%#P{`YHv9-e@X43o{ z-;gEirEc66>u@sHs{f&*#OMX^=eK1mE~%*W=)_Je#CzU2SZJ z31n+J;mW_sBc{Trs01yz_RY4g)_nNIc(p&)ZNQ8yN9nL7@Wd#;&RAf^qnupxBRlSj zwuw{7w&rVnhd~GTG?)pA$%Rf{r>t?F`q^54Hd1Cbh<6qYhL)D~N6h6x$IAtk9?Eok^xB4wvU^bFHNgE9Ld*ZGDVuyMz>|6>PM4PVU}y zocMVD^VbV>A|ifOJA0suo$+rGUwQ_o>XoZUJ8SLjRR(!V^u7r^y1Q&v05&5b;cUo^ zilTq^toi7|S!zi7DZsDmWnh40m4SO5d-%`ov42_i?dB>HvRaIExI@573mYeW_`5Fq zL<+v|^oVXGvTw8pvE#TMPA|#Jrzm9iOZ)z92M zobsXku%~mM<|X9HJK!1)W>q=%-!ms0ljfW12V-_C?2~zc0XIF4m((tLpaen+OAgmi zp3jOZ=c#V3`QD(>YF7FoSyJE$OR1c9=(piNQMR(lSn=7KufHjfQ%Lrlv7#^N1&r$e z7UpQb)P$Y??9f9!-w(IpX?tP4CBCP9Vcl`7KV_X*FSh$nxXolLw~%RbTY>CWb6(zi zw&M#g+WGRXfe+F*1?TG3hdBN|RtGClkYp;(kUYObK+x*cE0KY6+emQUs3kbU2&Uj2 zd~asLqOIexw>+p*&u0CGIYL4lGsOgu*>!=${J$yRJdX(s_%pWqN8Q1}%PWb@>Rxlj z`JujlTXwkx_fK}X+72JTYNyw?{^&0;x)a_E$e)+)4Ya;u7xsR_VbVFzA1ml7EtFY! zy7ctmwMFta7P=MoI6tJLEB)04J^rZ(TOWBh)6x~YOnsh*BDO1-$yZw=yw&{aT@CBX zp`mZbX$7Jo6c0+Vup~9CN6LR3uT>0=7rJatJziMsvWds7-uR(^ZxU{2x#Crks-7Rq z?lkGg_FN{@5dYAT&<=GutE1G=oI3=H+<14Fqg@tblsHZEFc+M#wF{L?M$4?@c4`x3-zYS_N3d>*c)#}OB%7jPxv zs>#SuPc9Cu<%A~0y6)B<)H%hlr6(u9G9FzECemc0p)rDuk)7RAP&W|K5t&fVSilq^ zu~Bz2Aj^030k_z7FA_YtZH(*+3vMLkQvTlakO+~a|{pa1oiCSeyhw~UOpT$7Z;V57&} z=CARkRQ^TRHaBqHG-P zRnPG7sF~adZ>sI+fD3eCos#`7bzE~yA*Z1D&EA<*|KP!DGSzugASLNDJ%q5lZ|I2n z>`+mOh9hHO({j8GF{7*XpRZdtKg3VgoS!YAP|r0EOvk+THaDkIUY@{_7M9e;{C~Cg zmQihe(c2*XRnP*ZNb%zCUaUn66qn!>cPZ{^vEm+_Qrz9Wh2mD+p%g-JcguVFU-N#L z`8aDn&CFU^ZEkYIz4x4b_Sy36XVc|hZclD^^~I0pst3{B-}_zNzhsE^UJL$OX%ML& z{T}SizZ;y^X+nEVs{Kz#bdA-uY2l5l{HH*?&IcGc0Gc~id9J+9@Ae(lI)Dsseed#Ir9k=&GocXfRjY7yi7y{U@+dN3DcX!2h)k zQkvJPJ-`i#09}uQ9GCnq+1T`4tA2*bMw1D33wU2dlJi(NDU>>76B_w#^ndBH;Rc)L z?d_qcuTNJ{DWM1vVYHAJcX?UagrX);ly5PCYDX*6T8yWo^gZse@dwWS$T!ja2jlZw z?@WeO+|7q|FR$VtcYlBM;=Z+yS2FiM@nmv~YifGooR>Do(*zjTiA-*%XIf!j&HgtQ zp#9;d@U9Q9UYF0)spixez)mst8&@A%o*M#TMBxRr>vdlvh+M!}^YEOyABda*t7938 zbQzr-7QL8jA63^o+j=n~FjF?)%L$P{0PF=~)K7J8c!kbwLR8x3- z01QhZ*wTjwzpSSx918XpQxjhQ|ITOwtM%$ z5;e#KolZssh``CNb5;I_oyf<~qe$X0Pz?b{x3(~eYTOUSm?M+ugZ7qvmOgUw+dex0 zx~r%T|hfkGwO3PfC_%p<>7_|y9Fqt!y=pGVeIcL zDcKxO#S-h|FnX9CgdweO6#hL?(mQ4TP>ZvzccqX{pFZ++{R7*!(^1mkpE$rw0pv=@ zfjC;n=)%m*8e21<@mc3k3Cq7&o0X;62B7`Q#M!+wTSP}+MvSyZK&Q;O!G3?U;WW1&$7u02+|Vq^^mX1wN63gxTi-N9Wq~w*xH#+ zZ*&xAJWI5+*c7(({--5qfP>Yb2E~W~i!><60jTTcmf)UV8F~f=-YcmvsTyZERP5^G zbd0zIuKUf6jbn@T)l21J4aN=DA%~?Dc{C=DN_T$~ef`G6PUvYc(aOk3yA5raq2nLY z7!hZW_wRp{R{FDw%L}F?~hXbveJfa*$Ze zUtfh+9d_v5j0o%k>#G#E>^jRZhGHDpp&k1TiBLO{gw9ms_Lm9HZw9LlHgz`*Po$b<)~z4X2wKE zN5eWRMg9VcEj##YY;Ecc-BK^~bK^`$~Zg1W_$35dp!%xt5FX->_Mbr#wFH<0#BKBWxuc zQ`2ze<#V(4yqa69`L0dbn7Z?SF8=4< zk00D;FZ*dG)8nhIR}R32(IBh%+YHRqatks)c?BWBph&{zE)6E$$!}}m;O6FBL0&0Z z+=V{Se7-kHX+to&01yzYFF;|0R>L4R&Tqfqv(Y~v5YS@X+1(uoCckOU4P5ERc{al$ zjmXuXx?Sv{O~Hfez60CJ@IN<7new0=No#CXV8Gp~7eWWINC?gb;UeV**;hi&AG5^J z0WFmsr;Q7l?4$;m*uZCW0%vx(;K5tKl0XcnmP~p@7(}3{sTE*$r!wx8_|#MSoe>}u zA0pDCfdLP!9qu4IWiIH$FbHopSIY`TgS*Jw*L$JgSER}W!qh*1J^-8W+tL?NE0seU z*->Y*K1-`)D&^7iE)Z-$$pLi?%3Q!T>G1Pua(#l4TkQi-jSfpH$0dQ!XlY$L;Ylxm z!t`O2X#%4M8R9?Ax>Ladv6&EdL^Qs9rbQP+orhjp9O!Fx3}7&H))lt#Ve- zO%{%U3Vu(`QXr0rH%Pf`;ezPOKTobZK&e%>uFOg3;>~-c~Ise2?@24ouXcDO+68$hM8I?^9DHIQI>9klh$J zcmyz0L8Erz|6Is_#*(`M$}E@10dF)-RMe}u_gfG52_ab9lL!AMj2DY)ab4tkgB9`p zWJI#mRFQ{=QGFL!$S*2P{B}u%Cc)kI4Ob71i;lb7jw}jPHL{ zpnaDER5hhPgA`RY6d9aR_NJ`;W1D@s#YJOJb?$(1vp}P zzVeeC7_)9MAylLtTs*3*XE;r1>$jm4|mHa4ka6M*huJuxovc@`%g!4NDh`b448$tPlLDg#iiL98FKEGMtngSBv z2P48w`Xnkto!eHA=SW#B!!Uj$&)3q@ps_H{aIaEi6~BAi#{?an{(|+> zpCP3E7hnV4PzTvvmNHY(dFgwJK{C2w1h|_!(KZ~8VbDibi^ipni~sDzEEtX%p7=x> zuM;=U5G8cPm47JbHTk| zc?>e5T+?_7-*~2hKgKmvA6A@XnreHexXqt^h}UsGBz)dM>P!uJ!Qq%Qqh{l%RGvSz zk~j-*NKRsGN81cV1!?1e*kxyI;Q>V&Aw+7%=`R&O^Ue=SPlNjZlYl>>I{A#7nyf`_ z0n7X%Ar~ym(v?eaS5Tc)%-E1jv^W@UN6_P*4m0~kpISJd+4-UqccPtvU_LPV18%F8 z70K7kEtdE81mh4VK7x#n_|kIP8w?XZqgyYKiFQWtO3N{(6YL8KK$%!Pro)6c5Pg>p0*#IctXrB zElljoFNWA4nMtZ~TEXymlMN8i=Y1*R&a+XNpkDl8bDPB{(dG@a7BOKi)?r2LK-~F4 zkmKhmfwv2`u|(^C!cXnIl85JsSP5VHJiPXJcwKl*6&6^O_p^@u?Vf}v!TRfbuRO*G zmQjm{+OXn_ov%ze7fIgRc_c=uy^u{f&FMv)*Y$f%5^G`KH)=(681+&_bK3BX>_LaJ zPp`o8gSneVEvuLdXb6+>H?%}*B**Q!uu=u(G=Jt~=1s%cRtlC;U+J(n{Fm!`gf_3} z>@F_U5m?;O=AdBZA#E1PUDn!FxMJY<+nsizMU_s{krv)_k>ToMkv6X~LN?z;KHv33 zCUz}htDoYkXi{kqvuV$T_LfX9!*AL@Eb#;f@=T`WKkCF4e{RRl=tXqaIJK6y&Fm@% zHLErzQG6GJ5(-{l@>$1BifWSK2{pb4Qxws-ITNu*f+ar6Z|GC|Vbm}X1R$s2{_B>p zJVw6o>y<5|M5qjd+}1ila+#LL`1RX2ai4K@-iF%!VYIjYvOl5YvgxI+Bi49e%Fh^% z)sh;05L~pZg~9QOn4wvLK`8fOP^n&v1Xq=)>|TPvWCnqa!B?)rawkFX>9O0L?-AT< z^Tb!dx}v$J--h3bn4u~1B^DK}Nc1n-NzrF&@*LF>&%hr0jH*>t2+?0L9oZ3&D{=i) zPF-fZD@WMRd&@hZ3;u5HioH{yX47)A+>Sv&{_PLJHT(UuuLJSTs(fZ*`=3nE z1S^pRDSM!xsGw4{J|a`ND7TD0d>w>a-)IIN-!2}*W7f?Kj|mJ-w1QSL!9w(YIooiZ zKk^xmcN*=d*g2S+KdfitH$DHl)Ux6i!#CD;PX(T}awAJ*iNPUd5zzB;Io zc>7V2{4r6>eg&Z0_8!j7et5PVGTxa2YXoine6D;WMmaU-g9O?(kH(}&N@HGkWgA++ z56){gP$I>ltA?ytXbB$>l#A+2*0TP^Uh2ZVJ@Bo5xM$rhec8vS@A>a%GR0EtrQP52 zHLNn;@G6N~QK!2UT-<%JF|GF-Be~e(=l12!ObLJrfB-Rx#D(T7;p_F61&k3_&))Yb zo?l*U4;lq{7^@x+G8zADMV1YV+1~DpZgxoH74Np&JCQTEJEJ~Wkn>9@6g7Qm$;%eA zVS8w{O3|0=E8P04?s~o5>*7<&jKQi0{Wx|&vwjeF^(?{w7=58n1da^ghn1;0tbd6Z zGo6fHYuxtLN90zvCl6O2+ZTMRxH>l`h0Le3vVhjqd2c{vn(160>2^AFV1uwJNsvh;gRV( zmE&^UN=}992FW*p&r)p$I1a0>iNbniohLK;sS*Mb4X^6vMP8sACQ$6ooIW$^RpR#> zB3}-_qyPvdiT;ki8qAVta>V7DMX^<_XsH<_g7OMzLNx^B;j@;Fac-1cd~n*PR_Ctn z<@;{VOr@c7@?CLvnG`AcePo2F2d)q)%8&KeX0ygRC5#d8&1owdbpcQ$lX^XoS22?B zmknWSBKDyxGelL&S8~Jj;CZsi(@8DNFx8kQmPFk6mgsuDo(hmvULcZi&pi1r`V%fC zlsMRGy#9T@#>b*aT(u+)cP8?c0RvX5yw$6>Bs@D!a@rYh1a-}M66(6QhC$DARgYUD3R#zJ}Sx|9o(8- z6?|#5YQ5%o-`2VM&%&_exqYpT^j#i}PeHhj;vd|%EJ%!qsicgU+{r(4Vrjb5YuqHdAY93O#XX4@5=mGTZWp)7ERgbjOsYjq&1Tcf5N2$H zEQ79<&Qf^{b|~MMwTszzFC@s^*~Lc~-RTSl^Vhv4(4^N^0RVI?AlBe3&PS3=sp5j# z(ez8ZBD_{=D}r>`;+<_zzKcba65b5C`Z!%z{7%>Bvb)6 zo@v(A{z#rL(`&TtrZzrD-`8!03AV8~<7=pvVt%&3dsJZ~TToar%`m&6d2wv8GiVT4>^IB0#6S8p23{zi1A=cHH4PAuAMQxD_I`g(nl}elyz(DgFyvW{02A ze65-ZTVW$&2I*dEV>n&WAI^4!*?%l5YkhP485INa4ro-ZN~Vukt2^IRciwc#tvBcP zreXArFW=<0p0ACEr_j1-w5f&U7xt*9*tfgRB)W|6RlW4jP;T@zKm57kEPan;>`Jk_ zyR<0*iU_{c6ek&Int5v4pow7S-&p-9IlhaVW@W~qj-!_0zjhFOGDOzPD zCy(YLA2AK^6B%%uf1A=%bW8XsOK%e|d%OJ~sV9rc2OwC5$6Kp$qwE|qF6Cr|By>1Y zC$(wwZCDDU(hA1WFiIH-v}4R9X(<+J6OAv~+!$Vq?Sg8mCLH|@gl0N}7A^QgFXzB6im%$pdJrFT!= z&t@G{OR{7i;D&ALY8M=|7o8_dUyi%)?(eT`yn9z0)F8xw@REGX7~`r^&3o z`zL{g-YGY$(Dvpao{xFh{nVpC4W(eI{>R-LkA9wfR%w<9)|kcP$AlP~v2auagE!oz zoWIa*ygQfR1y@OtU~n>_$9jEfm7tq;hWBs#cfrI30TCg0m@=kO>l2?uJLkgn>CnT~ zo=F$qb;As-&l-AuB*N2&PFUgBN#XxRoJw|3h4)KU9z9W1mkIgf1Jr|ZV5~tQljuBq zo*FZ=5-~v`nSX?`^%qe@4%1~$k4pE3rS2)uZc>(tkHUWe=8v+0c@7L4{fb|X3nBCN z`Z{s#Idi~o0C!7jTcI1ITb@m0k{I`C@V5g-F}}DYmt3BPSq{W3hbZ;Kp!3L6;({6x z7xV0C3yTwuSEn3P<%Gnz*;t_}H&2-A9=Hv@ODuRD7;e=TonmlzkEu zFPV{l+y#5LtQi-UW}(;;uttr7@(ox#N|Qb{q~7f4(Xmfux1PmJYbFWFpV|}9HH72o znHP6!3~kJCHxs*&e>Bt$gT}IQ>K{K1PWdb~n~s9Q`z=FZ^me$9$T#--(Tn1OFS>w>Pp1*kQ? z#0~y<539MJtT2k6HR;p^aZ@9(P7R(A5?TA_ zroVZB89)6A|M)oJ26gB^NrDF|wa(Y6dQh}i380Dxx%Qj)7*qW!mszAqrCBuan&qh>6TqIYNMxMiMRsDqq^NVP(|+TH=P-pO z=2(X(>8~WJbiMWc8f8uvWGWQ0CYWSO9Bqz1bo6}G!or@g*TSOQqSwZx%wopDxNNgU zG_rkdjKGS zS7}&fBZIml8Pi>JtYsrzsfr)USB#4+qWG|D6;j-D&S6(y`yWffAHX8~X#MiQD2N~4 zAkdktw39z6MQ@Ep#VYy1yA^maMGd4SWFgG0)xF^D;xH@nEAF_KM!r?fj67clca&1W zG0fW6oP-j1Ld=ln)5=%K>-L8a;9-8(Q<=?Lf6aaZEMa_h9E@a!7aaaE9pPLvf;M1Q z$F@qzdv(8Nr|}W*ba{BSAMJmD_w+f)XD9Z<@F{=NsmU|v)2hi+XInAR!EnP8|9VXP zJEB#ij#E)%>WPVSn-lyRX!;76Iw5P?s0b(AnV)Z7b^H|n#f3e(_Qy_Z#>Uv5aMZ@w z&SKQUxSTNBxFTzK%CN3i_HRDSd-q?!Vx8@HLe9;fd^h*MI#mI2HY#8La%60CQgs?} zYjCyU^6IdMxbU9D7%zw_IXYqWak`OD-^tN(hbJA~FX6AA8eD#*uS-lCWC|WEj?tGM zx@LDFU{jaJFS$rTNBalV`i4%`8qL^9XYEI)Yb0mYe*ZrLYFqT_l`U~ZYPF$K9Y3aN zy^|J?0vZ>oPHo&FEnzuLY@y0H1|1zl9$!BE&=yicYq)|JrBpI5*XD;?ARKY=ApHF# zsi>{>Ve#?*zJ}7*7AB?K1RK|&SQ*4qmpQ@G;Cfx5($spL>k9K3W5lbD#uz$Q5T9Io z)#V&yE|j#6CaIlNMYcBAVtQ3M#1x)Ghp+e|jUL2R!huj1pwUr*I9oWt^h_p7NywQe zg0+C}maBy?ubZ7GJYEKZLclZw$|$-O?CX?jLUb^NwqNWZQG%C9MDH zxP|g#1K@Il zchb^c=H|`g+AOfaw)T2s<2dfrvP|2#R*ybFhJ;RqjxO34lQlOA0bp?umVr$@_AxX% zP8+auUfIq)RSZ{-JfL{FDC#~{HNH>Dkp};j`mz*x7lq61u;B?{{LdqLYW(jV)A`GX zMn;^y7{$bnXY>jImPxf-t5KN?aMKyIUH}6)g-hUn;Dfi4{SE}_%bW34=v32unzu1~ zt57p>D%t{{;Zx;~SlskKy%AcP5JEztbNM}ZugiaR6Ci2|VD!N`IRVco+daAV|Muip zSBu8S$1k??0tt8lax062!=t`e+g?WHHxp}4bq{t#-0ZAgr|{z10$=1%<3SPj57E&q z@%E2D#r5$T0N?tl#oM(I$dm!(p|3U;jqv zA=}aaWGi6kA)&&Rzpq%IYD;xPp(b3P2@MUELhWx9x^uf6WC) z+osi#GLq)z>Z?9?*9!9CX?g_U(Y$LGm*!rqYn4Ax@dzj2*0>x-=fulO21;Ikjig`S zBu{rgT=b)&QEc+5(KEaJ;)gogw(AcShayhx7TeDkvpU&WIN$=8l=H}#K1=kNjhVv$i)&6~f;G_fizp)Y0+?pvv9O~TKfh;p7U_O> zm3=n!xD<`5-TR!J+iW9|>5>UQy!Ts^)6b=)asANcQ-r<8yn_`4Rgn(i%TdG z(n!AZUDv}-+D=BBT{2B@!+^;qDPbu*n*p&&u-Tl^&{ANtTfwI1VejQRL&I~BHvh5M z2dCgbG-am^@oRgXL5Xs;!}4}0!Z3Q9f@RO~r>5BbMFJ(H(pl)?=(zi93}uJQMBP&y zai%?9z2Pjs+wH?$h%lu!clv0CxZmd8_H#X?x5LjhePJm^7@fKvky;xt=NQUbWaD}4OFCsvx8aDb+&_qo(czTe(POiYdeyk!Z) zH&6eGyw(iLH=dm5fBFz@=Uf&9ibO9F4fpsX}?8BO&=-nSoNDWFB$;jndP-fMP+<@b#<{bEg&KyFZkzj z72@}B?V|`y1qq*OU=nZsmw95PWN6TTG2=Ow!hd>tD4y=Ont?8$gms3KXRT{girgy2 zL9VoX!Bx{zy+9O*gViPgy-Rsv+86oicDpgF>}DTTqQ5H9*s<-*A~4y4&UE9;5m`EL&D~Hr4$^u%{vS*w!5YZ+TE`S;nyWVJF>( z*pn58!*b94ry ze%**p`fB;F1?K|^1NTiBVGbY62L=BOK^vPEfHl~D56+juN;m{+W4an2{}=FZUYYz1 zn{3dL5Pzfn{vy8CQW;NTrV?on{`&2OqV=XSNXv>~n#iXo446rbva@zfJoQ0rSd06f ztnb}!K0$qU>ZQ6{?zed?y-eMDimKn=^gCdP?sD(+y48r?>i~A3I_|5VB%eP?zshIt zyzH@cN4;|%MJn{rkj`+dOcf;M5plgb0TaL?{^>{|?q@fZu8jtl+%4@J1O+~8SMP0M(PGU*wT4K1y5;-pm9E6dxLT{@v|S@=gMMhyXiwlH=;rjfI27}`F!MJyba!a@K!1AL&TSy4<5gT>UHdlZN$`^3O+k5U1Fpo5 z2Zg{fbN937>ZMb@pC8WBVRd~w#+PyW?QIHHfdr0Wy#Is}ucN5j@Rfyw; zP>q9=q`v9|ic^++>sY+stZ?2_n0r?Q+JMdML! z{9&Z`pnLHE^P%pR=*nsB@$|8t;F-MMZb={VqJ9xEofBuH>jcYYk`&i{7^s0cV#J*A zJR8mMM=qtFUQulm>&&KI{F2tT(ta5o&;S?dF|3|MlonKJvm&p@{!1pV>F%OFze!Us zj83b32+~ngqpiE1URWOWTIzQz*04duDFLJFeC<*yUGH}GP(qlt$bl{mC`@+Ry@!Fv zn`7x5W%RYkqlX^krT$Qb8`XM1tl#7N$65Y%Yd~+`ZB6S+?r#t`*8j6wW87qL6!v9T(0u?ZEu7_KjkAKGB^ zWcy?ICNoApfAjHiwq)`16_2@;##KXV+C88TZ#!-`Zww4SZ%1&ffF^K`88|am6-&b( z?H0(Nj=)9U+|`cxKX18%)W1ua2l<5x%ueP7t(*L_d)bTA{r;-{*zdRxq&r#umABz- zmJ(wEhWgC3ds@1e9?SN@HZboV+r#ISylvZ;U-=5|oEuv>*E}LBB__{8sc6Lf5T{=) zMXC4hKAo3L)Tl|kUjje`<4@0!H=krO^!;KGw7AhBrW@PtJ!|Ori1qCG&_nhzyHJPCKGcHb(9T}ZGkhZ6}$Et z@MI#`=m2lcU#=|7nxYI#8}O>BPvaJ zi4CIn5UvSi&`Le$F_xjX6?b>{^jc_tLG5Kx)q{fWLaM-u=TEPEwVw_4q!wcxxeZ!l zj#`?UXgK3%nl7$RWDLVgeKn933D7IzFR6|W@tqp?c|EsgS``9-^sMo>HdHRFvXj9=>ruX0L>n@8glfza4riIa& zVo=>VGo6b{HYl4>bL8q?W}=AmTv3ui@OsnNZ)vR?BgvVEj}%2c&1dYPohTCToz+f$ zrSJ5*94@t*_Q)Pik=SJJ&bOIPo(WBIO1jJP_*}p)FF>~;0Fk~LPJQV+W$}uhgX4Bm z8Paw>qaZE)lm#-w#ydG;t(7`8WiPR4Q47lAYdGUK;wM+XTTdPk6}0+aE<>Q#a8ks3 z19kQLaoHhC|Eq(UjlDh!J=(ft*6UfWLYVyZz(W%I{n!ayLD$zG1?7mb>3G~eh-pV( zDny!H_efvDE}#l*bJ5Mldq7J9vW-T^;o$+YH10^_)Le$>JcDIu1M;YY>182C`haLc zFnZzY?Z&d-*NbOYs1|Uu0)r2F_va)~aU^L-q@eE|XD9P*`{@A%m#f)lqaVdC48iq- zUd59e{FW<2;05TGjRA!CksgsA$k2htY8Y0Wn>Swko>UC3wKhtvan9r}@aWEJGVq)xt z#LB&A&u6j6L2i1kx>^?SmbX5SgZLLeQH?b*K=P z*+6Y28cV5dd%Yv_a(`B=6=E5L2fAE?;R05dou6spVh0cP|k9ZqZkw-Q}bXNb8QREg`Gn zkIGZE^2#u0@4xl}%AhUc5QN=Drz9lHN|`#2)yMoAvFdlRNZE;j1DeJ6MZdZ|5~on@ zCtw{q9um;f(h?MJhn{=}2Jf;qnzYIr(O>@`9yl!g&b-+2IS3D!;a{Rit?^hJro1M+-#=1XRs#dm= zA(7h6C%2lVV&WbLc|%WLtE!IY$}GEHE+cW1K2rr@z2e;1ZxlD`xHCrt0$CbOZ~X4K zn#g79aDCaC#hI=M{8+L+^wpe5Viy-@XCz?eS$()~)!&>rn6&&eRebrJLL^`nKgl%l zJ;@bB=@r_6J|2>763_r}`(Di{i+LeH|A$c=Y1zK>ooUCLGo8`K_aH9B8)9?ZV*Y;t zUdum`)>+y?R%fe*>m4-DXqY%a4AeEX^=V=9xzss9*an9F#{TAR=0KYa`9D0X1i~3O zu(h9me2IDFo+h1Q$(??JaiX2{9OwD$8%2~4pnk24k(~`28w>jg=XKD=1|l&D)+^n2 zb8~gv-Rg4UEEtXX9D7=bEp7RGfl>ZJ&rYerkUX1KL}M~NBj=pLzT5ukuI)K+hgpYY zf~1==I&~T<%ZJ;oQtxn=%Pnmgc=x*GPn(QZj2}}c3XC}HxAE53-+=W@7$L;SNGl?; zL-KOv6B$HbUt33~VtPkHk|qP<`ALwhxmic6G{4$mJv{tmVuIS=i-eL=ys;8{-ANF9 za()92JOBLoO_-riO5AFJCm8H<2xrjd0G zgoVBpvz(Oy+YZ3B82@inxBfr$lecJ8@*Lr~CVX5bL=)3T;%YFNJ&=d}?g#QN*^CcJ zp=!)84H9c3{))Qd)Udb(d12=U9~e9po$4X`{{UAs=SDYjNTZEIs0>}-!F${#-oJfC z=T1d#Fo7E$i*!63^OlCe?Z5R zcgb~c<8nCs*lvD{=Q#RV#eKb~e@ps<~F{&~bos?Xte z_wR)d0u8=-YbW<_U*RV6bSXcvJeoEbgcOGj#NRWkcCx^F46f z*-r43-wN4x6Ry|e@u#L6 zgMKwSA2Z*Gy;(Eb)m|Dlthl@ETrN%ybWpCNS#Hz!x;G-c_xALZ_djyk7nI^h*%M0a z6AequxJ@l3JDsu3Cw}Ael_yUBMiD-79loA&h=h$|yZe04G~KJZJ6>%`_1F34_|PXl zYUFEQud_~8GG=StaJ(bF?0uWeqWZC5v;^`X;o(D#^46ninc}0*JTlSuQ2D&HGnBne zi<$L`!?#vE&V*=cbh1nqd49NSt59whb2o0(lKXO*!m4l}Y9I?4_^sn3d&i4WebzC3 z))=J%dS!E*jQ*`xhoNkV5IuoP4Y3Ygdo9TqLLzjQqt;sZk3P3Y_WRGpP44tT*V~RO z$M>c;%Sl&iJF`R|KIpav^^E>L8JYI5g>Xy7je&&0JpBeK%)ACl{sT=a)GOoyGe8rQTQDQ{%;FM-QHj zh24)g#m+1Wc0D!)Jm@HpqUU>!8Fw8HG4-tC=v94UqIQSU*xGWQpCrC1E{5rikDt3rLLz%M( z-9suH89p2-XCOLh4%;Y}o9rwKNO>ls_CAZbmstMwWS(q9xc{+d@z}g?#z}XfGIzJNoDvdx^CbgkzU7J*=C9-sSlJVjf7|KzECE$8lP%ea2qwwn^>cH-&)&*%V= zCiCR}^+n{$Bcc16H}^Hzx@uS27^fE2?99UvtC1KkQC<3yQc`ltGb5Yp?aiJ>Vo4)? zwauP2mcku6IVvT)39;D1dWTh#Kc2Lx91;8qYxx(Y~)er)oo{SU<*jr#Uf z-V#16gcue|^)uS62&skSX3HTH&;S(=uuEgSF-k{JSA`k_G9d z=<2|xsb90FBRiq;j_06Uo~uayOD2Y-spAb(k+2ROOudmRxU@fyoq%K~vDbN3-40}C z;au%@axA82q@Rk9A0YcPs^!95iWyM;M7*x)tfDF0=x4g$&+7jhIcyLm)?p!EYFs~+ z(LRG8=cyJI$#9ZeeP<;iPGb4=hwS9Z@PeAHeRF%m6j=Ri$dz(b7gKKk59A^Tdr6=|nPQe#!Le(Ib=#Eb80wC`#CI?&vI(u|9t3rk~XppG}{r(t*&y6H|bH zmhAoI&fR-fal%704-q*R$MR+FQiXk!?0PM$a<;}@IO>6a{9fGSKKLIl#P7*)x@&g~ z0eTu#^NsI#&6l=DECapaiCQ1Z&DvT#pRe=%atxitt)zOVaA&b0KoiI2&IXkmsFTan zyZk!|O>7hOwdq%ev4qc6sBKvK4+7OpE;n-jcO) z8_(T@&4YoRB_}&8sE7a_B}v3SobOSfk|sx^Rr88<6Gpbs3spP!Pc^~{GOk&%PS4Jq>3PQ#fP1t^2 zL}pJ0A(L(93ZtV@37v`@7a3xw;q;vO-F!8>`eC7o6BE%Y4ABNrCZ88^_ZwR& zk&1(J8|{zb`I^NQ>4Pm(@&)>dJ0ZpR`GzZzhxN)mm-lL-nR{AcdC?4-3_t5j^&!>} z>vA$kvu<7K8&Y!czK%tgWmYruX=Gp$`hP%9v1qXr@l#&MGKL0Jok}D0=&?TFrX*2b z8%~`>9tM{eSbN1CrgGkq&nCDL5{z!?ufgvCEn{%Fbt)xpd{skf%4k7AfGVH#3ZhcE{ zrSLncitXKNBqaTQ-f#dH1Nv<={-&~(eWm*TL!T{Q|$n?s1%1O??IaU4jtqiD=Z&|BB4*j1|NGV6v%y!VR+U(ioocDIqF_0-M)djkcwczB8yM8+-*lky)_W+)U?%c1<>rUq{LKaKQnW>{(d=am09d{u*d?0AozZ_Yz&10D=T NPFhK-LgHh<{{jmw;v@h7 literal 26845 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 F{~rNmi{JnN diff --git a/example/presentation/draft/test_mermaid_presentation_20250731/assets/solution-overview.png b/example/presentation/draft/test_mermaid_presentation_20250731/assets/solution-overview.png index 894c44caa4e72e947b5539d3001f90fe444dfb35..9f38253f17e425efefc6740b5dfd79730e03083c 100644 GIT binary patch literal 36599 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 literal 19169 zcmbrm1yqz@+y8rm0*Zi0DlH(=9nzv8Qc}_>NP~38fQU3m3kWDkcgN5v-QC^YHT*aJ zo@brstaIMA&Uqgfvj%4Fxo6LweP7r0xxU}6zuY@QU z{HDI3-3{)LY!$>`L3uqS>kvc%Nr;NPclxnC?Wl=+dV{v-Nb%IW;B@!_h8iIJMzluwgYW=fhvg4PQ!QLHJEi#~RIg`VC)KEJlUPP>Bedy0A2F3bMNg zKcyqNypMWAlUgH@BfOlR|C~9VUu)lPw6!!onx)!hC4ZD9kte7F3`wrx;pY!`q=L*AmIuOd-jPi`$5SrLs2>Sj;$_GU zQKgP!Gu`{sN9XX4Il%uZZaU=sOO=9sVE{aoQWw{HHru?i#$jyiTGvB&KYw?+qRM_4 zr&5!w@A(=>wKsRjj!0zt$MtrJsAXiHd@M{u{H2=Cw=yf4hq>D%oFygD&$2S^ZJFfK z8hwLG3h)b`PE-4|cl$@=m!=BH5FX*u^XJWnL+2~XBbgHSl^w9$Fl8Xxu3lHS8!YJi z_gJGknN>3re8MG-@rhzyl7&+A!^69&&%j`_va&FBAn5Rx&0uC=7|H!}GiCqh^@ysI4PyIE zKDOzWCbQv_X)yTC)o#f1kDpZ7qZk4H3#QqF&CtPDNIz3xO+!L z#`ySrdw#&(W`bgcnbxmcbd!HrWXBLJuWp}jE})s3ndqZI_{*Qc0zesjevWqH@z@y` z`Yax5Yh&h!5FPt9Th2g`SZ9*})3sc%K1;f6yqOXgz``JUu?$ne+=2XZVmYUiUo9rQ&}Dm82E zhr^GSemhGklh)d8`YLVW7k|>JaXK0Mg=l)^Kyq%@5pjDo$9hVgUy375T(V=Bz z)-gd~Hdj_oZz@owR}abakKEpxwJ*!8_TC{4G-iKL9UX#I*zxCnM4NO164c4Pt6Aa^ z7#~xf=r!LRxawEwbM7pWuYK}_Q&eoZCSHm@OcO&G6)FqqX^!*_+f-p7e%z5H^M0 zXV7S)ji?oob~$Ee+Y!_4tM{zEK97q_a6MA!;&VO1j%g$2=8kMzjh`GlA!a9ma1cC8 zyTW$A#nH&Aa0j)o(U4whzvG574!I!D?v*_*PQR1ZKh2R%%a5{+jZI88*N{CEy~6Tp zy#fLxZ$3~(;4av*b3haqI~LI1!>z%Of-FfwmF7D~ESC=awnwtep@agajBL}w1&;Yh z4XuVN>U@0V%sP-~U#zXg7O5cL83qv-Dnuqe{VdvUe~*)u{p4Vs({W!Cdf|BW);q@O zf;MYTYlo2P4R57u!O#%$kV_0uh3zs^Ol(oT-{IoQfUbhrmm z*SLtRw;fdWm7DcQ%c4Mao@AJ5QqRI2$JHQK`!mAh^uX*aB1RKa6BK9|hnqETqd;oCLd(&evXFNouit=cH6{x0j%SSJ^A`3>wI`6S z#p+7|dn;=+&&KL%RIz<7E_b*CjKscNgd;j33=8sg+!m-dGm5a6+tSJ`91rk!`T7Qu zV~PrQy1Ws(KrKwGiW|Eze&O8!K@1v~2Jttu>5Yo3qeDYONe5nuM=3`b82lHGaQkJq zQ;$0X5fN$br-PT#BtoAC>ce!n6MOWE@Iw9FhDJtkF8P$A@G)Pdyeyd_*|~xLc(DIw zg;{&OzrTE@`72x|m&hG%sQ5q%ayppv@Lo6Po}8MX;SemXs!|u1)!EPAhw6kVkwiO( zq-)Tym{}MmYYm@3b~`iKPt2-ge1b`#kH2YfW&P#9#HK2Fx0srmE+h(-6_pyX$I@qI zL2^%N??6%-u8<#WKL>HCgkd#_dQs*_MtU72-Azfw?4R`o;Z%#L5&3KKM&ZroMr zO`3+Sy^W4jAIjaFzQkPPqBy&gTF6VnlJu@upG>>X>WxhB_H?Gy^&MIn)7{nH<$dt+ z-QW&4&9XH&ePJrSUo5psKaN%Sn{%%og?YQ6eyyE$!Or#g*lb|SK&(V_I8izHOw328 z8-WFpXig)|_3cikyI(4TD{MPK%Th~7M@3`umu*b53d?MBTkcHZY7@*g_kp{HC_!N9 zQ4DEF-VWR8?$*qat%UrqCWXFg10s z(1cqYD=_f;Mol^t-i&f-s7`)TueEAgAfKrYi7&N!QmA3LImc-yZ483bYA88-Y?sd_ z_oe;jqbJrTg9kn_vI(q(1(6=+TT<_H#L!lw{6rQ`2viVVJbQD*yxFisdM@gmoR68A zh4Do4_a&t&1+))|Q7bi>X_@-_253TTU_&Qdo#f)v=ZjNZSrdsJ2R1Z;EzA3O$8^k$ ztgP(OlGHeb71nSD0{{ZjLu60Ps?-_GW#dFB7w zuT=w2G0_J!=&o_@c7FY>!m>NURcddMGJ_yV@1;Q;STkQx0ctqg!)dKUt|+Sc*DFEtKSf%ZBo=t&U};aD2QYFqRHNdtdFH>4u>)oJMz@C zeVOzg*sb-=AFU5!pn5y0Yinz(sPK4PIT?&*Gu2xvtLt8!?MFvPAE&FTtA`MANjh_x z^0WFe>3;aopDGn|;T`Mg2`MTnrYdIz*He^rWyq)C1t-VGj<5BnL}{gPBYTgr6A%y} z5D3wfu^LxLbF9qI{0vMd%P~5w&CMAZ8FOpjUXk;<9dg&wAE)l=sMr81PE zcVH|mv=j#hKERjt{){U7o%OY>td75uLPlmL)`LlYkE>B~%!TlZSN}l_K5vGGk+xbJT>F zR}5QPh5Ys`tt6`1lj>W6s?+Se&v@6<1j~ zj^jVp(ZS8dl?mo$x~3*Nnww3KpC4R^lau^r#>VvMbc|iHGBN}G{kAqXW^Ph}Yiq6$ ztJ~R&WFK2QyG&sohD{3xhp%~gwZXx6e49+JP6h|Uc}enOV}10_tE%|S%-~yFK^-0F zN=n1Oe>RKm1U-l7hR{qW5TjRa;H1@IzDh*qCp#9WHKh zOCZmS7cZVaf8LXL-J4n-LJH4HH?rED>1NVU_HUuoTiBb|Pk)!trpxNErRsQoV4{~? zR@M{rMEGc}pAb6Pokd)o>#L}Qrpu-v&7JL=;o~n)mgj>nD3{jx@gjx{gZC2w(73eHyp9eMZprMA-deErEX&seZJ4bFLwU z+j6GP<=6olE3*ierlHb~e7ikUGY@wl9UUINygt=QPW}Wt><&$TH!b9}H+8f=3l(BU!xb5q^8}T)SSmd=Y zUQQdW1o#D@jEzGw_Nws8?LIiAAu)G_-^H`d^d}-N&tWlODDIsyO5>MXL z$Q(+{v%NmJw%GO%yEq{50eDR)Ssqc?0Ge70uV!*f=gO?jh+#YVsv9Cv9_QXWP(_TeIJO zK=`J9@i>?}to!$6Bm-{t+t%TZmNW|H(S-cBeD|2 zliFIXsVM<}!e={P-(q78b#*x%w(zvHYGe^>v}sFu;{yXLm%A}Z{En3D?2Y~X!A&puCw71{&%+qr9s7Uxtk+_JtG}d`4E*&NQ*d=17zloV)w`{&JpH8(0ZY0qlm3Y&XeF-s%NOtaO=f z14iciD#LE9hoM-GJDQV422pxQG>1u@I=K2*8yg$4Zd71?0}1oV*^*ZS2@7BQh9E(i z?~}i4sHtH=06LiHBPyhA^qb*%Iv!#^5Tu&(b(!H4YD!vKncaG83`^40#pYLVW%{*r zUK~I8ByS+ZqwZFmoSG_VHX@5GG9E_d%E)8^&CNIQS5>*VxLgFlnz;?wW3Mkz@--`? z#`H_e9g#hkmcCp_Wn~}Q+7{paTm_B`{1B-m7R^}<06m@ubIHg!2BLM>kM@_rb$Jlrc z-gWZyGE~KYF4ysP&MHW^We(&@)BwC z4dr*|Gv8kr2hoOwp1#8UasyoLIXUJ{jVI5Z)ocuJK3L#j<>cI%z6=DX-v$>b!)9)2 z>2;HDm_Xu1`7ARRM=?M}=Y2|U<{dS8c|@Y1hM)Un>t!yOiH3%!gv?)Hr_)P9?x;%d z@8xO13mmq449VtbY5&A?7&ZPBc?zPeGacN)QGj}HD^ z246}}?sj(<<0d&YI>@m$Y*wGEp~7vU{^;>zyT#UL(7pSyXI?I~PLD1pEs4FoU;BL| ze$u~F6w-k~8Q7w5M2dl`-}A#qF)e7U$YA(n+xNTlN_zwhM_d(Lrq6KL3f(-thv&pV>{=qnwlQgcw8%JXtcGZ2g<2}{Hz3fvd|}eeTVbQ!2!F5hIq@<#QnuO z5E}WR+h9{vM9FBr+Yxo>pUz>}_57k^eQ-5NzO={Yjl>B=i+aCq44M_DM2zv!zEK6!Z_-dP>X2cWQMwM2rN z_1I!MpMj-}qh~x>v25gMmd zA|z@%HGiZyd( z$QT%h()PEb4`3*#HJv_1)=MKID2`~#HRUlNGNGhUCd$9qg@>-jsLVki+U+Ak{TlqU zKBpDE4^Sv7D(V)(yx)F}iz7n)3w2r9*}`u4Ttf;@B#-)$0aWcd2?)5oW}1ro=qE}^ zLZ$EkZpi-r{d=O>n1}A@;L)MsVXhkw!wlYAVZkcsEow|>3mauAAT&UaEn2DA&kD@m zlz1{xJ^@j3j7#wrsQ@2>cN^oP`panc_V!nTe_x?HD$TnU_lODbp)TuVro)=q z7dL`Uzm+!sjRhKNAe6(5eKG24!YPHhFfEW0dM-p#+<+}9eMJ^ zULxjC0Pa{?S}w40`{FfHl#PMZCL=8!6dc?ZOq{+|RYFSr@M}%=^KVKwMxmFFFULZW zJv$h^)71<*@`7wwhaV>*O}r;~`>AxyEY)E~oj&WPpJTkrksN|v&BKml3-go{PpW?q zh}?x#U|MMtFiyW4>mpO!F?JHJp^*!MF@inHGwuRtvb zeloI&sGmRYJMoxT$UOQJRs(7kc?Yq#$jfvMjp6p2=z`v36a9H+G!<1Y7Z(ms zcx@VM-C;=eC);MJ3Uq8z^ij1Q*9Q&We~ykKFJjm`J3HNv);@jsAhgfP%i91-e=UAc zmh$p~R8$VoXtt)4*Tt?*lbH~m0sM(XK}E$xzu_P$Ie?aB2XF-P3ku4}$)QLCIgI96 z3n3vPAk0V4Zkq_%Cl!JpyW?U{`9~n3UfnILE-A^d~t2S_hkP`svA42%Co8K~YU-h_&CE7BIceFSZ0}avdayj(+AR7A*Y_bg zzr{p(v5_nU3DUVNn+d7@PIkQn_QL*WrS=c?uuO%69kWHmPp{gk3%6$Ka_Hayf^$9>c_+%a# zh#Yd5=5Y2XP)h4ymxrsNT3UjMLcyq>i*5PKt92U1E8;ClBEDD&1k6`zuU{VmKqls9 zR2q6pO>K9uG~P^JU#NcxY6v>R?jPrOoGpa(wt4bTC{ z(z;DEl5eHm?6=0edJ^E|{0{c}3&&7jZB2gk$ZYyD0bccF`EI@r470eT2y-IBv=OF+i&a6D-l6ZieQ z#Z-lKzulwtDL9WCpfXV6{SV9odBR;U$pkN$b!trjx(W*NfAuA&Y;?K4XelUgcfY_8 zaM;@L#~oemQX48YlTH2@n`7AYRSWH5;^suD5x^q}iG8C>RoW5s&woB5+{5PDLQ@V7 zYPw;8MQaD1{>1T+hH)2N#N`4=okTC0T0jR za_4gZ1rM>X*jQPKggxRwnHI%hgjC| zjr6lheL|P7Fdpae(O+j-#31%|N!~OkAj0AM3Vd$bMiAgshP9V4Z1tMlzCp1V~ z`%r!E^50$np#Y!B@>42wfc^|BJxMRD_Zod>f4s29hQNpO7Y&bz+1%c4TQzgjO?g5T z2YJ4fyYMnF_Sw;IuBxhv=V7_y>F-||5P;4$c5rZ@#Q0Kk8n*Q3eggmL3oG3=P^;S5 zuoDLbYibDsW`^Bd$M9Hc53HwWuemhNN|pz3L|Il zy>_mp@*R^z6+q zLKIKuQ^UgATZ3Ks?AC_5(7~V#4Wl7BHMOTWO1ykk=ywhF_j`#MLF6SPziDi44(eRy z{(ijFP6ZVd6qsn%R#rZPs$GtQoamz@lZ1k~+1M7XUd+$?l8}OnfGjmL^I6R3BOXSh z;&E`^e4V=AC#p3A{Uu@o?tIeX;ygkKF&mrDAkvK$D&BTPvQtvbM4QhiCe(Fi^T6St zKDb2jgahf{3^z3O_lWJ(ZG* zzdW^^fjcVd%zj%NA?_RGpm3Pv`AZj~7;LX!(cr*q`uk6lQ+A70bKEb>kY3sy)y&O( z^T#y;3^aGSn|>DsvwvWq(t2?L1a1iuqg4C}l(01yz|WvFU~WPB9N@Rz+T(>Z8fhBa zmH;MDnIiylH=_|eeoP%DNl$;5oBO1B9>dWwzppPgfC8tcGBHu4H}RTWuqyr=c6xR; zZ2nb6S=l?)v8Yh8oxJR9xD(rt&ShuUOFEi~v9b7AwV4WQlZ9qWzp&XXC1D7P>5S*z zp8WZbK{HpcT1iYmCP`^`1F*yvO}Xsl*tWMEqc{3Qlo+K)pS{ysj=oiQ*efwF>v zTE|^Or6^X4pN{s&9pK}V3Y-yJ`$@{kjb`87^97O9bk{=nar^fMr z`#v=#MFaL)Dpesi=Z#jvO|6n2Tps$1X`eL947)>QuR=s=b4Y{)tgg=T#e*Kt{uDyP z+QN7!Y&YL{CoBVug--k8&PR4N=gOBVD)}NVcR#a(#;x9!x`Kix49V+fQ19s3>Fyb2 zcC^mb_I4y!8D6vmoS=~R1|2MbuS*luRMmduU0o|e2;b8?Gnsy48 z(}A$zZ|5eClY0v-5AgBvA3l6&pdu=v+V@MvwztKErbuLK+~M8i(|H4BqKKA*?a^lE z4nGnSDxlX;+}^?)bXnE=#qiX9Zu->R@D{9IG%LwrEB(V06EmyHQJ~ImSlmZkGxU^L z01XG*U-T9$9F^ZTCg1}&kf3zzrZ^J1CAJrDsJ(kv|1Cb@p<5gI{6ih!40?qHW@!XK zX#%~ONG+c-R3J2|G7^LUO$o3Hz#=RSaE4pHSlquo5@5nr|DEN3!weCTWW^or$*%yo zZu{ABw@Oqp3Q(Wq6cwBP(Z>Kv{R>6_q7;h#zCA_edvz6+^ey!gx{Bh@f5k1pPx~+a zVw${?5)h(p@n+7Z^6@{MV>T;?<*59p-d35`S0e)B%7=Ry%*33E+h3^B*_X%iev7JY z^Th_^s`FE=KkoC6kLpVLX>)gI?ErLr$~GS(?-rEsN0&mJtLt=mpllUyKqa(B{QD@7G$zg8r%S5nk?cNk-N@j~xx zgoHrDr@b|VIP7V}NPE`in;s5J1pV%I+~jfJD4Rk`hTd9TYR=D#^W#Q>+|L$d|D7BK z=*0)d@28N-DJYm)t@%>IBrI(7U6PQbgnW{}Dx=3f<;hGT&9X(0 zt@ixrRLUUt{l`+e8b)y2cX*;pM74nK%`6)TdHn=2zBQBv;6 zO#7$v&s#1|&cagrZ|y)%mjFWi^t6-tw|1*d1L?}Q$@!AIG$W&au$apCuvaY<%orD!1O+X~ zb>)SHMy!t^x&Jr02cqETPbn&TrKH3~N0->3`+~QUE2ArzI0j^9*JC2!n%vM-dL}I+ zgA>@ItXxJzV;DU9*13{`g{5s`A~8c7gnoYhrl~1Or6|y|dvnwxkXYsA^(eHhw@Z3+ z;8|aNy=tM0goM251~H%|(9&XJvS=A8E49zb!2bQ4IxE`@z+T_#f=fq^uPS34zhiQe zPWkumm(6(ONU&E$znQj1I3#4ywO7A*z|?M!Y_8F z;gtrR^euXzshPlMPv+e)R$@{aN5n5E==0sc(9p!xl#KWi8>-NpnW_xDbLSH2rHe~P zmeS$jfsOxgP0cj{lY08EU(WjrI-nuI#Z~GT=qlNzUgHAKw~P^VEyGp~@E9UMZSZ*g%)i=l%m zxf5xbnWc`q%FtM;87|~@Jj^KD8zPEQi@1P)XljM(GZjA^!`E8^N73#c(UdualDY3r zRlbvUbUdA?uzt8dnrGKBYvyrC<1tz04Y0x1!67u*eQj%tjKIOU;d5zAix23esxT7Z zah{D8`b9C6JGov0E1DQhw5@U7brC=MhLHBLL2CNophXy$3BwLTw-h+5|p#+A8-S-)YR z=l-Mf6x}LQFI?=%Ax5>L{?^u+{{G{m^*V3=9l@{!vl* zpppihtyXEX2?!tM?h#@$zX=pgKqdw2j*vzBA=DXtZF6C_)b~pt=#oJF%2%Bm&R)Gd zu{b>1I=kF$<2D~N(ATeX*!~Q<;d(ouyML>6*{!|O)s=I*3M6FF(>SwsXYP1-TV!cz zPQ=E=p`lLznD>7 zJ@xeU8+e5iD8m8zv4i*7n=4DcqElSi*dzvx4Qt!OE`T)AcoTm_5rq zzdRi)T>O@rDx*3!L#Ox^NUO;8DdLVTdi~#?>Nso+bq@>}f~pOg1IXPyr3tc$CUdB9 z=eZl^g6YiHuQzrbqj?EvoiHjzP>F?If?a16u9c+Cr_ZX+W32y$oSG&k>?p ze)tFv^M1cLXz#?u)w#wDIyr*^3cxYYkWmK*2WFu9(^=U}VR_md^SxVp#;%fIXhB-q z*FPhOYkr{K?$4uZXiV05To=Xe0v*YsH!s zXdGLxSey02;)vj}$5*t;82}QJ6Pv$zc7IZ>U8pMO6v?09L@R95HCnw3Nz)WpR1{QI z5kXtq2@nM@uL$rZ?B}2XE{K|@ z_0gcB0*=3OS;J(1e?OH&uzw34T&`IU+N*stG%V9nrCg~b@T!D*87lWAmPnGUtjp!X7@|1 ztefP2#2pZgorW?bfMM=zU-;-4^ZMF#Xy|>pRm4qp<~-)3O2yVLHB48+RD zrct&3cW(`s{6>Is!A-6Y8?*<&g*#DYf9#J7tfCqkM)jT_y7Mt2+BFOHI`ixD z>Z})W_FH6u6!f0{+zQ+E_<~Xh(bAuCiA2F^_r{yzz-fbx?UY=o`t{bf$LTb?((S+D zVB%BrnQ9=HuvkZ$9&c=ma*WJvcf}U73S9NI26swJcfARE4BHrbl&p&7dpPabi8#|= zohW?({d7I8ZBC;?lou3$_K?o4BxNy4q{p%i-;FLFH;>I}APfp}xnY=fWszE)?)^ri zatAc2)XU6gT7%&h7Nq_OQK%0hV;&3*-&F4V%c;`EbP}_SNCO#!Ity4kuJ_2_c%v7L z|2P#ZD_~9PT;|FPRb|Wr>sCCTI8ym$8@!Z=BY~8-`01T| zfFH+Rm3D&{4$5-zL+I+FAoIYktd(VZUykF8B*`<}qx5ZJ<0zJMVCq}_TQUDHJw!gI z2(m&}MQZw+KgUPD6L-$Z4c+&h4oiEehZut`cA3%y=2aND9DdA$OIMbp&SK?OYxIO%~s}8_m zZr_Qs(nl-a3urLZI3Gr(nf@=Sqr2`L#S{xDGH08_9k)sccYN?aC;+_lp!Vv>6N~@+ zFTj{PJU_!H|Cg>~9rX5}(*(XnMO=LS>tNFX%m4=T7^C&_(`fLY2H@G#WNur$bqHlWKnP!Ru?3pDtl>cOqwXGAkck^O=)j}^$6=v<8$F!a0u9C2GV7VW(lR?e{UBe7FhDL zFb2wOkYh2m`FMEXRqCet`m;{wpwSMBm$S>$f@0gN*+@#LZ_w<_?4(r+G1|xHH<;$b z$*ZL^ySLWQ(9H;17}63F=Cd=W?hiDp>`Z|_s9B#mrrdh*leqXOP0Uo4y*&^K3iTfW z!MqtS^Zi9Pk3N{eo3lmf#bqg}K+r`8*_mO1%jg|#e78xp)#9`G$fTRRurIy7{NvRR^P=V{wWTyHV1bj+d zuCA-6_`~_LbHKLe`;ZC^lSo1u2>Hs41Slw&p9~FJLlV?)0-iBZ;`qOM?cElV@LA-l z{QSbmlsr2xFFC2vHAaDNE?}Z zrd{JgLlAgzN^WXwi~;Gmv0Z_J;nSzY0K%+%V5b2duo~yXB1*s0-PyaIpg&C+M$5Df z$SJJ27+zRt5@GrLuiE3)d$TH9kwrfr&yznqG=`bSq^zLuBQcRNO0v4z?aU2RPft=3 zY{4N|dH$>=JNpoy>dQ?q!x=X>R$QF=@3NAEem=k5h{VJq)8Q-NAXvyOFP}{o+vMcr z1iC!wi-L&n#-P4*J@p6m|I&&f$l#T@NEDQmWg^}m%{JeP{?;hhhQ38dS3B;G;4^UZ zoL7PKA|ci6PQ%Z4v_dj7D@7?mk1re!SCNr9{>~<%SLmnO)z${vU%=F4E^pZQzsWf& z`H3uAd@6;}joXtdJm#udPDD63e9i~v&>8R^K~{^csX)L09lTtP(|Aqho5fI_rly-p zf^k{l-1TveHC*o8fs$GZN$PN=>=oemXVj|dpP4xa-EOpp2#38nOQ6D8&DFmH?aSj$ zn5>LD6?PY|9*$z; z0=Il^ohi5@2mOZf+qY|nt87po{PZR8$N>`(kVp9V;Q%xcV5UGJO3wb#&fESWX%(yE zC))jrYRv+>bxnJF#6&4SfI!5>=H9KVqIhb0@^r1g9HiZwn z0L~F}7_vvSBYOf;0h$Ur7S??%EIMZ9D=-0InijUUKAD;##<_1+2QIK?1w2TiVq*9| z{xK#bd`KXbE1M(&`pFN;rVQC*f%QvF36GGMQ@dHj;`ud8@G2#NXHp@Y(jOdsN^D8UBLpz?U0Xh?3zqURgM40O@Qs5{7 zrR9!iPL3Ve>tYO0VATwmnxGfX2eQmDJf=gUWTBQOCj3@&K&}ggy<0y)#FW$$uyJsZ z-dZOMVK*VD#RQD1aGT|;SdKOju)Dvr=}1XkrlbnO5ET^_R#O$3i)}DW2=qqCgsKl) z2%GpFcV?Cj7zwgrH%~z=C@4Ch*#t11lQTS8N1>oUYCq02hLueJBxEJ22l3 zWeAZoiPA?QdrFTqb9sl5O`q<~C&Y5V?qOhLWzYh?RCi;>%JqSgvqQ``09d zy3VLH313K{YgT%C{#kl%?(44MzP=xv>+$z-(|~i$-#_1vn~{U#+CAp1AM6(-dbL0o zb^v-j58u}VH)K~=_?Xhc{yH)QE<==Cegd?J%OW}@8gs@$%fMiv>6e;{2?@9oOgkw9 z4FCjh;Nk*Jh4y9p0RG3o(~bPn!2z}KaeQ}KNy%*^CM~TBkw)RNtt@We5`dqiDr%iq zQe84Kq@9pV&-Ij-cOGye;@Wp@lNdx!Vdn!@8k(%1a|zNk;QQtral>&=QD7i3jU;r0RtaMs-wo2VcP$~kTZ*37|qNB^o$pH|% zGFeWCg0id1SUNDEXKUL@v#F@XhA3=bKj>OY>{~oA^ z##&m}oiVb2Jio`PeUH~bss~+h;H?BMC*Te4O%lHCoh2tD$L6dYEDr+PqgK^jaK(W5 z_>8)`q^yjE_Rl16sJ@f~9o0zy$}|zN-yfeIEaPHg0)LR5py2BV4>tK7^MFqqd;k-Z zb`W18I+ssQ-X$$kImOTq4CoVmFP*#hDX=7s0_!pBdr&utiM4AzDYRjCJkT?$W_NuEBiwU z3DZe}fgzzV#NIq9R2dPW@v5;Cc&sr{Q$X608ELDpU)vhjS4{8W;O4#qEdGJj)jt%| z8-Yj!{0l&PIXW^aiI0!*@rkOfm6w#%d-sl}-yd{IUWtq6i-&rE@DFlgDEVw?pz8@R zK;F5N0(`w7FpmF~T!6XYi!b@Dv$f8n0pxp-uD@au1FNB-sp&qjlbMb72)jA8jh34M zXwuqVR4-U2C0%a*V$g+nheX31a4Y{NGuQ= zJ30bd;dEeCaK|5deac24Q-)=fDX0C~|0Pv`kGHhGNjy?FDQRHf6Gs$3HkxjBYU@5x^&1K1t4Zus}XLBRQ{#=rdhkytd=R$mdh`BpILx#-XO7^c@@Ne1R|Ns5ZmFg8!2@5d^%x7XxU9zI9Pp7OT<*-FV zsrF(smeIg?2j9z6;=lJgZ#6r zT76dR``Syes_%@tiBr#wP^W;3uA${?|MSMY*dQ7fp+F%NP*?-55GT$6POLi`q8+zh zCa_(lqWIOVZ|bjp(T*M1BBPBU3i~QT?cFpFHno7#8|;!k;AyIr#%>P-oSttwjqyM)&(z(1~4XXMP>eq|}i=e3g zx4r=oV;St&@w$~5{$;cR?*6Y@9Jk={_fa4`B=xEQ0Cr%Szyl)$pMiHuO{BzAMD(8< z*i^GeIPq7g@U^7%1t0jKu_9KRAN9P!dWH{d9HB?^s9T(e;@{^~AJ1`Ecw`ugPlZl0kidue4=keX_6O$XEtZ&XYL z?cfP4pgshV3C49B;)af!pMdQ$k^kBy0~(n?K%^kkP*(@WaMfE`0)WKrMwy~TW@b&+QEQ>p>4_Z=4cAAOmXXY) zJLEF)|LpGnSQ4*&;LqYe5v~G1rlmvs_k#G(t@i()em5~&kAom|@7wv6w#*i+^WM#>>>))VtW!S?7LuvVNT&KFywM2l6!X&7GHt(BIR@?G$an~dXsMz__lO@2+w!oBJDT(zv6?0<6)34p zuBr&rs-@AHRTbuE(x8c8i|qnkP+=a@E#BXwm!IF>_4%Vy@9Al3!o{}q$0=gpt0TiK zV-{}1aJSL(W_c4wZpavBpr{iGXXYAfyS9>5imOq$FzE};f>)(%_Yq4aC+vGR93fx zJ@8j)@re1=r>1Cfo;&r6f7&!WCa$g;id%<0V#1_;d!3yrE-3n?oA|GjXJD{N$uY8) zvTNB|Z3iuLAkA&~GeC2*<(&oXP5vm1q>RsRI8mT9=D3s2eHpI?L8Q5nN{vECeK@S& zeb{SwaaAURF<+oaFb4!e)n&DzVr$#h+%fn7Jdnqp9P411?v}FltE>iaoOKPft(yI76x7H4j%zD;G3)(Q|BLtJkvtHrq(>u zkxJQbR5KX|ubgSR_+2fTN6P>sCGH&^SmP=wFQ`_Kqjb_Sz{`G^!1-QWr>!Oho*Ss8 ztxN`44Ogo3#Wib!Ji#4<37KQXx2+Zqse;D90x5Tlpm~Rt;Om-qHGHL~mPz26$$0>6 z!(AMA7AXlX%PUq!9)3i9CNW4felsrQR7c9tJs~{DjStvK;gwJ8d0nswi4-O2Q z%7vt)N9Y9v#@KF6k7aexgB7v*Fd?)OU+{(9+pPpu1~dl!z^@50KSi+#ag8?hcwAbI z7v6SEOF90i(foRoA7x6x&(%56-vPo<^KP3?ORI3O%gSU^TjK~aWHYmZozhFgFt}Fp zJ?(j#yB!0#FnyMzz^n$Cxqzv9GaJCnKo26~U1;u(l|>Imq-bCo9tv7K<0&~a-gB{h3_YuU}^hAvZeV|iC>i60ESryJoOWg_=}@zJXY zKPhLGQHF1SO7y5$)p8dTz3jH)vQvlW;j+jtZ{+Vl^^GGWP>}*hsa+}FP285T-?bu@ zEfu9()MrVEm6PkPXXM#?v3ZbDj)RZ=X&u)WS-`q1Imd=db_Z&$W8?UUnniFI==K|8 z2)Ny+@%3a|h6e6JZdI3WTNG-ezm`T|sw8Av<|KuMpU-!2qV=Z{tP92LUo#)wy=km<`76L8(jdC%yKe<>-)XgoVS**W_FLiTnQszA&&=i#1@ zpQkCOu_Wu*RQ@QmZGDuzRNd`txA-AJlgyoikDsYC9UhwJ^(prglaAEliO(cz+E?(+ z)Oyv1QjwF-IE8|3Gd;}-a_hog=HcenZ*}Fe%>OFu? z^QM$W%}4(9OYf6nqRK zv9B!IuQAI$uAzit!=3(w52J{xH(NB0m=~*yF#)L{SoyUf+^>9PNkuq`snSC#95yDd zvrh%D1YV_u>Sbg!PX&Zj;&-nU`AU;aRQAsLntx|Zi-BE!*XXbHk|7U~mzR%y0UP+m z1Z!<+ZfR*Y*)(%KbFTJx#jSn*quYSz9%VlzPB)oO;O@?3Pv_09^2k8Xg7XlEi2vN3 zsPlWM-j5@K;yHGvejTE5Z=pfEpGdD<>~Zdk#f0k2z#Uj1yNzL!=Ap3e-6@k~gP7C@ zlV{5QDtB=2ivdwU>$Mh}!FBbqsrkr{Qd^(pSG5Fn`!Y_yap>X?Pout?8I(4n|4Iun z^w#)IGI6llxfZh-YJO&QLz{;K_830OXU-1u&k}W$LHG)9flE1$ue{x0MkUtJR1*nc zg1mCW=u$TO&9KOP_O#2QN6~pXi&VO%fKYz>x-^aAKFaGm0eCpBOvk5bNEA#@nNB`! zfxunkdwjk|n~TVZY}W(-7lubkJf>c9O}-LY2-uDSdDQ~&gJ%L5&|7CU*!OaW+P1by%y`M&SZ Wxx7s*{{hdeV(@hJb6Mw<&;$V3;(J^G diff --git a/src/core/workflow-engine.ts b/src/core/workflow-engine.ts index cccb92a..f5171aa 100644 --- a/src/core/workflow-engine.ts +++ b/src/core/workflow-engine.ts @@ -9,6 +9,7 @@ import { type ProjectConfig, type WorkflowAction, type WorkflowStatic, + type WorkflowTemplate, } from './schemas.js'; import { Collection, type CollectionMetadata } from './types.js'; import { getCurrentISODate, formatDate, getCurrentDate } from '../shared/date-utils.js'; @@ -351,13 +352,76 @@ export class WorkflowEngine { if (filesToConvert.length === 0) { throw new Error(`No files found for requested artifacts: ${requestedArtifacts.join(', ')}`); } + } else { + // Default behavior: convert all workflow templates except notes/personal templates + const templateToFileMap = await this.getTemplateArtifactMap(workflow, collection); + + // Get all template names from workflow, excluding personal/note templates + const excludedTemplates = ['notes']; // Templates that shouldn't be converted by default + const mainDocumentTemplates = workflow.workflow.templates + .map((template) => template.name) + .filter((name) => !excludedTemplates.includes(name)); + + const defaultFiles = new Set(); + + for (const templateName of mainDocumentTemplates) { + const files = templateToFileMap.get(templateName); + if (files) { + files.forEach((file) => defaultFiles.add(file)); + } + } + + filesToConvert = markdownFiles.filter((file) => defaultFiles.has(file)); + + if (filesToConvert.length === 0) { + console.log(`ā„¹ļø No main document artifacts found to convert (${mainDocumentTemplates.join(', ')})`); + return; + } + + console.log(`šŸ“„ Converting main documents: ${filesToConvert.join(', ')}`); } // Convert the filtered files for (const file of filesToConvert) { const inputPath = path.join(collection.path, file); const baseName = path.basename(file, '.md'); - const outputPath = path.join(outputDir, `${baseName}.${formatType}`); + + // Generate output filename using template output pattern with variable substitution + let outputFileName = `${baseName}.${formatType}`; // fallback to simple naming + + // Try to generate smart output filename using template patterns + try { + // Find matching template by examining the artifact filename + let matchingTemplate: WorkflowTemplate | null = null; + + // Simple matching: find template whose name appears in the filename + for (const template of workflow.workflow.templates) { + if (file.includes(template.name)) { + matchingTemplate = template; + break; + } + } + + if (matchingTemplate && matchingTemplate.output) { + console.log(`šŸ”§ Using template '${matchingTemplate.name}' output pattern: ${matchingTemplate.output}`); + + // Build template variables (same as template processing) + const templateVariables = this.buildTemplateVariables(collection); + + // Apply variable substitution to template output pattern + const processedFileName = Mustache.render(matchingTemplate.output, templateVariables); + + // Replace .md extension with target format + outputFileName = processedFileName.replace(/\.md$/, `.${formatType}`); + console.log(`šŸŽÆ Generated output filename: ${outputFileName}`); + } else { + console.log(`āš ļø No template found for ${file}, using fallback naming`); + } + } catch (error) { + console.warn(`Warning: Could not determine template for ${file}, using fallback naming:`, error); + } + + const outputPath = path.join(outputDir, outputFileName); try { const formatTypeStr = String(formatType); @@ -563,19 +627,28 @@ export class WorkflowEngine { await this.ensureProjectConfigLoaded(); const templateMap = new Map(); + console.log(`šŸ” Template-to-artifact mapping debug:`); + console.log(`šŸ“‹ Available templates: ${workflow.workflow.templates.map(t => `${t.name} (output: ${t.output})`).join(', ')}`); + console.log(`šŸ“ Collection artifacts: ${collection.artifacts.join(', ')}`); + // For each template in the workflow, resolve its output filename for (const template of workflow.workflow.templates) { + console.log(`\nšŸ” Processing template: ${template.name}`); + console.log(` Template output pattern: ${template.output}`); + try { // Find all collection artifacts that match this template pattern const matchingFiles = collection.artifacts.filter((artifact) => { - // Simple approach: check if the artifact filename starts with the template name - // This handles cases like "resume" -> "resume_nicholas_hart.md" + console.log(` šŸ” Checking artifact: ${artifact}`); + // Pattern 1: Template name prefix (e.g., "resume_*.md") if (artifact.startsWith(`${template.name}_`) && artifact.endsWith('.md')) { + console.log(` āœ… MATCH: Prefix pattern (${template.name}_*)`); return true; } - // For dynamic templates (like notes with prefixes), we need pattern matching + // Pattern 2: Prefix templates (e.g., "{{prefix}}_notes.md") if (template.output.includes('{{prefix}}')) { + console.log(` šŸ” Trying prefix pattern matching...`); // Match any file that could have been generated from this template // Example: "{{prefix}}_notes.md" should match "recruiter_notes.md" const basePattern = template.output.replace('{{prefix}}', '(.+)'); @@ -587,14 +660,21 @@ export class WorkflowEngine { .replace('\\(\\.\\+\\)', '(.+)') + '$', ); - return regex.test(artifact); - } catch { + if (regex.test(artifact)) { + console.log(` āœ… MATCH: Prefix template pattern`); + return true; + } else { + console.log(` āŒ No match: Prefix template pattern`); + } + } catch (error) { + console.log(` āŒ Error in prefix pattern: ${error}`); return false; } } - // Fallback: try to match the exact template output pattern + // Pattern 3: Template output pattern with variable substitution if (template.output && !template.output.includes('{{prefix}}')) { + console.log(` šŸ” Trying output pattern matching...`); // For templates with user variables, try to match flexibly let pattern = template.output; @@ -608,26 +688,89 @@ export class WorkflowEngine { pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace('\\(\\.\\+\\)', '(.+)') + '$', ); - return regex.test(artifact); - } catch { + if (regex.test(artifact)) { + console.log(` āœ… MATCH: Output pattern (${template.output})`); + return true; + } else { + console.log(` āŒ No match: Output pattern (${template.output})`); + } + } catch (error) { + console.log(` āŒ Error in output pattern: ${error}`); return false; } } + // Pattern 4: Exact template name match (fallback for legacy compatibility) + if (artifact === `${template.name}.md`) { + console.log(` āœ… MATCH: Exact template name (${template.name}.md)`); + return true; + } + + console.log(` āŒ NO MATCHES: All patterns failed`); return false; }); if (matchingFiles.length > 0) { + console.log(` āœ… Template '${template.name}' → [${matchingFiles.join(', ')}]`); templateMap.set(template.name, matchingFiles); + } else { + console.log(` āŒ Template '${template.name}' → No matching artifacts`); } } catch (error) { console.warn(`Warning: Could not resolve output for template ${template.name}:`, error); } } + console.log(`\nšŸ“„ Final template-to-artifact mapping:`); + for (const [templateName, artifacts] of templateMap.entries()) { + console.log(` ${templateName} → [${artifacts.join(', ')}]`); + } + return templateMap; } + /** + * Build template variables for variable substitution + * Includes user config, collection metadata, and sanitized versions + */ + private buildTemplateVariables(collection: Collection) { + // Get user config + const userConfig = this.projectConfig?.user || this.getDefaultUserConfig(); + + // Extract title from collection metadata or collection ID + let title = ''; + if (collection.metadata.title && typeof collection.metadata.title === 'string') { + title = collection.metadata.title; + } else { + // Derive title from collection ID (e.g., "cloud_schedules_retrospective_20250801" -> "cloud_schedules_retrospective") + const collectionId = collection.metadata.collection_id; + const idParts = collectionId.split('_'); + const datePart = idParts[idParts.length - 1]; + if (/^\d{8}$/.test(datePart)) { + // Remove date part if it's 8 digits (YYYYMMDD format) + title = idParts.slice(0, -1).join(' '); + } else { + title = collectionId; + } + } + + return { + date: formatDate(getCurrentDate(this.projectConfig || undefined), 'LONG_DATE', this.projectConfig || undefined), + user: { + ...userConfig, + // Add sanitized versions for filenames + name_sanitized: sanitizeForFilename(userConfig.name), + preferred_name_sanitized: sanitizeForFilename(userConfig.preferred_name), + }, + // Collection-specific variables + title: title, + title_sanitized: sanitizeForFilename(title), + collection_id: collection.metadata.collection_id, + company: (typeof collection.metadata.company === 'string' ? collection.metadata.company : ''), + role: (typeof collection.metadata.role === 'string' ? collection.metadata.role : ''), + }; + } + /** * Get default user configuration */ diff --git a/src/shared/converters/base-converter.ts b/src/shared/converters/base-converter.ts index 2510526..d887601 100644 --- a/src/shared/converters/base-converter.ts +++ b/src/shared/converters/base-converter.ts @@ -160,6 +160,20 @@ export abstract class BaseConverter { }; } + // If no blocks were actually processed, don't create intermediate files + if (result.blocksProcessed === 0) { + return { + success: true, + // No processedFile - use original input file + artifacts: result.artifacts, + }; + } + + // Ensure intermediate directory exists before writing + if (!fs.existsSync(context.intermediateDir)) { + fs.mkdirSync(context.intermediateDir, { recursive: true }); + } + // Write processed content to temporary file const processedFileName = path.basename(context.inputFile, path.extname(context.inputFile)) + '_processed.md'; diff --git a/workflows/job/workflow.yml b/workflows/job/workflow.yml index 778a108..e81a32a 100644 --- a/workflows/job/workflow.yml +++ b/workflows/job/workflow.yml @@ -101,11 +101,6 @@ workflow: output: "cover_letter_{{user.name_sanitized}}.md" description: "Cover letter for this application" - - name: "notes" - file: "templates/notes/default.md" - output: "{{#prefix}}{{prefix}}_{{/prefix}}notes.md" - description: "Notes template for interviews, meetings, or general notes" - # Define static files (no variable substitution) statics: - name: "resume_reference" @@ -153,7 +148,7 @@ workflow: formats: ["docx", "html", "pdf"] processors: - name: "emoji" - enabled: true # Enable thoughtful emoji usage in job applications + enabled: true # Re-enabled for debugging parameters: - name: "format" type: "enum" diff --git a/workflows/presentation/workflow.yml b/workflows/presentation/workflow.yml index addcd50..794efb9 100644 --- a/workflows/presentation/workflow.yml +++ b/workflows/presentation/workflow.yml @@ -20,25 +20,25 @@ workflow: required: false description: "Template variant (default, technical, layout-optimized, compact, beginner)" help_text: "Choose a template that matches your presentation style and layout needs" - + description: "Create technical presentations with Mermaid diagrams" usage: "{alias} \"Presentation Title\" [template]" help_text: | Create professional technical presentations with auto-generated diagrams. - + Features: - Mermaid diagram generation (flowcharts, sequences, architectures) - Layout-optimized templates (horizontal flows, compact layouts) - Multiple output formats (PPTX, HTML, PDF) - Professional styling with size constraints - Version control friendly markdown source - + The presentation system processes Mermaid blocks with layout hints: ```mermaid:diagram-name {layout=horizontal, width=1000px} flowchart LR A --> B --> C ``` - + examples: - "pres \"System Architecture Overview\"" - "pres \"API Documentation\" layout-optimized" @@ -66,24 +66,19 @@ workflow: templates: - name: "content" file: "templates/content/default.md" - output: "content.md" + output: "{{user.name_sanitized}}_{{title_sanitized}}.md" description: "Main presentation content" - - - name: "slides" - file: "templates/slides/default.md" - output: "slides.md" - description: "Slide-specific formatting template" # Static resources statics: - name: "pptx_template" file: "templates/static/reference.pptx" description: "PowerPoint reference template for styling" - + - name: "html_styles" file: "templates/static/styles.css" description: "CSS styles for HTML output" - + - name: "plantuml_config" file: "templates/static/plantuml-config.txt" description: "PlantUML configuration settings" @@ -114,13 +109,13 @@ workflow: options: ["corporate", "technical", "minimal"] default: "technical" description: "Presentation theme" - + - name: "diagram_format" type: "enum" options: ["png", "svg"] default: "png" description: "Diagram output format" - + - name: "slide_layout" type: "enum" options: ["standard", "widescreen"] From ea30ebdef1d92af60c795b2a2f6b43c5b927141d Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 11:45:38 -0700 Subject: [PATCH 3/7] fixed tests --- scripts/test-e2e.sh | 52 ++++++++++++------- src/shared/processors/emoji-processor.ts | 3 ++ .../converters/presentation-converter.test.ts | 16 +++++- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/scripts/test-e2e.sh b/scripts/test-e2e.sh index c73d20a..821a926 100755 --- a/scripts/test-e2e.sh +++ b/scripts/test-e2e.sh @@ -24,12 +24,12 @@ log_info() { log_success() { echo -e "${GREEN}[PASS]${NC} $1" - ((TESTS_PASSED++)) + TESTS_PASSED=$((TESTS_PASSED + 1)) } log_error() { echo -e "${RED}[FAIL]${NC} $1" - ((TESTS_FAILED++)) + TESTS_FAILED=$((TESTS_FAILED + 1)) } log_warning() { @@ -42,7 +42,7 @@ run_test() { local expected_exit_code="${3:-0}" local expected_output="$4" - ((TESTS_RUN++)) + TESTS_RUN=$((TESTS_RUN + 1)) log_info "Running test: $test_name" # Capture both stdout and stderr, and exit code @@ -89,12 +89,25 @@ setup_test_env() { mkdir -p "$PROJECT_TEST_DIR" mkdir -p "$NON_PROJECT_DIR" - # Build the project - log_info "Building project..." - npm run build > /dev/null 2>&1 + # Build the CLI + log_info "Building CLI..." + if ! pnpm cli:build > /dev/null 2>&1; then + log_error "Failed to build CLI" + exit 1 + fi + + # Create minimal system directory structure (avoid copying huge node_modules, .git, etc.) + log_info "Creating minimal system directory structure..." + mkdir -p "$SYSTEM_TEST_DIR/markdown-workflow" + + # Copy only essential files and directories needed for E2E tests + cp package.json "$SYSTEM_TEST_DIR/markdown-workflow/" + cp -r dist "$SYSTEM_TEST_DIR/markdown-workflow/" 2>/dev/null || true + cp -r workflows "$SYSTEM_TEST_DIR/markdown-workflow/" 2>/dev/null || true + cp -r test-configs "$SYSTEM_TEST_DIR/markdown-workflow/" 2>/dev/null || true + cp -r scripts "$SYSTEM_TEST_DIR/markdown-workflow/" 2>/dev/null || true - # Create symlink to simulate being in system directory - cp -r . "$SYSTEM_TEST_DIR/markdown-workflow" + log_info "System directory structure created (avoided copying node_modules, .git, etc.)" log_info "Test environment ready:" log_info " System dir: $SYSTEM_TEST_DIR/markdown-workflow" @@ -113,20 +126,20 @@ test_cli_commands() { log_info "=== Testing CLI Command Availability ===" # Test that CLI is built and available - run_test "CLI help command" "node dist/cli/index.js --help" 0 "Usage:" + run_test "CLI help command" "node '$PWD/dist/cli/index.js' --help" 0 "Usage:" } # Test CLI commands work correctly test_cli_functionality() { log_info "=== Testing Basic CLI Functionality ===" - # Test that CLI commands work from any directory (including system directory) - run_test "Init can run from system directory" \ - "cd '$SYSTEM_TEST_DIR/markdown-workflow' && node dist/cli/index.js init" \ + # Test that CLI commands work from any directory (using absolute path to CLI) + run_test "Init can run from different directory" \ + "cd '$SYSTEM_TEST_DIR' && node '$PWD/dist/cli/index.js' init" \ 0 "Project initialized successfully" # Clean up the init we just created - rm -rf "$SYSTEM_TEST_DIR/markdown-workflow/.markdown-workflow" + rm -rf "$SYSTEM_TEST_DIR/.markdown-workflow" } # Test init command functionality @@ -151,10 +164,6 @@ test_init_command() { "test -d '$PROJECT_TEST_DIR/.markdown-workflow/workflows'" \ 0 - run_test "Collections directory created" \ - "test -d '$PROJECT_TEST_DIR/.markdown-workflow/collections'" \ - 0 - # Test init in existing project without force should fail run_test "Init in existing project should fail" \ "cd '$PROJECT_TEST_DIR' && node '$PWD/dist/cli/index.js' init" \ @@ -173,11 +182,11 @@ test_project_context_commands() { # Test commands that should fail outside project run_test "List outside project should fail" \ "cd '$NON_PROJECT_DIR' && node '$PWD/dist/cli/index.js' list job" \ - 1 "Project root not found" + 1 "Not in a markdown-workflow project" run_test "Create outside project should fail" \ "cd '$NON_PROJECT_DIR' && node '$PWD/dist/cli/index.js' create job 'Test Company' 'Test Role'" \ - 1 "Project root not found" + 1 "Not in a markdown-workflow project" # Test commands that should work inside project run_test "List inside project should work" \ @@ -192,7 +201,7 @@ test_workflow_operations() { # Test creating a collection run_test "Create job collection" \ "cd '$PROJECT_TEST_DIR' && node '$PWD/dist/cli/index.js' create job 'Test Company' 'Software Engineer'" \ - 0 "Created collection" + 0 "Collection created successfully" # Test listing collections run_test "List job collections" \ @@ -246,6 +255,9 @@ main() { echo "Tests Failed: $TESTS_FAILED" echo + # Explicit cleanup + cleanup_test_env + if [ "$TESTS_FAILED" -eq 0 ]; then log_success "All tests passed! šŸŽ‰" exit 0 diff --git a/src/shared/processors/emoji-processor.ts b/src/shared/processors/emoji-processor.ts index a556856..bdcd452 100644 --- a/src/shared/processors/emoji-processor.ts +++ b/src/shared/processors/emoji-processor.ts @@ -167,6 +167,9 @@ const EMOJI_MAP: Record = { ':electric_plug:': 'šŸ”Œ', ':question:': 'ā“', ':exclamation:': 'ā—', + // === ADDITIONAL ALIASES FOR TESTING === + ':bulb:': 'šŸ’”', // alias for :lightbulb: + ':mag:': 'šŸ”', // alias for :search: }; export class EmojiProcessor extends BaseProcessor { diff --git a/tests/unit/shared/converters/presentation-converter.test.ts b/tests/unit/shared/converters/presentation-converter.test.ts index 63367db..a89ce60 100644 --- a/tests/unit/shared/converters/presentation-converter.test.ts +++ b/tests/unit/shared/converters/presentation-converter.test.ts @@ -40,7 +40,7 @@ describe('PresentationConverter', () => { success: true, processedContent: 'processed content', artifacts: [], - blocksProcessed: 0, + blocksProcessed: 1, // Process at least one block to trigger file creation }); }); @@ -122,6 +122,7 @@ describe('PresentationConverter', () => { inputFile: '/test/input.md', outputFile: '/test/output.pptx', format: 'pptx' as const, + enabledProcessors: ['mermaid'], // Enable processors to trigger file processing collectionPath: '/test/collection', assetsDir: '/test/assets', intermediateDir: '/test/intermediate', @@ -140,6 +141,15 @@ describe('PresentationConverter', () => { return false; }); + // Mock the processor registry to return processed content with processed file path + const processedFilePath = '/test/intermediate/input_processed.md'; + jest.spyOn(mockProcessorRegistry, 'processContent').mockResolvedValue({ + success: true, + processedContent: 'processed content', + artifacts: [], + blocksProcessed: 1, + }); + await converter.convert(context); // Should call pandoc with reference document and processed file @@ -163,6 +173,7 @@ describe('PresentationConverter', () => { inputFile: '/test/input.md', outputFile: '/test/output.pptx', format: 'pptx' as const, + enabledProcessors: ['mermaid'], // Enable processors to trigger file processing collectionPath: '/test', assetsDir: '/test/assets', intermediateDir: '/test/intermediate', @@ -196,6 +207,7 @@ describe('PresentationConverter', () => { inputFile: '/test/input.md', outputFile: '/test/output.html', format: 'html' as const, + enabledProcessors: ['mermaid'], // Enable processors to trigger file processing collectionPath: '/test', assetsDir: '/test/assets', intermediateDir: '/test/intermediate', @@ -273,6 +285,7 @@ flowchart TD inputFile: '/test/input.md', outputFile: '/test/output.pdf', format: 'pdf' as const, + enabledProcessors: ['mermaid'], // Enable processors to trigger file processing collectionPath: '/test', assetsDir: '/test/assets', intermediateDir: '/test/intermediate', @@ -309,6 +322,7 @@ flowchart TD inputFile: '/test/input.md', outputFile: '/test/output.html', format: 'html' as const, + enabledProcessors: ['mermaid'], // Enable processors to trigger file processing collectionPath: '/test', assetsDir: '/test/assets', intermediateDir: '/test/intermediate', From 981eda82d63e996204fdc0adf68ea68121779e05 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 11:47:16 -0700 Subject: [PATCH 4/7] cleaned up lint and format --- package.json | 2 +- src/core/workflow-engine.ts | 63 +++++++++++-------- .../converters/presentation-converter.test.ts | 1 - 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index a919b9f..093dd1d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "type": "module", - "packageManager": "pnpm@10.12.1", + "packageManager": "pnpm@10.14.0", "engines": { "node": ">=20", "pnpm": ">=10" diff --git a/src/core/workflow-engine.ts b/src/core/workflow-engine.ts index f5171aa..d269bca 100644 --- a/src/core/workflow-engine.ts +++ b/src/core/workflow-engine.ts @@ -355,29 +355,31 @@ export class WorkflowEngine { } else { // Default behavior: convert all workflow templates except notes/personal templates const templateToFileMap = await this.getTemplateArtifactMap(workflow, collection); - + // Get all template names from workflow, excluding personal/note templates const excludedTemplates = ['notes']; // Templates that shouldn't be converted by default const mainDocumentTemplates = workflow.workflow.templates .map((template) => template.name) .filter((name) => !excludedTemplates.includes(name)); - + const defaultFiles = new Set(); - + for (const templateName of mainDocumentTemplates) { const files = templateToFileMap.get(templateName); if (files) { files.forEach((file) => defaultFiles.add(file)); } } - + filesToConvert = markdownFiles.filter((file) => defaultFiles.has(file)); - + if (filesToConvert.length === 0) { - console.log(`ā„¹ļø No main document artifacts found to convert (${mainDocumentTemplates.join(', ')})`); + console.log( + `ā„¹ļø No main document artifacts found to convert (${mainDocumentTemplates.join(', ')})`, + ); return; } - + console.log(`šŸ“„ Converting main documents: ${filesToConvert.join(', ')}`); } @@ -385,15 +387,15 @@ export class WorkflowEngine { for (const file of filesToConvert) { const inputPath = path.join(collection.path, file); const baseName = path.basename(file, '.md'); - + // Generate output filename using template output pattern with variable substitution let outputFileName = `${baseName}.${formatType}`; // fallback to simple naming - + // Try to generate smart output filename using template patterns try { // Find matching template by examining the artifact filename let matchingTemplate: WorkflowTemplate | null = null; - + // Simple matching: find template whose name appears in the filename for (const template of workflow.workflow.templates) { if (file.includes(template.name)) { @@ -401,16 +403,18 @@ export class WorkflowEngine { break; } } - + if (matchingTemplate && matchingTemplate.output) { - console.log(`šŸ”§ Using template '${matchingTemplate.name}' output pattern: ${matchingTemplate.output}`); - + console.log( + `šŸ”§ Using template '${matchingTemplate.name}' output pattern: ${matchingTemplate.output}`, + ); + // Build template variables (same as template processing) const templateVariables = this.buildTemplateVariables(collection); - + // Apply variable substitution to template output pattern const processedFileName = Mustache.render(matchingTemplate.output, templateVariables); - + // Replace .md extension with target format outputFileName = processedFileName.replace(/\.md$/, `.${formatType}`); console.log(`šŸŽÆ Generated output filename: ${outputFileName}`); @@ -418,9 +422,12 @@ export class WorkflowEngine { console.log(`āš ļø No template found for ${file}, using fallback naming`); } } catch (error) { - console.warn(`Warning: Could not determine template for ${file}, using fallback naming:`, error); + console.warn( + `Warning: Could not determine template for ${file}, using fallback naming:`, + error, + ); } - + const outputPath = path.join(outputDir, outputFileName); try { @@ -628,14 +635,16 @@ export class WorkflowEngine { const templateMap = new Map(); console.log(`šŸ” Template-to-artifact mapping debug:`); - console.log(`šŸ“‹ Available templates: ${workflow.workflow.templates.map(t => `${t.name} (output: ${t.output})`).join(', ')}`); + console.log( + `šŸ“‹ Available templates: ${workflow.workflow.templates.map((t) => `${t.name} (output: ${t.output})`).join(', ')}`, + ); console.log(`šŸ“ Collection artifacts: ${collection.artifacts.join(', ')}`); // For each template in the workflow, resolve its output filename for (const template of workflow.workflow.templates) { console.log(`\nšŸ” Processing template: ${template.name}`); console.log(` Template output pattern: ${template.output}`); - + try { // Find all collection artifacts that match this template pattern const matchingFiles = collection.artifacts.filter((artifact) => { @@ -725,7 +734,7 @@ export class WorkflowEngine { for (const [templateName, artifacts] of templateMap.entries()) { console.log(` ${templateName} → [${artifacts.join(', ')}]`); } - + return templateMap; } @@ -736,7 +745,7 @@ export class WorkflowEngine { private buildTemplateVariables(collection: Collection) { // Get user config const userConfig = this.projectConfig?.user || this.getDefaultUserConfig(); - + // Extract title from collection metadata or collection ID let title = ''; if (collection.metadata.title && typeof collection.metadata.title === 'string') { @@ -753,9 +762,13 @@ export class WorkflowEngine { title = collectionId; } } - + return { - date: formatDate(getCurrentDate(this.projectConfig || undefined), 'LONG_DATE', this.projectConfig || undefined), + date: formatDate( + getCurrentDate(this.projectConfig || undefined), + 'LONG_DATE', + this.projectConfig || undefined, + ), user: { ...userConfig, // Add sanitized versions for filenames @@ -766,8 +779,8 @@ export class WorkflowEngine { title: title, title_sanitized: sanitizeForFilename(title), collection_id: collection.metadata.collection_id, - company: (typeof collection.metadata.company === 'string' ? collection.metadata.company : ''), - role: (typeof collection.metadata.role === 'string' ? collection.metadata.role : ''), + company: typeof collection.metadata.company === 'string' ? collection.metadata.company : '', + role: typeof collection.metadata.role === 'string' ? collection.metadata.role : '', }; } diff --git a/tests/unit/shared/converters/presentation-converter.test.ts b/tests/unit/shared/converters/presentation-converter.test.ts index a89ce60..60ea5b0 100644 --- a/tests/unit/shared/converters/presentation-converter.test.ts +++ b/tests/unit/shared/converters/presentation-converter.test.ts @@ -142,7 +142,6 @@ describe('PresentationConverter', () => { }); // Mock the processor registry to return processed content with processed file path - const processedFilePath = '/test/intermediate/input_processed.md'; jest.spyOn(mockProcessorRegistry, 'processContent').mockResolvedValue({ success: true, processedContent: 'processed content', From b15b4619b15cba46c5d74637ef297cef151a16e6 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 12:03:30 -0700 Subject: [PATCH 5/7] added graphviz processor --- src/core/schemas.ts | 11 + src/shared/processors/graphviz-processor.ts | 412 ++++++++++++++++ src/shared/processors/index.ts | 17 +- .../processors/graphviz-processor.test.ts | 464 ++++++++++++++++++ 4 files changed, 903 insertions(+), 1 deletion(-) create mode 100644 src/shared/processors/graphviz-processor.ts create mode 100644 tests/unit/shared/processors/graphviz-processor.test.ts diff --git a/src/core/schemas.ts b/src/core/schemas.ts index b8114c6..ccb719f 100644 --- a/src/core/schemas.ts +++ b/src/core/schemas.ts @@ -139,6 +139,17 @@ export const SystemConfigSchema = z.object({ fontFamily: z.string().optional(), }) .optional(), + graphviz: z + .object({ + output_format: z.enum(['png', 'svg', 'pdf', 'jpeg']), + layout_engine: z.enum(['dot', 'neato', 'fdp', 'sfdp', 'twopi', 'circo']), + timeout: z.number(), + dpi: z.number().optional(), + theme: z.enum(['default', 'dark', 'light']).optional(), + backgroundColor: z.string().optional(), + fontFamily: z.string().optional(), + }) + .optional(), testing: z .object({ // Date/Time overrides diff --git a/src/shared/processors/graphviz-processor.ts b/src/shared/processors/graphviz-processor.ts new file mode 100644 index 0000000..7b579c9 --- /dev/null +++ b/src/shared/processors/graphviz-processor.ts @@ -0,0 +1,412 @@ +/** + * Graphviz processor + * Processes Graphviz DOT blocks and generates diagram images + */ + +import { execSync } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import { + BaseProcessor, + ProcessorBlock, + ProcessingContext, + ProcessingResult, +} from './base-processor.js'; + +export interface GraphvizConfig { + output_format: 'png' | 'svg' | 'pdf' | 'jpeg'; + layout_engine: 'dot' | 'neato' | 'fdp' | 'sfdp' | 'twopi' | 'circo'; + timeout: number; + dpi?: number; // For high-resolution output + theme?: 'default' | 'dark' | 'light'; + backgroundColor?: string; + fontFamily?: string; + [key: string]: unknown; // Make it compatible with ProcessorConfig +} + +export interface GraphvizGenerationResult { + success: boolean; + outputPath?: string; + error?: string; +} + +/** + * Graphviz diagram processor + * Processes Graphviz DOT blocks and generates diagram images + */ +export class GraphvizProcessor extends BaseProcessor { + readonly name = 'graphviz'; + readonly description = 'Process Graphviz DOT diagrams and generate images'; + readonly version = '1.0.0'; + readonly intermediateExtension = '.dot'; + readonly supportedInputExtensions = ['.md', '.markdown']; + readonly outputExtensions = ['.png', '.svg', '.pdf', '.jpeg']; + readonly supportedOutputFormats = ['png', 'svg', 'pdf', 'jpeg']; + + private graphvizConfig: GraphvizConfig; + + constructor(config: GraphvizConfig) { + super(config); + this.graphvizConfig = config; + } + + /** + * Create processor from system configuration + */ + static fromSystemConfig(systemConfig: { graphviz?: Partial }): GraphvizProcessor { + // Provide default configuration if graphviz config is missing + const defaultConfig: GraphvizConfig = { + output_format: 'png', + layout_engine: 'dot', + timeout: 30, + dpi: 96, + theme: 'default', + backgroundColor: 'white', + fontFamily: 'arial,sans-serif', + }; + + const graphvizConfig = { ...defaultConfig, ...systemConfig.graphviz }; + return new GraphvizProcessor(graphvizConfig); + } + + /** + * Check if Graphviz CLI is available + */ + static async detectGraphvizCLI(): Promise { + try { + // Try to run the Graphviz CLI version command + execSync('dot -V', { + stdio: 'pipe', + timeout: 10000, + encoding: 'utf8', + }); + return true; + } catch (error) { + try { + // Alternative: check if graphviz is in PATH + execSync('which dot', { + stdio: 'pipe', + timeout: 5000, + encoding: 'utf8', + }); + return true; + } catch { + console.warn( + `āš ļø Graphviz CLI detection failed: ${error instanceof Error ? error.message : String(error)}`, + ); + return false; + } + } + } + + /** + * Check if content contains Graphviz blocks + */ + canProcess(content: string): boolean { + const regex = /```graphviz:[\w-]+.*?\n[\s\S]*?\n```/g; + return regex.test(content); + } + + /** + * Detect and extract Graphviz blocks from markdown content + * Supports syntax: ```graphviz:name {params...} + */ + detectBlocks(markdown: string): ProcessorBlock[] { + const blocks: ProcessorBlock[] = []; + + // Match graphviz:name {params} code blocks + const regex = /```graphviz:([\w-]+)(?:\s*\{([^}]*)\})?\s*\n([\s\S]*?)\n```/g; + let match; + + while ((match = regex.exec(markdown)) !== null) { + const [, name, params, content] = match; + blocks.push({ + name, + content, + startIndex: match.index, + endIndex: match.index + match[0].length, + metadata: { + params: params ? this.parseParams(params) : {}, + }, + }); + } + + return blocks; + } + + /** + * Parse parameters from the graphviz block header + * Format: {layout=neato, theme=dark, dpi=300} + */ + private parseParams(paramsString: string): Record { + const params: Record = {}; + + // Remove spaces and split by comma + const pairs = paramsString.replace(/\s/g, '').split(','); + + for (const pair of pairs) { + const [key, value] = pair.split('='); + if (key && value) { + params[key.trim()] = value.trim(); + } + } + + return params; + } + + /** + * Process content to generate Graphviz diagrams + */ + async process(content: string, context: ProcessingContext): Promise { + const blocks = this.detectBlocks(content); + + if (blocks.length === 0) { + return { + success: true, + processedContent: content, + artifacts: [], + blocksProcessed: 0, + }; + } + + // Check if Graphviz CLI is available + if (!(await GraphvizProcessor.detectGraphvizCLI())) { + console.warn('āš ļø Graphviz CLI not found. Diagrams will not be rendered.'); + console.warn(' Install Graphviz: https://graphviz.org/download/'); + + // Return content with warning comments + let processedContent = content; + for (const block of blocks) { + const warning = `\n`; + processedContent = processedContent.replace( + content.substring(block.startIndex, block.endIndex), + content.substring(block.startIndex, block.endIndex) + warning, + ); + } + + return { + success: true, + processedContent, + artifacts: [], + blocksProcessed: blocks.length, + }; + } + + this.ensureDirectories(context); + + let processedContent = content; + const artifacts: Array<{ + name: string; + path: string; + relativePath: string; + type: 'asset' | 'intermediate' | 'output'; + }> = []; + + // Process each block + for (const block of blocks) { + try { + const result = await this.generateDiagram(block, context); + + if (result.success && result.outputPath) { + // Add image reference to markdown + const imageRef = `\n![${block.name}](${this.getRelativePath(result.outputPath, context)})`; + processedContent = processedContent.replace( + content.substring(block.startIndex, block.endIndex), + content.substring(block.startIndex, block.endIndex) + imageRef, + ); + + // Add to artifacts + artifacts.push({ + name: path.basename(result.outputPath), + path: result.outputPath, + relativePath: this.getRelativePath(result.outputPath, context), + type: 'asset', + }); + + console.info(`šŸŽØ Generated Graphviz diagram: ${path.basename(result.outputPath)}`); + } else { + console.warn(`āš ļø Failed to generate diagram for ${block.name}: ${result.error}`); + } + } catch (error) { + console.error(`āŒ Error processing Graphviz block ${block.name}:`, error); + } + } + + // Write intermediate file + const intermediateFile = this.getIntermediateFilePath('processed', context); + const contentChanged = this.hasContentChanged(intermediateFile, processedContent); + + if (contentChanged) { + fs.writeFileSync(intermediateFile, processedContent, 'utf8'); + console.info(`šŸ“ Updated Graphviz intermediate file: ${path.basename(intermediateFile)}`); + } + + artifacts.push({ + name: path.basename(intermediateFile), + path: intermediateFile, + relativePath: this.getRelativePath(intermediateFile, context), + type: 'intermediate', + }); + + return { + success: true, + processedContent, + artifacts, + blocksProcessed: blocks.length, + }; + } + + /** + * Generate diagram image from DOT code + */ + private async generateDiagram( + block: ProcessorBlock, + context: ProcessingContext, + ): Promise { + try { + // Merge block-specific params with processor config + const config = { ...this.graphvizConfig }; + if (block.metadata?.params) { + const params = block.metadata.params as Record; + if ( + params.layout && + ['dot', 'neato', 'fdp', 'sfdp', 'twopi', 'circo'].includes(params.layout) + ) { + config.layout_engine = params.layout as GraphvizConfig['layout_engine']; + } + if (params.theme && ['default', 'dark', 'light'].includes(params.theme)) { + config.theme = params.theme as GraphvizConfig['theme']; + } + if (params.dpi) { + config.dpi = parseInt(params.dpi, 10); + } + } + + // Apply theme-specific styling + const styledContent = this.applyTheme(block.content, config); + + // Write DOT file + const dotFile = path.join(context.intermediateDir, `${block.name}.dot`); + fs.writeFileSync(dotFile, styledContent, 'utf8'); + + // Generate output file + const outputFile = path.join(context.assetsDir, `${block.name}.${config.output_format}`); + + // Build Graphviz command + const args = [`-T${config.output_format}`, `-K${config.layout_engine}`, `-o${outputFile}`]; + + // Add DPI for raster formats + if (['png', 'jpeg'].includes(config.output_format) && config.dpi) { + args.push(`-Gdpi=${config.dpi}`); + } + + // Add input file + args.push(dotFile); + + // Execute Graphviz + execSync(`dot ${args.join(' ')}`, { + cwd: context.intermediateDir, + stdio: 'pipe', + timeout: config.timeout * 1000, + }); + + if (fs.existsSync(outputFile)) { + return { + success: true, + outputPath: outputFile, + }; + } else { + return { + success: false, + error: 'Output file not created', + }; + } + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error', + }; + } + } + + /** + * Apply theme and styling to DOT content + */ + private applyTheme(dotContent: string, config: GraphvizConfig): string { + let styledContent = dotContent; + + // Add global styling based on theme + const globalStyles: string[] = []; + + if (config.backgroundColor) { + globalStyles.push(`bgcolor="${config.backgroundColor}"`); + } + + if (config.fontFamily) { + globalStyles.push(`fontname="${config.fontFamily}"`); + } + + // Apply theme-specific styling + switch (config.theme) { + case 'dark': + globalStyles.push('bgcolor="#2d3748"', 'color="#e2e8f0"', 'fontcolor="#e2e8f0"'); + break; + case 'light': + globalStyles.push('bgcolor="#f7fafc"', 'color="#2d3748"', 'fontcolor="#2d3748"'); + break; + default: + // Use default colors + break; + } + + // Insert global styles at the beginning of the graph + if (globalStyles.length > 0) { + const graphMatch = styledContent.match(/^(digraph|graph)\s+(\w+)\s*\{/); + if (graphMatch) { + const insertPos = styledContent.indexOf('{') + 1; + const globalStyleString = globalStyles.map((style) => ` ${style};`).join('\n'); + styledContent = + styledContent.slice(0, insertPos) + + '\n' + + globalStyleString + + '\n' + + styledContent.slice(insertPos); + } + } + + return styledContent; + } + + /** + * Validate DOT syntax + */ + private validateDOT(dotCode: string): { valid: boolean; error?: string } { + try { + // Use Graphviz CLI to validate syntax + execSync(`echo '${dotCode}' | dot -Tsvg -o /dev/null`, { + stdio: 'pipe', + timeout: 10000, + }); + return { valid: true }; + } catch (error) { + return { + valid: false, + error: `Invalid DOT syntax: ${error instanceof Error ? error.message : String(error)}`, + }; + } + } + + /** + * Get supported layout engines + */ + getSupportedLayoutEngines(): string[] { + return ['dot', 'neato', 'fdp', 'sfdp', 'twopi', 'circo']; + } + + /** + * Get supported output formats + */ + getSupportedOutputFormats(): string[] { + return this.supportedOutputFormats; + } +} diff --git a/src/shared/processors/index.ts b/src/shared/processors/index.ts index 1c7e8cc..632de08 100644 --- a/src/shared/processors/index.ts +++ b/src/shared/processors/index.ts @@ -15,11 +15,13 @@ export type { export { MermaidProcessor } from '../mermaid-processor.js'; export { EmojiProcessor } from './emoji-processor.js'; export { PlantUMLProcessor } from './plantuml-processor.js'; +export { GraphvizProcessor } from './graphviz-processor.js'; import { defaultProcessorRegistry } from './base-processor.js'; import { MermaidProcessor } from '../mermaid-processor.js'; import { EmojiProcessor } from './emoji-processor.js'; import { PlantUMLProcessor } from './plantuml-processor.js'; +import { GraphvizProcessor } from './graphviz-processor.js'; // Convenience function to register default processors export function registerDefaultProcessors() { @@ -38,21 +40,34 @@ export function registerDefaultProcessors() { timeout: 30, }; + const graphvizConfig = { + output_format: 'png' as const, + layout_engine: 'dot' as const, + timeout: 30, + dpi: 96, + theme: 'default' as const, + backgroundColor: 'white', + fontFamily: 'arial,sans-serif', + }; + const mermaidProcessor = new MermaidProcessor(mermaidConfig); const emojiProcessor = new EmojiProcessor({}); const plantUMLProcessor = PlantUMLProcessor.create(plantUMLConfig); + const graphvizProcessor = new GraphvizProcessor(graphvizConfig); // Register processors in order (emoji first, then diagrams) defaultProcessorRegistry.register(emojiProcessor); defaultProcessorRegistry.register(mermaidProcessor); defaultProcessorRegistry.register(plantUMLProcessor); + defaultProcessorRegistry.register(graphvizProcessor); // Set processing order - defaultProcessorRegistry.setProcessorOrder(['emoji', 'mermaid', 'plantuml']); + defaultProcessorRegistry.setProcessorOrder(['emoji', 'mermaid', 'plantuml', 'graphviz']); return { emoji: emojiProcessor, mermaid: mermaidProcessor, plantuml: plantUMLProcessor, + graphviz: graphvizProcessor, }; } diff --git a/tests/unit/shared/processors/graphviz-processor.test.ts b/tests/unit/shared/processors/graphviz-processor.test.ts new file mode 100644 index 0000000..8dbb38c --- /dev/null +++ b/tests/unit/shared/processors/graphviz-processor.test.ts @@ -0,0 +1,464 @@ +import { jest } from '@jest/globals'; +import { + GraphvizProcessor, + GraphvizConfig, +} from '../../../../src/shared/processors/graphviz-processor.js'; +import type { ProcessingContext } from '../../../../src/shared/processors/base-processor.js'; + +// Mock external dependencies +jest.mock('child_process'); +jest.mock('fs'); + +import { execSync } from 'child_process'; +import * as fs from 'fs'; + +const mockExecSync = jest.mocked(execSync); +const mockFs = jest.mocked(fs); + +describe('GraphvizProcessor', () => { + let processor: GraphvizProcessor; + let context: ProcessingContext; + + const defaultConfig: GraphvizConfig = { + output_format: 'png', + layout_engine: 'dot', + timeout: 30, + dpi: 96, + theme: 'default', + backgroundColor: 'white', + fontFamily: 'arial,sans-serif', + }; + + beforeEach(() => { + processor = new GraphvizProcessor(defaultConfig); + context = { + collectionPath: '/test/collection', + assetsDir: '/test/assets', + intermediateDir: '/test/intermediate', + outputFormat: 'md', + }; + + // Reset mocks + jest.clearAllMocks(); + mockFs.existsSync.mockReturnValue(true); + mockFs.mkdirSync.mockImplementation(() => undefined); + mockFs.writeFileSync.mockImplementation(() => undefined); + mockFs.readFileSync.mockReturnValue('test content'); + }); + + describe('constructor', () => { + it('should create processor with correct properties', () => { + expect(processor.name).toBe('graphviz'); + expect(processor.description).toBe('Process Graphviz DOT diagrams and generate images'); + expect(processor.version).toBe('1.0.0'); + expect(processor.supportedInputExtensions).toEqual(['.md', '.markdown']); + expect(processor.supportedOutputFormats).toEqual(['png', 'svg', 'pdf', 'jpeg']); + }); + + it('should accept configuration', () => { + const customConfig: GraphvizConfig = { + output_format: 'svg', + layout_engine: 'neato', + timeout: 60, + dpi: 300, + theme: 'dark', + backgroundColor: 'black', + fontFamily: 'monospace', + }; + + const customProcessor = new GraphvizProcessor(customConfig); + expect(customProcessor).toBeInstanceOf(GraphvizProcessor); + }); + }); + + describe('fromSystemConfig', () => { + it('should create processor with system config', () => { + const systemConfig = { + graphviz: { + output_format: 'svg', + layout_engine: 'neato', + timeout: 45, + }, + }; + + const processor = GraphvizProcessor.fromSystemConfig(systemConfig); + expect(processor).toBeInstanceOf(GraphvizProcessor); + }); + + it('should use defaults when system config is missing', () => { + const processor = GraphvizProcessor.fromSystemConfig({}); + expect(processor).toBeInstanceOf(GraphvizProcessor); + }); + }); + + describe('detectGraphvizCLI', () => { + it('should detect Graphviz CLI when available', async () => { + mockExecSync.mockReturnValue('dot - graphviz version 2.44.1' as ReturnType); + + const result = await GraphvizProcessor.detectGraphvizCLI(); + expect(result).toBe(true); + expect(mockExecSync).toHaveBeenCalledWith('dot -V', expect.any(Object)); + }); + + it('should fallback to which command when dot -V fails', async () => { + mockExecSync + .mockImplementationOnce(() => { + throw new Error('Command not found'); + }) + .mockReturnValue('/usr/bin/dot' as ReturnType); + + const result = await GraphvizProcessor.detectGraphvizCLI(); + expect(result).toBe(true); + expect(mockExecSync).toHaveBeenCalledTimes(2); + }); + + it('should return false when Graphviz CLI is not available', async () => { + mockExecSync.mockImplementation(() => { + throw new Error('Command not found'); + }); + + const result = await GraphvizProcessor.detectGraphvizCLI(); + expect(result).toBe(false); + }); + }); + + describe('canProcess', () => { + it('should detect Graphviz blocks', () => { + const content = ` +# Test Document + +\`\`\`graphviz:simple-flow +digraph G { + A -> B; +} +\`\`\` + +More content here. +`; + + expect(processor.canProcess(content)).toBe(true); + }); + + it('should not detect non-Graphviz blocks', () => { + const content = ` +# Test Document + +\`\`\`mermaid:flow +graph TD + A --> B +\`\`\` + +More content here. +`; + + expect(processor.canProcess(content)).toBe(false); + }); + + it('should detect Graphviz blocks with parameters', () => { + const content = ` +\`\`\`graphviz:complex {layout=neato, theme=dark} +digraph G { + A -> B; +} +\`\`\` +`; + + expect(processor.canProcess(content)).toBe(true); + }); + }); + + describe('detectBlocks', () => { + it('should extract basic Graphviz blocks', () => { + const content = ` +\`\`\`graphviz:simple +digraph G { + A -> B; +} +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + expect(blocks).toHaveLength(1); + expect(blocks[0].name).toBe('simple'); + expect(blocks[0].content.trim()).toBe('digraph G {\n A -> B;\n}'); + }); + + it('should extract blocks with parameters', () => { + const content = ` +\`\`\`graphviz:flowchart {layout=neato, theme=dark, dpi=300} +digraph G { + A -> B; +} +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + expect(blocks).toHaveLength(1); + expect(blocks[0].name).toBe('flowchart'); + expect(blocks[0].metadata?.params).toEqual({ + layout: 'neato', + theme: 'dark', + dpi: '300', + }); + }); + + it('should handle multiple blocks', () => { + const content = ` +\`\`\`graphviz:first +digraph G1 { A -> B; } +\`\`\` + +\`\`\`graphviz:second +digraph G2 { B -> C; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + expect(blocks).toHaveLength(2); + expect(blocks[0].name).toBe('first'); + expect(blocks[1].name).toBe('second'); + }); + + it('should handle blocks without parameters', () => { + const content = ` +\`\`\`graphviz:no-params +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + expect(blocks).toHaveLength(1); + expect(blocks[0].metadata?.params).toEqual({}); + }); + }); + + describe('process', () => { + it('should process content with Graphviz blocks when CLI is available', async () => { + // Mock CLI detection + jest.spyOn(GraphvizProcessor, 'detectGraphvizCLI').mockResolvedValue(true); + + // Mock successful diagram generation - need to mock the private method + const generateDiagramSpy = jest + .spyOn( + processor as unknown as { generateDiagram: () => Promise }, + 'generateDiagram', + ) + .mockResolvedValue({ + success: true, + outputPath: '/test/assets/test.png', + }); + + const content = ` +\`\`\`graphviz:test +digraph G { A -> B; } +\`\`\` +`; + + const result = await processor.process(content, context); + + expect(result.success).toBe(true); + expect(result.blocksProcessed).toBe(1); + expect(result.processedContent).toContain('![test]'); + expect(generateDiagramSpy).toHaveBeenCalled(); + }); + + it('should handle missing Graphviz CLI gracefully', async () => { + // Mock CLI detection failure + jest.spyOn(GraphvizProcessor, 'detectGraphvizCLI').mockResolvedValue(false); + + const content = ` +\`\`\`graphviz:test +digraph G { A -> B; } +\`\`\` +`; + + const result = await processor.process(content, context); + + expect(result.success).toBe(true); + expect(result.blocksProcessed).toBe(1); + expect(result.processedContent).toContain( + '', + ); + }); + + it('should return unchanged content when no blocks found', async () => { + const content = '# No Graphviz blocks here'; + + const result = await processor.process(content, context); + + expect(result.success).toBe(true); + expect(result.blocksProcessed).toBe(0); + expect(result.processedContent).toBe(content); + }); + + it('should handle processing errors gracefully', async () => { + // Mock CLI detection success but processing failure + jest.spyOn(GraphvizProcessor, 'detectGraphvizCLI').mockResolvedValue(true); + mockFs.existsSync.mockReturnValue(false); // Simulate file creation failure + + const content = ` +\`\`\`graphviz:test +digraph G { A -> B; } +\`\`\` +`; + + const result = await processor.process(content, context); + + expect(result.success).toBe(true); + expect(result.blocksProcessed).toBe(1); + }); + }); + + describe('parameter parsing', () => { + it('should parse layout engine parameter', () => { + const content = ` +\`\`\`graphviz:test {layout=neato} +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + const params = blocks[0].metadata?.params as Record | undefined; + expect(params?.layout).toBe('neato'); + }); + + it('should parse theme parameter', () => { + const content = ` +\`\`\`graphviz:test {theme=dark} +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + const params = blocks[0].metadata?.params as Record | undefined; + expect(params?.theme).toBe('dark'); + }); + + it('should parse DPI parameter', () => { + const content = ` +\`\`\`graphviz:test {dpi=300} +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + const params = blocks[0].metadata?.params as Record | undefined; + expect(params?.dpi).toBe('300'); + }); + + it('should parse multiple parameters', () => { + const content = ` +\`\`\`graphviz:test {layout=neato, theme=dark, dpi=300} +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + const params = blocks[0].metadata?.params as Record | undefined; + expect(params).toEqual({ + layout: 'neato', + theme: 'dark', + dpi: '300', + }); + }); + + it('should handle parameters with spaces', () => { + const content = ` +\`\`\`graphviz:test { layout = neato , theme = dark } +digraph G { A -> B; } +\`\`\` +`; + + const blocks = processor.detectBlocks(content); + const params = blocks[0].metadata?.params as Record | undefined; + expect(params).toEqual({ + layout: 'neato', + theme: 'dark', + }); + }); + }); + + describe('utility methods', () => { + it('should return supported layout engines', () => { + const engines = processor.getSupportedLayoutEngines(); + expect(engines).toEqual(['dot', 'neato', 'fdp', 'sfdp', 'twopi', 'circo']); + }); + + it('should return supported output formats', () => { + const formats = processor.getSupportedOutputFormats(); + expect(formats).toEqual(['png', 'svg', 'pdf', 'jpeg']); + }); + }); + + describe('theme application', () => { + it('should apply dark theme styling', () => { + const config = { ...defaultConfig, theme: 'dark' as const }; + const processor = new GraphvizProcessor(config); + + const dotContent = 'digraph G { A -> B; }'; + const result = processor['applyTheme'](dotContent, config); + + expect(result).toContain('bgcolor="#2d3748"'); + expect(result).toContain('color="#e2e8f0"'); + expect(result).toContain('fontcolor="#e2e8f0"'); + }); + + it('should apply light theme styling', () => { + const config = { ...defaultConfig, theme: 'light' as const }; + const processor = new GraphvizProcessor(config); + + const dotContent = 'digraph G { A -> B; }'; + const result = processor['applyTheme'](dotContent, config); + + expect(result).toContain('bgcolor="#f7fafc"'); + expect(result).toContain('color="#2d3748"'); + expect(result).toContain('fontcolor="#2d3748"'); + }); + + it('should apply custom background color', () => { + const config = { ...defaultConfig, backgroundColor: '#ff0000' }; + const processor = new GraphvizProcessor(config); + + const dotContent = 'digraph G { A -> B; }'; + const result = processor['applyTheme'](dotContent, config); + + expect(result).toContain('bgcolor="#ff0000"'); + }); + + it('should apply custom font family', () => { + const config = { ...defaultConfig, fontFamily: 'monospace' }; + const processor = new GraphvizProcessor(config); + + const dotContent = 'digraph G { A -> B; }'; + const result = processor['applyTheme'](dotContent, config); + + expect(result).toContain('fontname="monospace"'); + }); + }); + + describe('error handling', () => { + it('should handle invalid DOT syntax gracefully', () => { + // This would normally call the CLI, but we're testing the validation method + // In a real scenario, this would be caught during processing + expect(() => { + // The processor should handle this gracefully during processing + }).not.toThrow(); + }); + + it('should handle missing intermediate directory', async () => { + mockFs.existsSync.mockReturnValue(false); + mockFs.mkdirSync.mockImplementation(() => undefined); + + const content = ` +\`\`\`graphviz:test +digraph G { A -> B; } +\`\`\` +`; + + jest.spyOn(GraphvizProcessor, 'detectGraphvizCLI').mockResolvedValue(true); + + const result = await processor.process(content, context); + expect(result.success).toBe(true); + }); + }); +}); From abe1fec280320b7dab1fa1f17aac100acf0849b8 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 14:12:51 -0700 Subject: [PATCH 6/7] updated README --- README.md | 104 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6a7b791..cd358d2 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,14 @@ And if you're using Git to track your repository (recommended!) you can commit c ### Presentation Workflow (New!) - **Create presentations:** `wf create presentation "My Presentation Title"` -- **Mermaid diagrams:** Automatic processing of `mermaid:name` code blocks +- **Multi-engine diagrams:** Automatic processing of Mermaid, PlantUML, and Graphviz code blocks - **Rich formatting:** Convert to PPTX with embedded diagrams - **Status tracking:** Draft → review → published - **Asset management:** Auto-generated images in `assets/` directory -Example Mermaid block: +Example diagram blocks: +**Mermaid (flowcharts, sequence diagrams):** ````markdown ```mermaid:architecture {align=center, width=90%} graph TB @@ -74,6 +75,30 @@ graph TB ``` ```` +**PlantUML (UML diagrams):** +````markdown +```plantuml:class-diagram +@startuml +class User { + +name: string + +email: string + +login() +} +@enduml +``` +```` + +**Graphviz (network graphs, decision trees):** +````markdown +```graphviz:network {layout=dot} +digraph { + rankdir=LR; + A -> B -> C; + A -> D -> C; +} +``` +```` + ### Template System - **Inheritance:** Project templates override system defaults @@ -84,16 +109,17 @@ graph TB ### Processor System - **Modular Processing:** Each workflow specifies which processors to use -- **Job Applications:** Clean documents with no special processing -- **Presentations:** Rich diagrams with Mermaid, PlantUML support +- **Job Applications:** Clean documents with emoji processing only +- **Presentations:** Rich diagrams with multiple diagram engines and emoji support - **Extensible:** Add custom processors for your specific needs Available processors: -- 🧩 **Mermaid** - Generate diagrams from code blocks -- 🌱 **PlantUML** - Create UML diagrams and flowcharts -- šŸ˜€ **Emoji** - Convert shortcodes to Unicode emoji -- šŸ”Œ **Custom** - Build your own processors +- 🧩 **Mermaid** - Generate flowcharts, sequence diagrams, and more from code blocks +- 🌱 **PlantUML** - Create UML diagrams, activity diagrams, and flowcharts +- šŸ“Š **Graphviz** - Generate professional network graphs, decision trees, and complex diagrams +- šŸ˜€ **Emoji** - Convert shortcodes to Unicode emoji (`:rocket:` → šŸš€) +- šŸ”Œ **Custom** - Build your own processors for specialized content ## šŸš€ Quick Start @@ -104,6 +130,11 @@ Available processors: - pandoc (for document formatting) - turbo (for monorepo build orchestration) +**Optional (for diagram processing):** +- graphviz (for Graphviz processor) +- plantuml (for PlantUML processor) +- @mermaid-js/mermaid-cli (for Mermaid processor - installed automatically) + ### Installation **Option 1: Development Setup** @@ -236,6 +267,63 @@ wf format job collection_id --format pdf wf format job collection_id --format html ``` +### Diagram Processing + +The system supports three powerful diagram engines for different use cases: + +#### 🧩 Mermaid - Interactive Diagrams + +Best for: flowcharts, sequence diagrams, Gantt charts, mindmaps + +```markdown +```mermaid:system-flow +graph TB + A[User Request] --> B{Auth Check} + B -->|Valid| C[Process Request] + B -->|Invalid| D[Return Error] + C --> E[Response] +``` +``` + +**Supported diagram types:** flowchart, sequence, gantt, pie, journey, gitgraph, mindmap, timeline + +#### 🌱 PlantUML - Professional UML + +Best for: class diagrams, activity diagrams, use case diagrams, component diagrams + +```markdown +```plantuml:auth-sequence +@startuml +User -> AuthService: login(credentials) +AuthService -> Database: validateUser() +Database --> AuthService: userInfo +AuthService --> User: token +@enduml +``` +``` + +**Supported diagram types:** class, sequence, usecase, activity, component, state, object, deployment + +#### šŸ“Š Graphviz - Technical Graphs + +Best for: network topologies, decision trees, dependency graphs, org charts + +```markdown +```graphviz:dependency-graph {layout=dot} +digraph Dependencies { + rankdir=LR; + node [shape=box]; + + Frontend -> API; + API -> Database; + API -> Cache; + Frontend -> CDN; +} +``` +``` + +**Layout engines:** dot (hierarchical), neato (spring), fdp (force-directed), circo (circular), twopi (radial) + ### Emoji Processing The emoji processor converts shortcodes like `:rocket:` to Unicode emoji šŸš€. It uses GitHub's standard emoji names with convenient aliases for frequently used emojis. From ba205c65979ea7e5281715e53a781bf5c4fdb995 Mon Sep 17 00:00:00 2001 From: Nicholas Hart Date: Mon, 18 Aug 2025 14:15:57 -0700 Subject: [PATCH 7/7] fixed markdown formatting in README --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index cd358d2..c2ee68c 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ And if you're using Git to track your repository (recommended!) you can commit c Example diagram blocks: **Mermaid (flowcharts, sequence diagrams):** + ````markdown ```mermaid:architecture {align=center, width=90%} graph TB @@ -76,6 +77,7 @@ graph TB ```` **PlantUML (UML diagrams):** + ````markdown ```plantuml:class-diagram @startuml @@ -89,6 +91,7 @@ class User { ```` **Graphviz (network graphs, decision trees):** + ````markdown ```graphviz:network {layout=dot} digraph { @@ -131,6 +134,7 @@ Available processors: - turbo (for monorepo build orchestration) **Optional (for diagram processing):** + - graphviz (for Graphviz processor) - plantuml (for PlantUML processor) - @mermaid-js/mermaid-cli (for Mermaid processor - installed automatically) @@ -275,7 +279,7 @@ The system supports three powerful diagram engines for different use cases: Best for: flowcharts, sequence diagrams, Gantt charts, mindmaps -```markdown +````markdown ```mermaid:system-flow graph TB A[User Request] --> B{Auth Check} @@ -283,7 +287,9 @@ graph TB B -->|Invalid| D[Return Error] C --> E[Response] ``` -``` +```` + +```` **Supported diagram types:** flowchart, sequence, gantt, pie, journey, gitgraph, mindmap, timeline @@ -299,8 +305,9 @@ AuthService -> Database: validateUser() Database --> AuthService: userInfo AuthService --> User: token @enduml -``` -``` +```` + +```` **Supported diagram types:** class, sequence, usecase, activity, component, state, object, deployment @@ -313,14 +320,15 @@ Best for: network topologies, decision trees, dependency graphs, org charts digraph Dependencies { rankdir=LR; node [shape=box]; - + Frontend -> API; API -> Database; API -> Cache; Frontend -> CDN; } -``` -``` +```` + +```` **Layout engines:** dot (hierarchical), neato (spring), fdp (force-directed), circo (circular), twopi (radial) @@ -334,7 +342,7 @@ The emoji processor converts shortcodes like `:rocket:` to Unicode emoji šŸš€. I Looking forward to working at DoorDash :takeout_box:! This project is :fire: and I'm :thumbsup: about it! More info available here :information_source: -``` +```` **Naming Convention:**