From cc5244228dec84975d8b73df5fee67f7790f359a Mon Sep 17 00:00:00 2001 From: Peter Verhas Date: Sat, 18 Nov 2023 22:21:39 +0100 Subject: [PATCH] DEMO.md document was created --- jamal-assertions/README.adoc | 5 +- jamal-snippet/README.adoc | 34 ++-- jamal-test/DEMO.md | 129 ++++++++++++++ jamal-test/DEMO.md.jam | 162 ++++++++++++++++++ jamal-test/KROKI_MD.svg | 1 + jamal-test/KROKI_MD.svg.hash | 1 + jamal-test/STR.svg | 1 + jamal-test/STR.svg.hash | 1 + .../src/test/resources/demoConverted.docx | Bin 12792 -> 12792 bytes .../test/resources/includetestConverted.docx | Bin 34572 -> 34572 bytes .../src/test/resources/pictureConverted.docx | Bin 21869 -> 21869 bytes .../src/test/resources/sampleConverted.docx | Bin 40811 -> 40815 bytes 12 files changed, 316 insertions(+), 18 deletions(-) create mode 100644 jamal-test/DEMO.md create mode 100644 jamal-test/DEMO.md.jam create mode 100644 jamal-test/KROKI_MD.svg create mode 100644 jamal-test/KROKI_MD.svg.hash create mode 100644 jamal-test/STR.svg create mode 100644 jamal-test/STR.svg.hash diff --git a/jamal-assertions/README.adoc b/jamal-assertions/README.adoc index f641ac8ac..253e1a603 100644 --- a/jamal-assertions/README.adoc +++ b/jamal-assertions/README.adoc @@ -565,4 +565,7 @@ results 7. ERROR: 8. ERROR: 3.14 is not a not numeric 9. ERROR: three is an int, not a not int, and thus a numeric ----- \ No newline at end of file +---- + + + diff --git a/jamal-snippet/README.adoc b/jamal-snippet/README.adoc index bfb3c6699..08a37a020 100644 --- a/jamal-snippet/README.adoc +++ b/jamal-snippet/README.adoc @@ -168,7 +168,7 @@ Since 1.7.4 option `onceAs` This macro collects text snippets from files. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The syntax of the macro is @@ -318,7 +318,7 @@ The output of the `collect` macro is an empty string. The macro behaviour can be altered using options. -These options are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These options are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. * `include` @@ -780,8 +780,8 @@ will result in [source] ---- -/Users/verhasp/github/jamal/jamal-snippet/documentation/macros/snippy.txt -/Users/verhasp/github/jamal/jamal-snippet/documentation/macros/snip_define.adoc.jam +../jamal-snippet/documentation/macros/snippy.txt +../jamal-snippet/documentation/macros/snip_define.adoc.jam ---- @@ -1108,7 +1108,7 @@ You cannot use `warning` and `error` together. This macro lists the defined snippets. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The list is represented as comma-delimited, which contains the names of the snippets. @@ -1152,7 +1152,7 @@ This is not an error in Jamal, only if you try to use any of these snippets. This macro saves all the collected snippets to a file. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The file name must be specified by the parameter `output`. The general syntax of the macro is @@ -1244,7 +1244,7 @@ It is saved as a `CDATA` section(s). This macro can load the snippets from a file, which was saved by <>. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The file's name has to be specified by the parameter `input`. The general syntax of the macro is @@ -1294,7 +1294,7 @@ If you want to change something in the XML file and edit some snippet code tempo This macro can cut off the unneeded spaces from the start and end of the lines. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. When you include a code fragment in the documentation as a snippet, the lines may have extra spaces at the start. @@ -1700,7 +1700,7 @@ will result [source] ---- -/Users/verhasp/github/jamal/jamal-snippet/README.adoc.jam:967:30 +../jamal-snippet/README.adoc.jam:968:30 ---- @@ -1914,7 +1914,7 @@ If you write `semver` (case insensitive) instead of the fully qualified domain n This macro can put numbers in front of the lines, sequentially numbering them. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The syntax of the macro is @@ -1983,7 +1983,7 @@ Any illegal formatting will result in an error. This macro deletes, or keeps the selected lines from its input. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The format of the macro is @@ -2072,7 +2072,7 @@ In this case only the comment lines remained that start with `//` at the start o You can use this macro to skip lines from the snippet. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. It is similar to <> but this macro deletes ranges of lines instead of individual lines. @@ -2183,7 +2183,7 @@ In that case you can switch it off using the option `(detectNoChange=false)` in This macro replaces strings in the input. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. It works similarly to the macro <>. @@ -2618,7 +2618,7 @@ This macro will define the macro with the literal text `UNDEFINED` if the macro This macro reflows the content. The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The default behavior is to remove all single new-line characters replacing them with spaces. @@ -2882,7 +2882,7 @@ It can kill/keep lines, skip, replace, trim, lines, select line ranges; it can r The first line following the macro identifier until the end of the line may contain parameters. -These parameters are parsed using the Standard Parameter Parsing as defined in link:../documentation/PAROPS.adoc[PAROPS]. +These parameters are parsed using the Standard Parameter Parsing as defined in link:../../../documentation/PAROPS.adoc[PAROPS]. The macro implementation itself is calling the underlying other macros, so the functionality what and how it does the above actions are identical. @@ -3600,7 +3600,7 @@ will result in the output [source] ---- -2023-11-18 18:20:49 +2023-11-18 22:08:12 ---- @@ -3949,7 +3949,7 @@ will result in [source] ---- -/Users/verhasp/github/jamal/jamal-snippet/README.adoc +/Users/verhasp/github/jamal/jamal-snippet/../jamal-snippet/README.adoc ---- diff --git a/jamal-test/DEMO.md b/jamal-test/DEMO.md new file mode 100644 index 000000000..06ad56c3e --- /dev/null +++ b/jamal-test/DEMO.md @@ -0,0 +1,129 @@ +# Jamal Markdown Demo + + +> This document is not meant to be read formatted. +The formatted version is `DEMO.md`. +What you need to read is the `DEMO.md.jam` file in IntelliJ and see the source code and the formatted version side-by-side. + +This is a simple markdown demo file, that you can edit using IntelliJ IDEA with the Asciidoctor plugin and Jamal installed as a preprocessor. +The current Jamal version is`2.5.0-SNAPSHOT`. +This version information is read from the `pom.xml` file. +It means that there is no need to edit this document if the version changes only to change the version number. + +## Dependency on External Files + +This document depends on many files. +(No, not really.) +One file is `README.adoc.jam` (no, not really). +In this text this file is referenced using the `file` macro. +With this macro, we can be sure that the file exists. + +If the file `README.adoc.jam` was renamed, or removed and the Jamal processing of this file is part of the CI/CD process, the build will fail. +This is a god thing, because it means that the documentation is always up-to-date. + + + + +We can check not only the existence of the file, but also its content. +Currently, the hashCode of the file `README.adoc.jam` is `5030f7f5.fd1c50e4.629944fd.44409cb9.9b55f346.bd66859c.73cd98cd.da5418d5`. +We can use the `snip:check` macro to check that the file has not been changed. +If the file has changed, the build will fail. +This is a god thing, because it means that the documentation is always up-to-date. + +Oh, by the way: you do not need the whole hash code! +Do not freak out! +It is enough if you copy 8 characters from the hash code. + +## Internal Consistency of the Document + +Did I say that already? +Oh yes, I did. +What happens if I realize that there is a typo in this text and I want to correct it? +It is not a _god_ thing, even though Jamal is superb, but still it is a _good_ thing. + +Without Jamal, the probable scenario would be that I change the occurrence where I see that there is a missing 'o'. +The other occurrence would remain unchanged. +However, using the `variation` macro Jamal will warn me that there are multiple occurrences of the same text. +Until I change all of them to be identical, the build will fail. +This is a god thing, because it means that the documentation is always up-to-date. +(Sorry, I still have to write it so again, because I want this typo for demonstration.) + +However, you can use the `variation` macro even if the texts differ a bit. +You can separate the "constant" and the "variable" part of the text. +Like here: + +This is a good thing, because it means that the documentation is always up-to-date. + +How did this happen? +I enclosed the variable part of the text in `pass:[<<]` and `pass:[>>]`. +So I wrote `This is a gopass:[<<]o>>d thing,...` +As simple as that. + +## Avoid copy-paste totally + +If you do not want to use the `variation` macro and maintain copies of the same text you can define macros. +In this document, we have already used a macro definition. +If you look at the `DEMO.md.jam` file you will see a definition on the line 24. +We define the macro `HASH` there because we want to use the same value in the `snip:check` macro and in the text. +Usually you do not display such hash codes in the text, you use it only in the `snip:check` macro. + +Macros are not only constant texts named. +Macros can have arguments, defined inside other macros, enclosed in scopes and many other things. +There are more than 200 different macros defined in several macro libraries. +Use only that you are comfortable with and what you need. + +## Diagrams + + +You can use, for example, the KROKI diagram creating macro. +Like here: + +![](KROKI_MD.svg) + +![](STR.svg) + +With this, you can embed diagrams into your documentation. +The `kroki` macro supports all the 27 diagram types that Kroki itself support. +You can embed any or all of the diagram texts into your documentation. +Jamal's processing will create the diagrams and embed them into the documentation. + +You do not need any Markdown (or whatever format you use) extensions. +The markdown file Jamal generates will only contain the image links. +Uploading the document to GitLab, GitHub or to another platform that handles only plain Markdown will work. +You will have there the `DEMO.md`, `KROKI_MD.svg` and `STR.svg` files. +(To avoid unnecessary processing the `.svg.hash` files are also created and Kroki runs only when the digram code changes.) + +BTW: the diagram code inside your document may also contain Jamal code, and it will be processed if you need it. + +## Fecth data from external sources + +You can fetch data from external sources. +You have already seen the software version. +You do not need to copy any text from the documented system. +You can define snippets in your code, collect them in your document and reference them. + + +For example, here is the default implementation of the `getId()` method of the Jamal interface `Macro`. + +```java + default String getId() { + return this.getClass().getSimpleName().toLowerCase(); + } + +``` + +If the code changes, the documentation will change too, automatically. +This is a good thing, because it means that the documentation is always up-to-date. + +It is not only code samples, you can fetch any text from any file, and you can also transform them before using them in your document. +If you think that a small piece of the documentation is easier to maintain as little comment in the code, you can do that. +Keep that small piece there, and fetch it into your documentation. +When your code changes, you are less likely to forget to update the documentation when the documenting text is right there with your code. + +## What else? + +What I described here is only the tip of the iceberg. +You can include files, information from JAR files, web pages, and so on. +You can use hierarchical counters, make transformations on the included lines, repeat the same text multiple times, and so on. + +For all the possibilities and the details, please read the [Jamal documentation](../README.adoc). \ No newline at end of file diff --git a/jamal-test/DEMO.md.jam b/jamal-test/DEMO.md.jam new file mode 100644 index 000000000..81ce9c1d4 --- /dev/null +++ b/jamal-test/DEMO.md.jam @@ -0,0 +1,162 @@ +# Jamal Markdown Demo +{%@snip:xml pom=pom.xml%}{%#define VERSION={%pom /project/version/text()%}%} + +> This document is not meant to be read formatted. +The formatted version is `DEMO.md`. +What you need to read is the `DEMO.md.jam` file in IntelliJ and see the source code and the formatted version side-by-side. + +This is a simple markdown demo file, that you can edit using IntelliJ IDEA with the Asciidoctor plugin and Jamal installed as a preprocessor. +The current Jamal version is`{%VERSION%}`. +This version information is read from the `pom.xml` file. +It means that there is no need to edit this document if the version changes only to change the version number. + +## Dependency on External Files + +This document depends on many files. +(No, not really.) +One file is `{%@file README.adoc.jam%}` (no, not really). +In this text this file is referenced using the `file` macro. +With this macro, we can be sure that the file exists. + +If the file `{%@file README.adoc.jam%}` was renamed, or removed and the Jamal processing of this file is part of the CI/CD process, the build will fail. +{%@variation This is a god thing, because it means that the documentation is always up-to-date.%} + +{%@define HASH=5030f7f5.fd1c50e4.629944fd.44409cb9.9b55f346.bd66859c.73cd98cd.da5418d5%} +{%#define LINE={%@pos.line%}%} +{%#snip:check file=README.adoc.jam hashCode={%HASH%}%} +We can check not only the existence of the file, but also its content. +Currently, the hashCode of the file `{%@file README.adoc.jam%}` is `{%HASH%}`. +We can use the `snip:check` macro to check that the file has not been changed. +If the file has changed, the build will fail. +{%@variation This is a god thing, because it means that the documentation is always up-to-date.%} + +Oh, by the way: you do not need the whole hash code! +Do not freak out! +It is enough if you copy 8 characters from the hash code. + +## Internal Consistency of the Document + +Did I say that already? +Oh yes, I did. +What happens if I realize that there is a typo in this text and I want to correct it? +It is not a _god_ thing, even though Jamal is superb, but still it is a _good_ thing. + +Without Jamal, the probable scenario would be that I change the occurrence where I see that there is a missing 'o'. +The other occurrence would remain unchanged. +However, using the `variation` macro Jamal will warn me that there are multiple occurrences of the same text. +Until I change all of them to be identical, the build will fail. +{%@variation This is a god thing, because it means that the documentation is always up-to-date.%} +(Sorry, I still have to write it so again, because I want this typo for demonstration.) + +However, you can use the `variation` macro even if the texts differ a bit. +You can separate the "constant" and the "variable" part of the text. +Like here: + +{%@variation This is a go<>d thing, because it means that the documentation is always up-to-date.%} + +How did this happen? +I enclosed the variable part of the text in `pass:[<<]` and `pass:[>>]`. +So I wrote `This is a gopass:[<<]o>>d thing,...` +As simple as that. + +## Avoid copy-paste totally + +If you do not want to use the `variation` macro and maintain copies of the same text you can define macros. +In this document, we have already used a macro definition. +If you look at the `DEMO.md.jam` file you will see a definition on the line {%LINE%}. +We define the macro `HASH` there because we want to use the same value in the `snip:check` macro and in the text. +Usually you do not display such hash codes in the text, you use it only in the `snip:check` macro. + +Macros are not only constant texts named. +Macros can have arguments, defined inside other macros, enclosed in scopes and many other things. +There are more than 200 different macros defined in several macro libraries. +Use only that you are comfortable with and what you need. + +## Diagrams + +{%@import res:kroki.jim%} +You can use, for example, the KROKI diagram creating macro. +Like here: + +{%kroki /KROKI_MD/plantuml/svg/ +Alice -> Bob: Authentication Request +Bob --> Alice: Authentication Response + +Alice -> Bob: Another authentication Request +Alice <-- Bob: Another authentication Response +%} + +{%kroki /STR/structurizr/svg/ +workspace { +model { +user = person "Algien" +softwareSystem = softwareSystem "Software System" { +webapp = container "Web Application" { +user -> this "Uses!!!" +} +database = container "Database" { +webapp -> this "Reads from and writes to" +} +} +} +views { +systemContext softwareSystem { +include * +autolayout lr +} +container softwareSystem { +include * +autolayout lr +} +theme default +} +} +%} + +With this, you can embed diagrams into your documentation. +The `kroki` macro supports all the 27 diagram types that Kroki itself support. +You can embed any or all of the diagram texts into your documentation. +Jamal's processing will create the diagrams and embed them into the documentation. + +You do not need any Markdown (or whatever format you use) extensions. +The markdown file Jamal generates will only contain the image links. +Uploading the document to GitLab, GitHub or to another platform that handles only plain Markdown will work. +You will have there the `DEMO.md`, `KROKI_MD.svg` and `STR.svg` files. +(To avoid unnecessary processing the `.svg.hash` files are also created and Kroki runs only when the digram code changes.) + +BTW: the diagram code inside your document may also contain Jamal code, and it will be processed if you need it. + +## Fecth data from external sources + +You can fetch data from external sources. +You have already seen the software version. +You do not need to copy any text from the documented system. +You can define snippets in your code, collect them in your document and reference them. +{%@snip:collect from=../jamal-api/src%} + +For example, here is the default implementation of the `getId()` method of the Jamal interface `Macro`. + +```java +{%@snip getId%} +``` + +If the code changes, the documentation will change too, automatically. +{%@variation This is a go<>d thing, because it means that the documentation is always up-to-date.%} + +It is not only code samples, you can fetch any text from any file, and you can also transform them before using them in your document. +If you think that a small piece of the documentation is easier to maintain as little comment in the code, you can do that. +Keep that small piece there, and fetch it into your documentation. +When your code changes, you are less likely to forget to update the documentation when the documenting text is right there with your code. + +## What else? + +What I described here is only the tip of the iceberg. +You can include files, information from JAR files, web pages, and so on. +You can use hierarchical counters, make transformations on the included lines, repeat the same text multiple times, and so on. + +For all the possibilities and the details, please read the [Jamal documentation](../README.adoc). + + + + + diff --git a/jamal-test/KROKI_MD.svg b/jamal-test/KROKI_MD.svg new file mode 100644 index 000000000..dad65ba26 --- /dev/null +++ b/jamal-test/KROKI_MD.svg @@ -0,0 +1 @@ +AliceAliceBobBobAuthentication RequestAuthentication ResponseAnother authentication RequestAnother authentication Response \ No newline at end of file diff --git a/jamal-test/KROKI_MD.svg.hash b/jamal-test/KROKI_MD.svg.hash new file mode 100644 index 000000000..aa48d990c --- /dev/null +++ b/jamal-test/KROKI_MD.svg.hash @@ -0,0 +1 @@ +b5a5bcc5fa63cd707cb51302e1036fb1773b33818760a6a0da96e1913e40d88b \ No newline at end of file diff --git a/jamal-test/STR.svg b/jamal-test/STR.svg new file mode 100644 index 000000000..cf5de03ef --- /dev/null +++ b/jamal-test/STR.svg @@ -0,0 +1 @@ +Software System - ContainersSoftware System[Software System]Web Application[Container]Database[Container]Algien[Person]Uses!!!Reads from andwrites to \ No newline at end of file diff --git a/jamal-test/STR.svg.hash b/jamal-test/STR.svg.hash new file mode 100644 index 000000000..c0153b416 --- /dev/null +++ b/jamal-test/STR.svg.hash @@ -0,0 +1 @@ +7308555bc6d712513cbec875321940bc46b6b29793c526611a32ffcc66d4f77a \ No newline at end of file diff --git a/jamal-word/src/test/resources/demoConverted.docx b/jamal-word/src/test/resources/demoConverted.docx index 83bb050751115f4782a7210231193caa21fa69c2..7eaf9119c34a06442932c753b678c31aac3b1813 100644 GIT binary patch delta 216 zcmey7{3Dq+z?+#xgn@&DgF$*@(MH}qjLblK^BG2E2;&n|JA_fgG6~F>EXZ~OtmF=x z2{)J_EMy8%;w?N4!gwOGlo>45BLOwfTk1G3SVUCgCL4$``JEXZ~OtmF=x z2{)J_EMy8%;w?N4!gwOGlo>45BLOwfTk1G3SVUCgCL4$``J5WAjdCxO41L@888T}y)L*~Cw25Sj~v4SlT!rXfkIe7!fEkBfu0urTdK*HtU-aRE zFz)$QLl`ms9bm@f=K*#gO_MbO&A@bGpf#ADA7}%n?*&5S<%1ynxFC11_=+G~F#RIP o5lrg@L-;wt5Ou4AtswHj4q#e4#2ZXkhJ=CXOCkPXS|!vI0IUgW;{X5v delta 304 zcmaF6it+6#M&1B#W)=|!4h{~6@5O~1dCxO41L@888T}y)L*~Cw25Sj~v4SlT!rXfkIe7!fEkBfu0urTdK*HtU-aRE zFz)$QLl`ms9bm@f=K*#gO_MbO&A@bGpf#ADA7}%n?*&5S<%1ynxFC11_=+G~F#RIP o5lrg@L-;wt5Ou4AtswHj4q#e4#2ZXkhJ=CXOCkPXS|!vI0A$mDy#N3J diff --git a/jamal-word/src/test/resources/sampleConverted.docx b/jamal-word/src/test/resources/sampleConverted.docx index a804679034573f8e0eb1b312cd61805d89c3349f..79608f47205b70d86d771db7ab56381c6cde058b 100644 GIT binary patch delta 2382 zcmY+Gdpr|*AIE3JkZV0FxgB>>94eOxo0uXcq_QZUxkf{Cw>g>nwMJr%nB=aRxs0?* zR+;25mxeJ??w6hAR-Ds3f1Ky{&-?See7>*WpP%^-;Bp60;*!0f&_MtQ1OmvDLP-*D z1qA;gnJFN*Csu(!|0je{e1T(2gUJ}-F(7}>Q#5Q(FvYX>gpXwSo?uHeWcWLEs!#V$ zTv4~*8v#3EC0S>gPtAHcXgo`{u zGNe$V671}}7_9hQ1R`)Z4qxV{gZt=W=p2%Fyh4iFXENpo|H0M2hzMEryNw@WGBetd zK8MQB&mXHdawD_HtL^W6@9xI@X!mR^pSK$J$erbcJ2S7;i-nzH9SA3BDWGivFDW^#ECZJVz2VW;Vk%dne{9GoW^e<%9-Y`VSn2N$x_!+- za)#-D^Lt{+SCS`fn64vPZbdM$o*xa{i4*>INOsX*4F}si#F`W7XP?wIaoEvS%Uw*b_ zzdQpc7cVW%d|_>BB9)uxykqRiL+j)7_+krm^yfMUeBI1;2zEfJFnDCz)nz$4JGFn; zTn$313>pvWUQZT=4!>eQIUOqsOAK}geU#>@ff~(c3P{8%Ob{yP*vkR<_j4DA?>mtP z+e%~V-MZ_7pDYuTa_pn`U#2pxynGiL`gA(As;WN@z8%o7-gS+Tarv+KzNrd>fv?Vi zrb{wUoMvU)w`$OAX2GoD=*SNi8D*5|xUrdoQK(2#WB}!tw=ejQD2fqjn}{9J4Ti_! zXFZX0>;LS^W0Zar2$s*m(Bj=svy%;}tPukV4DF`1y32jzh*k>aMXljgNz2>MV_z77 zh2P!cjYGDko5rQg*@q=I*NI(Ylo|FXxvISF4o}vtF%&8)%&&>YW2aB&EOWVkB~D!& zbj;kQE)}(%Msv<~m_>gkYIWX%?=w*?%b!S5cj(l{$bPartu6at*vW)rXk&mi`BS1V z1f-ERX*UrGYzDWgsvm~xNX5A%Q#;+h#a19qZAMB|7%5XARNQES-8&&zF0Mt^8m_7a zE(Lje#79pUo{QbpO#y`{E}hqc%82$uUW7l*fWzr(de(9%Z%w;qsm&C2pUS zWFbZ+8)jTe>l@TR}mtlVgjuU?F+%$$KO^cL8sK23XG)FVMwU# zK;Wd)y?Rp_q+Va12K2o~-2qcz@6lP{kRK+ttT#3NI*xYA=1fkBG_Xfn4zl&6{ai(R z5lu$Lxjd>r_}lEJ8ulKW%MBB-RM0utfmZE0lQuYS7rI2;1PhF)9O>6S$aqChRXkMh<)o_kV?p)} zSb=yVQ|EEbrvN!?C2R|Yc3-U4ECge>4-%E`{Qbnn)FzU=AlS8sCY^7F z!lCfA;%eF9i>nzIv2SiPUeUN`vtg0Hf#g7a3x&)()$)a2BU(i6+XHh6>VKROFV5!F zWvhxA?Z0POg`Jvmy(ao_;u%V#b*i+LIKiOz?RT;`DBhT)ZDKY_anmqQTg8Org1mPl z_2*PtB=XXCNNa9plr3GJjcLGHDtrX)Im+uT;C9eISYV@0P3n^CYE5Ae+n7Qg9$8lI zbETJ%t$2WMu5T2p)8|ZMx>=C1RvTRjoaf{7b8h6yE)cOmsg3AKS*i{0s$LsN{5^bt zQN47*!*MOV`MTrvyr$$67(X|}9pyz@e`?Xs(uC@-E7L2sQf|W~^_6-={QZT-=iNKe z0ZVuLGnz-4N${SuSn{GB#$a*6y?pV_3W8Ds%aA;*NSaJ{+%AADdrzqoaSJuYX75LF z85a!0AFQ71x@c(dzH{YjxL?NcwK)O3QD<^~{d{S~x@Mc{q-TmPM)q@Uu!DIA1QN|8 zPHbp1JmPFYHHmDg@t~v2ub_jl5*S?gGq`KrQO@Bq$*~QAG#hV~)FF-YRBH(5H zyWSo<%9rd#K=zpfi6tTcz#BOL;Q#Ujc{!1~pC1Bh9t;WdMN&b^UXGB#Tktc$WxNre z>3B0f-{Z~s1U=p(?D1KCo%Pt3&!NYbe995_=2r!;Swr zoPUv#@~`R>4muIP9{>=F1puS~|9&&Ljv^(#lU*b)K*Vhqsq-DnVmgj60RR9k2ml=X Rw*e4`vnbXQ7RLW-{te9Bg)#sD delta 2421 zcmY+Gdpy(s9>>3ya%s7h%P6-fQsf$&wopw*Zm|?CcOr7%WcyYwOUB$nW)o^c=9Zt_ z%Oy3TD?-RMlWRW@cb%H^IFHWzpXcj+|NQrP&ow}%8z6hEFgtkn0sQ>@z;aMP*`8LO z9lu%enFqEl79gAd6}%x_kuoGAQ33Ay3gOn_1cJ83=iLe0!b2!@TMUW373J2j6d!Mo zuvfxtryd>pc!8S=znR93{27{}N)iGu2lf9WMnW|<Xe|h zvq_09F-jLj%5#G|K@`U3S(eAgbA7R%zDDcLl5zf$adD07TSQyjNw0n^v)K@i9K%BUy?cEQ5MF!d@P+<)?+b<(x&_I3`qBn2{rV6Eq^mpYZB&^!EAS` zEa0%|X%rCyn&yeP$m>|oy*(Co7eCU9WiHrz)D{a8w=#5pq*D+DN=$v7nvl`Em?EF~ zm(MmEIBRX*8%{m|GH_uY3#Q<`IMqW*$r>56?|T=mM==93``|u;UzbICnT!KZ``TY@ z>@}gfq9V(>Z1-E-hAX>H7fg;!LrX28P=|j*^foHumA#Oaw)b(KXk=dj`*7$ML)#Kc znf_MvwDdvG_(NK4ME3G}zQj_GfwF7|J##mjxT)-*ZKP2Y-!U@X$=JAJKl!Q1oA1nd=9H&wXNBFf|K14tWZ7ws~ug**7=4dw4QE#C#aeT zoFfsT8mygpB9Eo6=7pe1&IQBfeun0+8x2nCzHXkGYj3GrSxu)0H`dpuP{enxu1b&UIH!bd;N-3@~b|R z2;|5|32nv9OxfzQem0PYDb}dSQ|%^p*ANALNa2r5V1DMb!jvjXyRd3CCvO|I?J_AZzP{fyxQ|s^cWb4E8PfeJsPRLcmU_%R-<+#iy06wEyo>WsLUj7-cuJ6k zLt)HMk&%3tiG+XDC*Bv};bYl+TBVT=S4T;`sok>|rlDCltlX`x#Ws_(0MHTYBhA>b?~fEs9CfB@m{Ier>vS<_9a*UezCOX6EaWx{3@e)j$Et{OGMt+ zZA+Szgp)Vc?MG$9HznXEm5a0F$^)=T^PeN1W^PY|5^pqz(k(wqCZOC=CkCZPWowh= zl>>$?7((B7Dmc0+B$$rp>*uPZ3*3u3YR`K{5zI`4q750E(45l*QMi!1&Zxea7;dE7 z#q#Vv6REw{w>ZbCyI^p+LnmKagPSKhPB{vOOIaL)4>ypP^Dh(5E zDpAJRG)k(~^Yi9P3_JD?*87zwr>ul4ncyv-nDB>+s>+!PM`HdpBG_6Hh_MH41fSKc zJ!}vXkGM7|d%+2d17t{k$U;?+skuYxG56*thTqMrCzmdN0ls;tPWr#~IKl^+lo_DAM+2~I$_4x)@5Eo_SDcBks5q6U~RB%l~ zP;BI_UxEL3j(^lt5;i<9Y76l{#Cc zzBf+>O4tv^R7sb*Qsrec5wNUP-b@7tpcPWA0L!A!_t73Jo}UlUf+@dT1+VCwx*>DT zzS(u$2T>KHwq&R6-9o4+vm=F^F!WR>%gU^)7xux1z89CRsg@&sJ?7WKA!~<9rlIO# z+NTZ?9G0ANt6Xav+Gl26mIs=1KiK$#5zln%PI<3K>XQA8sd{tFqQ!yeKvMV9OUvcg zJP2U#Q_o_(s{F(6a*l!FVCg|i$?yanON z!V0Tx4)XZ8k4s>Q*!vb+B)lfgW_6&p({f@M$w6E-nVfaq-K;&e8tc58w3smhF1q7o z)Q*_8EfsumWYjS%5_;_Bx@+36&r;}RAXRF-88JRHuOWeLslPkbeRx_B1^%sWb$a z9W+BOp;_C+WS!>v$ysN)?9W1Rd4Rs1cci1aK9hcu%L%#>mq!?If#377+{dL{XXrWp z@!q8v58r|U0B-~U2m^oHNHhS1`3Jgb1O*d(-GkKe*L|%pJdl0B|E?lzpz(+7^j!c@ sB@Y1NfA<2}DZdy>a(@=g396n)^8f&82k^V|ZzH4_XCK}Lq5X;d2NcA93jhEB