AutoDoc-2023.06.19/000755 000766 000024 00000000000 14444021302 013735 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/PackageInfo.g000644 000766 000024 00000011055 14444021247 016266 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later SetPackageInfo( rec( PackageName := "AutoDoc", Subtitle := "Generate documentation from GAP source code", Version := "2023.06.19", Date := ~.Version{[ 1 .. 10 ]}, Date := Concatenation( ~.Date{[ 9, 10 ]}, "/", ~.Date{[ 6, 7 ]}, "/", ~.Date{[ 1 .. 4 ]} ), License := "GPL-2.0-or-later", Persons := [ rec( LastName := "Gutsche", FirstNames := "Sebastian", IsAuthor := true, IsMaintainer := true, Email := "gutsche@mathematik.uni-siegen.de", WWWHome := "https://algebra.mathematik.uni-siegen.de/gutsche/", PostalAddress := Concatenation( "Department Mathematik\n", "Universität Siegen\n", "Walter-Flex-Straße 3\n", "57072 Siegen\n", "Germany" ), Place := "Siegen", Institution := "Universität Siegen" ), rec( LastName := "Horn", FirstNames := "Max", IsAuthor := true, IsMaintainer := true, Email := "mhorn@rptu.de", WWWHome := "https://www.quendi.de/math", PostalAddress := Concatenation( "Fachbereich Mathematik\n", "RPTU Kaiserslautern-Landau\n", "Gottlieb-Daimler-Straße 48\n", "67663 Kaiserslautern\n", "Germany" ), Place := "Kaiserslautern, Germany", Institution := "RPTU Kaiserslautern-Landau" ), # Contributors: rec( LastName := "Barakat", FirstNames := "Mohamed", IsAuthor := false, IsMaintainer := false, ), rec( LastName := "Pfeiffer", FirstNames := "Markus", IsAuthor := false, IsMaintainer := false, ), rec( LastName := "Skartsæterhagen", FirstNames := "Øystein", IsAuthor := false, IsMaintainer := false, ), rec( LastName := "Wensley", FirstNames := "Chris", IsAuthor := false, IsMaintainer := false, ), rec( LastName := "Whitney", FirstNames := "Glen", IsAuthor := false, IsMaintainer := false, ), rec( LastName := "Zickgraf", FirstNames := "Fabian", IsAuthor := false, IsMaintainer := false, ), ], Status := "deposited", PackageWWWHome := "https://gap-packages.github.io/AutoDoc/", SourceRepository := rec( Type := "git", URL := Concatenation( "https://github.com/gap-packages/", ~.PackageName ), ), IssueTrackerURL := Concatenation( ~.SourceRepository.URL, "/issues" ), PackageWWWHome := Concatenation( "https://gap-packages.github.io/", ~.PackageName ), README_URL := Concatenation( ~.PackageWWWHome, "/README.md" ), PackageInfoURL := Concatenation( ~.PackageWWWHome, "/PackageInfo.g" ), ArchiveURL := Concatenation( ~.SourceRepository.URL, "/releases/download/v", ~.Version, "/", ~.PackageName, "-", ~.Version ), ArchiveFormats := ".tar.gz", AbstractHTML := "", PackageDoc := rec( BookName := "AutoDoc", ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0_mj.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := "Generate documentation from GAP source code", ), Dependencies := rec( GAP := ">= 4.5", NeededOtherPackages := [ [ "GAPDoc", ">= 1.6.3" ] ], SuggestedOtherPackages := [ ], ExternalConditions := [], ), AvailabilityTest := ReturnTrue, TestFile := "tst/testall.g", Keywords := [ "Automatic documentation, GAP, GAPDoc" ], AutoDoc := rec( entities := rec( VERSION := ~.Version, DATE := ~.Date, io := "io", PackageName := "PackageName", ), TitlePage := rec( Copyright := Concatenation( "©right; 2012-2022 by Sebastian Gutsche and Max Horn

\n\n", "This package may be distributed under the terms and conditions ", "of the GNU Public License Version 2 or (at your option) any later version.\n" ), Abstract := Concatenation( "&AutoDoc; is a ⪆ package whose purpose is to aid ", "⪆ package authors in creating and maintaining the ", "documentation of their packages.\n" ), Acknowledgements := Concatenation( "This documentation was prepared using the ", "&GAPDoc; package .\n", "

\n" ), ), ), )); AutoDoc-2023.06.19/LICENSE000644 000766 000024 00000036463 14444021247 014766 0ustar00mhornstaff000000 000000 The AutoDoc package is free software; you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The AutoDoc package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Version 2 of the GNU General Public License follows. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS AutoDoc-2023.06.19/makefile000644 000766 000024 00000000245 14444021247 015446 0ustar00mhornstaff000000 000000 all: doc doc: doc/manual.six doc/manual.six: makedoc.g PackageInfo.g doc/*.xml gap/*.gd gap/*.gi gap makedoc.g clean: (cd doc ; ./clean) .PHONY: all doc clean AutoDoc-2023.06.19/CHANGES000644 000766 000024 00000017765 14444021247 014760 0ustar00mhornstaff000000 000000 This file describes changes in the AutoDoc package. 2023.06.19 - Revise handling of chunks XML file - Remove `AUTODOC_AbsolutePath` - Don't build PDF docs if `NOPDF` environment variable is set - Various janitorial changes 2022.10.20 - Prevent some file descriptor leaks - Do not try to read non-existing file gap/ContextObject.gd 2022.07.10 - Output all entities defined via either the `scaffold.entities` option to AutoDoc (or equivalently via the `AutoDoc.entities` record in `PackageInfo.g`) into a file `_entities.xml`, so that they can also be used with a hand-made main XML file (and not just when AutoDoc generated the main page) - Remove `&see;` entity from the default list of entities 2022.03.10 - Strip trailing newlines in PostalAddress and some TitlePage elements - Allow AutoDoc record in PackageInfo.g to not contain a TitlePage entry 2022.02.24 - true/false are keywords, not just code: use K tags - extract examples: do not flush pkgname.tst - remove duplicate entries in autodoc.files 2020.08.11 - Add support for using the string `]]>` in examples - Add support for `DeclareGlobalName` (new in GAP 4.12) - Add extract_examples.skip_empty_in_numbering option - Enhance extract_examples to remove outdated .tst files (e.g. if chapter number changes, we won't leave outdated extracted .tst examples behind) - Fix a warning about a missing file `/doc/_Chunks.xml` which appeared when building the documentation of some packages 2019.09.04 - Deprecate @BeginAutoDoc and @EndAutoDoc; they will be removed in a future AutoDoc version - Deprecate @BeginAutoDocPlainText and @EndAutoDocPlainText; they will be removed in a future AutoDoc version - Fix @BeginCode / @EndCode / @InsertCode, which were broken in version 2019.07.03 2019.07.24 - Add support for ISO 8601 dates in package metadata (to prepare for GAP adding official support for this in the future) - Remove undocumented and long-unused support entities specified using a raw `` entity string - Fix the &see; entity we always generate (for legacy support) to display the correct output in LaTeX / PDF mode - Fix support for chunks with names / labels that contain spaces (GAPDoc does not like these, so we replace the spaces by underscores) 2019.07.17 - Fix bug in extract_examples option that could result in invalid .tst files 2019.07.03 - Make Chunks compatible with GAPDoc chunks - Tweak two error messages, add two more error checks - Check that gapdoc.files is a list of strings - Add @GroupTitle command (thanks to Glen Whitney) - Make @Begin.../@EndExampleSession respect plain_text_mode (thanks to Glen Whitney) - Handle documentation of DeclareCategoryCollection declarations (thanks to Glen Whitney) - Repair minor omissions/imprecisions in AutoDoc() function doc (thanks to Glen Whitney) - Improve manual further 2019.05.20 - Ensure that starting a "manpage" (= documentation for a filter, function, property, ...) ends any active subsection (in GAPDoc, manpages are equivalent to subsections internally, and hence cannot be nested in each other) - Add deprecation warnings for @InsertSystem, @System, @BeginSystem, @EndSystem (use @Chunk etc. instead), and also @EndSection, @EndSubsection - Rename scaffold.gapdoc_latex_options to gapdoc.LaTeXOptions. The old name is still supported, but triggers a deprecation warning. - Update copyright information and author's contact data - Minor fixes in the manual 2019.04.10 - Add opt.extract_examples to AutoDoc function - Add @NotLatex command to complement @LatexOnly - Allow disabling title page creation, by teaching `AutoDoc()` to correctly handle `scaffold := rec( TitlePage := false )` instead of raising an error - When generating a manual title page, only include persons as authors for which IsAuthor is set to true in PackageInfo.g - Some improvements to the manual - Various internal changes 2019.02.22 - Updated changes file 2019.02.21 - Removed possibility to mark function arguments via curly braces, as {A}, as it caused problems with writing {} in math mode. 2019.02.20 - Accept single backticks to indicate inline code spans - Added possibility to mark function arguments via curly braces, as {A} 2018.09.20 - Scan bracket `\[\]` declarations correctly (PR #162) - Removed the hardcoded utf8 option, make it overridable via gapdoc_latex_option - Allow AutoDoc() to take absolute dirs and run from any dir (thanks to Glen Whitney) - Add a test suite for AutoDoc (thanks to Glen Whitney) - Fix documenting DeclareInfoClass 2018.02.14 - Added @*Title commands to specify titles for Chapters etc. - Document @BeginExampleSession instead of @ExampleSession - Document the aliases @Example, @ExampleSession, @Log, and @LogSession - Improve manual (thanks to Chris Wensley): - fix a few typos - added abstract and acknowledgments - added bibliography file AutoDoc.bib - added checklist subsection 1.3.3 - added some index entries - change makedoc.g to highlight some useful features of the AutoDoc() function - Various other tweaks and fixes 2017.09.08 - Add ChapterLabel, SectionLabel, and SubsectionLabel - Add ExampleSession environment to support GAPDoc-Style examples - Add support for documenting DeclareConstructor - Empty lines in AutoDoc comments start a new paragraph, as in TeX - Improve @Example documentation - Fix some spelling mistakes in the manual - Fix support for KeyDependendOperations (see issue #124) - Don't show a return value if no @Returns is given - Various other tweaks and fixes 2016.12.04: - Revise and officially document the `entities` option for AutoDoc() 2016.11.26: - Use english month names on title pages - Ignore empty dependency lists in PackageInfo.g files - Better error message when .six file is not available 2016.03.08: - Fix the "empty index" workaround from the previous release 2016.03.04: - Improved the manual. - AutoDoc can now be instructed to invoke GAPDoc in such a way that links in the generated documentation to the GAP reference manual use relative paths. - Also scan for .autodoc files (Issue #104) - Workaround a problem with GAPDoc where an empty index could lead to an error. - Allow entities in chapter and section titles. - Fix a bug where the indentation for code blocks was not preserved. 2016.02.24: - Again improved the error messages produced by the parser. - Document worksheets (and fix them -- the previous release broke them). - Removed the @URL documentation comment command. - Add current directory to default list of directories which are scanned for *.{g,gi,gd} files containing documentation. - Fixed various typos and other mistakes in the documentation. - Make it possible to tell AutoDoc to build manuals with relative paths (issue #103). 2016.02.16: - AutoDoc does not anymore produce an error when invoked on a new project which has no documentation yet (issue #65) - Various errors in the parser now produce much better error messages, with information in which file and line the error occurred, and what the error is (issue #89) - Files generated by AutoDoc for chapters as well as the "main" file now have names starting with an underscore, to make it easy to distinguish generated files from those maintained by hand. - Removed the old "Declare*WithDoc" API. Any packages still using it must upgrade to use documentation comments. 2016.01.31: - Improved the documentation of AutoDoc itself - Some code is now more robust, detects more error conditions and reports them clearly to the user, instead of triggering some weird error later on. - Lots of minor tweaks, fixes and cleanip 2016-01-21: - The AutoDoc() function now accepts IsDirectory() objects as first argument, and you can omit the first argument (it then defaults to the current directory). Packages using AutoDoc may want to adapt their makedoc.g to use this new facility for improved robustness. AutoDoc-2023.06.19/TODO000644 000766 000024 00000002562 14444021247 014442 0ustar00mhornstaff000000 000000 todo: Please create a (maybe random) test suite for invoking the AutoDoc command. We already have a nice testsuite for all comments possible, although Mohamed always seems to find a way to crash them into void. IDEAS: We need to collect all possible combinations to invoke the AutoDoc command. It should be no problem to design a loop in GAP, but checking the output for differences might be painful. Also, what to do with entities? The following is a list of possible valid inputs for the different option records, which might produce the desired output in all combinations. However, Murphys Law tells us that at least one of them will break anyway. So good luck. dir: * doc * nothing -> Both should produce the same output. scaffold: * includes * appendix * bib * TitlePage: + ... Stuff, see GAPDoc. * document_class * latex_header_file * gapdoc_latex_options Documenting C/C++/C# with AutoDoc: Use comments of C/C++/C# before AutoDoc hashes, i.e. // #!. You can also begin a whole comment section with /* and then end it with */. Please don't put a AutoDoc hash in the same line as /* and */. If using the @AutoDocPlainText command, you can get rid of the supersticious hashes. Please do *NOT* use the comment syntax with an asterisk at the beginning of every line, it will mess up the markdown extension! AutoDoc-2023.06.19/README.md000644 000766 000024 00000002561 14444021247 015230 0ustar00mhornstaff000000 000000 [![Build Status](https://github.com/gap-packages/AutoDoc/workflows/CI/badge.svg?branch=master)](https://github.com/gap-packages/AutoDoc/actions?query=workflow%3ACI+branch%3Amaster) [![Code Coverage](https://codecov.io/github/gap-packages/AutoDoc/coverage.svg?branch=master&token=)](https://codecov.io/gh/gap-packages/AutoDoc) # AutoDoc: A GAP package to help creating a GAPDoc documentation. AutoDoc is a package for the [GAP](https://www.gap-system.org) computer algebra system. It is meant to simplify the creation of reference manuals for GAP packages. It makes it possible to create documentation from source code comments, without writing XML files. It is not a substitute for GAPDoc, but rather builds on GAPDoc, by generating XML input for the latter. As such, you can combine an existing GAPDoc manual with AutoDoc. ## Using AutoDoc Please consult the AutoDoc manual for information on how to use it. It is accessible via the builtin help system of GAP. In addition you can find the manual for the latest AutoDoc version online at ## Support Bug reports and other feedback are welcome. The latest version of this package can be found at ## Copyright and licensing Please consult the LICENSE and COPYRIGHT file you should have received as part of this package for details. AutoDoc-2023.06.19/gap/000755 000766 000024 00000000000 14444021247 014514 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/makedoc.g000644 000766 000024 00000001074 14444021247 015522 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later LoadPackage("AutoDoc"); AutoDoc( rec( autodoc := true, gapdoc := rec( LaTeXOptions := rec( EarlyExtraPreamble := """ \usepackage{a4wide} \newcommand{\bbZ}{\mathbb{Z}} """ ) ), scaffold := rec( includes := [ "Tutorials.xml", "Comments.xml" ], bib := "bib.xml", ) )); AutoDoc-2023.06.19/doc/000755 000766 000024 00000000000 14444021302 014502 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/COPYRIGHT000644 000766 000024 00000002253 14444021247 015242 0ustar00mhornstaff000000 000000 AutoDoc: A GAP interface to Singular. AutoDoc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. AutoDoc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with AutoDoc; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Copyright (C) 2012-2019 by its authors and contributors: Authors: * Max Horn * Sebastian Gutsche Contributors: * Chris Wensley * Fabian Zickgraf * Glen Whitney * Jerry James * Markus Pfeiffer * Mohamed Barakat * Øystein Skartsæterhagen AutoDoc-2023.06.19/tst/000755 000766 000024 00000000000 14444021247 014557 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/init.g000644 000766 000024 00000000763 14444021247 015066 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ReadPackage( "AutoDoc", "gap/DocumentationTree.gd" ); ReadPackage( "AutoDoc", "gap/Parser.gd" ); ReadPackage( "AutoDoc", "gap/AutoDocMainFunction.gd" ); ReadPackage( "AutoDoc", "gap/ToolFunctions.gd" ); ReadPackage( "AutoDoc", "gap/Magic.gd" ); ReadPackage( "AutoDoc", "gap/Markdown.gd" ); AutoDoc-2023.06.19/read.g000644 000766 000024 00000000763 14444021247 015036 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ReadPackage( "AutoDoc", "gap/ToolFunctions.gi" ); ReadPackage( "AutoDoc", "gap/DocumentationTree.gi" ); ReadPackage( "AutoDoc", "gap/Parser.gi" ); ReadPackage( "AutoDoc", "gap/AutoDocMainFunction.gi" ); ReadPackage( "AutoDoc", "gap/Magic.gi" ); ReadPackage( "AutoDoc", "gap/Markdown.gi" ); AutoDoc-2023.06.19/tst/worksheets/000755 000766 000024 00000000000 14444021247 016755 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/dogfood.tst000644 000766 000024 00000003516 14444021247 016741 0ustar00mhornstaff000000 000000 ############################################################################# ## ## AutoDoc package ## ## Test the behavior of AutoDoc by generating its own manual ## ## Copyright 2018 ## Contributed by Glen Whitney, studioinfinity.org ## ## Licensed under the GPL 2 or later. ## ############################################################################# gap> START_TEST( "dogfood.tst" ); # need IO package for ChangeDirectoryCurrent gap> LoadPackage("io", false); true # temporarily change info levels to suppress all GAPDoc output gap> oldGAPDocLevel := InfoLevel( InfoGAPDoc );; gap> oldWarningLevel := InfoLevel( InfoWarning );; gap> SetInfoLevel( InfoGAPDoc, 0 ); gap> SetInfoLevel( InfoWarning, 0 ); # change into the package directory gap> olddir := AUTODOC_CurrentDirectory();; gap> pkgdir := DirectoriesPackageLibrary( "AutoDoc", "");; gap> ChangeDirectoryCurrent(Filename(pkgdir, "")); true # regenerate the manual using AutoDoc gap> Read("makedoc.g"); # restore info levels and current directory gap> SetInfoLevel( InfoGAPDoc, oldGAPDocLevel ); gap> SetInfoLevel( InfoWarning, oldWarningLevel ); gap> ChangeDirectoryCurrent(olddir); true # prepare to compare the output to the reference output # No point in testing chapters 1 or 2 unless/until they are converted to autodoc gap> docdir := DirectoriesPackageLibrary( "AutoDoc", "doc" );; gap> ex_dir := DirectoriesPackageLibrary( "AutoDoc", "tst/manual.expected" );; # check chapter 3 gap> chap3 := Filename( docdir, "_Chapter_AutoDoc_worksheets.xml" );; gap> chap3ref := Filename( ex_dir, "_Chapter_AutoDoc_worksheets.xml" );; gap> AUTODOC_Diff("-u", chap3ref, chap3); 0 # check chapter 4 gap> chap4 := Filename( docdir, "_Chapter_AutoDoc.xml" );; gap> chap4ref := Filename( ex_dir, "_Chapter_AutoDoc.xml" );; gap> AUTODOC_Diff("-u", chap4ref, chap4); 0 # gap> STOP_TEST( "dogfood.tst" ); AutoDoc-2023.06.19/tst/misc.tst000644 000766 000024 00000002314 14444021247 016246 0ustar00mhornstaff000000 000000 # # test miscellaneous stuff # gap> START_TEST( "misc.tst" ); # AUTODOC_SetIfMissing gap> r:=rec(); rec( ) gap> AUTODOC_SetIfMissing(r, "foo", 1); gap> r; rec( foo := 1 ) gap> AUTODOC_SetIfMissing(r, "foo", 2); gap> r; rec( foo := 1 ) # # AUTODOC_FormatDate # # gap> AUTODOC_FormatDate(2019); "2019" gap> AUTODOC_FormatDate(2019, 3); "March 2019" gap> AUTODOC_FormatDate(2019, 3, 1); "1 March 2019" gap> AUTODOC_FormatDate("2019", "3", "1"); "1 March 2019" gap> AUTODOC_FormatDate(rec(year:=2019)); "2019" gap> AUTODOC_FormatDate(rec(year:=2019, month:=3)); "March 2019" gap> AUTODOC_FormatDate(rec(year:=2019, month:=3, day:=1)); "1 March 2019" gap> AUTODOC_FormatDate(rec(year:="2019", month:="3", day:="1")); "1 March 2019" # error handling gap> AUTODOC_FormatDate(); Error, Invalid arguments gap> AUTODOC_FormatDate(2019, 3, 40); Error, must be an integer in the range [1..31], or a string representing\ such an integer gap> AUTODOC_FormatDate(2019, 13, 1); Error, must be an integer in the range [1..12], or a string representi\ ng such an integer gap> AUTODOC_FormatDate(fail, 3, 1); Error, must be an integer >= 2000, or a string representing such an int\ eger # gap> STOP_TEST( "misc.tst" ); AutoDoc-2023.06.19/tst/manual.expected/000755 000766 000024 00000000000 14444021247 017634 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets.tst000644 000766 000024 00000000637 14444021247 017517 0ustar00mhornstaff000000 000000 # # test worksheets # gap> START_TEST( "worksheets.tst" ); # gap> AUTODOC_TestWorkSheet("general"); Extracting manual examples for General Test package ... 1 chapters detected Chapter 1 : extracted 2 examples # gap> AUTODOC_TestWorkSheet("autoplain"); Extracting manual examples for Plain file.autodoc Test package ... 1 chapters detected Chapter 1 : extracted 2 examples # # gap> STOP_TEST( "worksheets.tst" ); AutoDoc-2023.06.19/tst/testall.g000644 000766 000024 00000000202 14444021247 016371 0ustar00mhornstaff000000 000000 LoadPackage( "AutoDoc" ); TestDirectory( DirectoriesPackageLibrary("AutoDoc", "tst"), rec(exitGAP := true ) ); FORCE_QUIT_GAP(1); AutoDoc-2023.06.19/tst/manual.expected/_AutoDocMainFile.xml000644 000766 000024 00000000267 14444021247 023465 0ustar00mhornstaff000000 000000 <#Include SYSTEM "_Chapter_AutoDoc_worksheets.xml"> <#Include SYSTEM "_Chapter_AutoDoc.xml"> AutoDoc-2023.06.19/tst/manual.expected/_Chunks.xml000644 000766 000024 00000000000 14444021247 021736 0ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/manual.expected/_Chapter_AutoDoc.xml000644 000766 000024 00000042763 14444021247 023535 0ustar00mhornstaff000000 000000 AutoDoc

The AutoDoc() function nothing This is the main function of the &AutoDoc; package. It can perform any combination of the following tasks: It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in &GAPDoc; format to be used as part of your manual: First, a file named doc/PACKAGENAME.xml (with your package's name substituted) which is used as main XML file for the package manual, i.e. this file sets the XML doctype and defines various XML entities, includes other XML files (both those generated by &AutoDoc; as well as additional files created by other means), tells &GAPDoc; to generate a table of contents and an index, and more. Secondly, it creates a file doc/title.xml containing a title page for your documentation, with information about your package (name, description, version), its authors and more, based on the data in your PackageInfo.g. It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; tags and the Autodoc command. This will produce further XML files to be used as part of the package manual. It can use &GAPDoc; to generate PDF, text and HTML (with MathJaX enabled) documentation from the &GAPDoc; XML files it generated as well as additional such files provided by you. For this, it invokes to convert the XML sources, and it also instructs &GAPDoc; to copy supplementary files (such as CSS style files) into your doc directory (see ). For more information and some examples, please refer to Chapter .

The parameters have the following meanings: packageOrDirectory The purpose of this parameter is twofold: to determine the package directory in which &AutoDoc; will operate, and to find the metadata concerning the package being documented. The parameter is either a string, an IsDirectory object, or omitted. If it is a string, &AutoDoc; interprets it as the name of a package, uses the metadata of the first package known to &GAP; with that name, and uses the InstallationPath specified in that metadata as the package directory. If packageOrDirectory is an IsDirectory object, this is used as package directory; if the argument is omitted, then the current directory is used. In the last two cases, the specified directory must contain a PackageInfo.g file, and &AutoDoc; extracts all needed metadata from that. The IsDirectory form is for example useful if you have multiple versions of the package around and want to make sure the documentation of the correct version is built.

Note that when using AutoDocWorksheet (see ), there is no parameter corresponding to packageOrDirectory and so the package directory is always the current directory, and there is no metadata. optrec optrec can be a record with some additional options. The following are currently supported: dir This should either be a string, in which case it must be a path relative to the specified package directory, or a Directory() object. (Thus, the only way to designate an absolute directory is with a Directory() object.) This option specifies where the package documentation (e.g. the &GAPDoc; XML or the manual PDF, etc.) files are stored and/or will be generated.
Default value: "doc/".
scaffold This controls whether and how to generate scaffold XML files for the package documentation.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.scaffold is missing but the package's info record in PackageInfo.g has an AutoDoc entry. In all other cases (in particular if opt.scaffold is false), scaffolding is disabled.

If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings.

If opt.scaffold is a record, it may contain the following entries.

includes A list of XML files to be included in the body of the main XML file. If you specify this list and also are using &AutoDoc; to document your operations with &AutoDoc; comments, you can add _AutoDocMainFile.xml to this list to control at which point the documentation produced by &AutoDoc; is inserted. If you do not do this, it will be added after the last of your own XML files. index By default, the scaffold creates an index. If you do not want an index, set this to false. appendix This entry is similar to opt.scaffold.includes but is used to specify files to include after the main body of the manual, i.e. typically appendices. bib The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file doc/PACKAGENAME.bib then it is assumed that you want to use this as your bibliography. entities A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record SomePackage,

SomePackage", RELEASEYEAR := "2015" )]]> then the following entity definitions are added to the XML preamble: SomePackage'> ]]> This allows you to write &SomePackage; and &RELEASEYEAR; in your documentation, which will be replaced by respective values specified in the entities definition. TitlePage A record whose entries are used to embellish the generated title page for the package manual with extra information, such as a copyright statement or acknowledgments. To this end, the names of the record components are used as XML element names, and the values of the components are outputted as content of these XML elements. For example, you could pass the following record to set a custom acknowledgements text: For a list of valid entries in the title page, please refer to the &GAPDoc; manual, specifically section . MainPage If scaffolding is enabled, by default a main XML file is generated (this is the file which contains the XML doctype and more). If you do not want this (e.g. because you have a handwritten main XML file), but still want &AutoDoc; to generate a title page for you, you can set this option to false document_class Sets the document class of the resulting PDF. The value can either be a string which has to be the name of the new document class, a list containing this string, or a list of two strings. Then the first one has to be the document class name, the second one the option string ( contained in [ ] ) in &LaTeX;. latex_header_file Replaces the standard header from &GAPDoc; completely with the header in this &LaTeX; file. Please be careful here, and look at &GAPDoc;'s latexheader.tex file for an example. autodoc This controls whether and how to generate additional XML documentation files by scanning for &AutoDoc; documentation comments.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.autodoc is missing but the package depends (directly) on the &AutoDoc; package. In all other cases (in particular if opt.autodoc is false), this feature is disabled.

If opt.autodoc is a record, it may contain the following entries.

files A list of files (given by paths relative to the package directory) to be scanned for &AutoDoc; documentation comments. Usually it is more convenient to use autodoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for &AutoDoc; documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].
level This defines the level of the created documentation. The default value is 0. When parts of the manual are declared with a higher value they will not be printed into the manual.
gapdoc This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text files from your various XML files.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.gapdoc is missing. In all other cases (in particular if opt.gapdoc is false), this feature is disabled.

If opt.gapdoc is a record, it may contain the following entries.

main The name of the main XML file of the package manual. This exists primarily to support packages with existing manual which use a filename here which differs from the default. In particular, specifying this is unnecessary when using scaffolding.
Default value: PACKAGENAME.xml.
files A list of files (given by paths relative to the package directory) to be scanned for &GAPDoc; documentation comments. Usually it is more convenient to use gapdoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans for .gi, .gd and .g files; all of these files are then scanned for &GAPDoc; documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].
LaTeXOptions Must be a record with entries which can be understood by . Each entry can be a string, which will be given to &GAPDoc; directly, or a list containing of two entries: The first one must be the string "file", the second one a filename. This file will be read and then its content is passed to &GAPDoc; as option with the name of the entry. gap_root_relative_path Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to false), references in the generated documentation referring to external documentation (such as the &GAP; manual) are encoded using absolute paths. This is fine as long as the documentation stays on only a single computer, but is problematic when preparing documentation that should be used on multiple computers, e.g., when creating a distribution archive of a &GAP; package.
Thus, if a relative path is provided via this option (or if it is set to true, in which case the relative path ../../.. is used), then &AutoDoc; and &GAPDoc; attempt to replace all absolute paths in references to &GAP; manuals by paths based on this relative path.

On a technical level, &AutoDoc; passes the relative path to the gaproot parameter of

extract_examples Either true or a record. If set to true, then all manual examples are extracted and placed into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... and so on, with one file for each chapter. For chapters with no examples, no file is created.

As a record, the entry can have the following entries itself, to specify some options. units This controls how examples are grouped into files. Recognized values are "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, one file is created for each chapter, each section, each subsection or each example. For all other values only a single file is created.

On a technical level, &AutoDoc; passes the value to the units parameter of . skip_empty_in_numbering If set to true (the default), the generated files use filenames with strictly sequential numbering; that means that if chapter 1 (or whatever units are being used) contains no examples but chapter 2 does, then the examples for chapter 2 are put into the file tst/PACKAGENAME01.tst. If this option is set to false, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file tst/PACKAGENAME02.tst. maketest This option is deprecated. Please use extract_examples instead.

Either true or a record. When it is true, a simple maketest.g file is created in the main package directory, which can be used to test the examples from the manual. As a record, the entry can have the following entries itself, to specify some options. filename Sets the name of the test file. commands A list of strings, each one a command, which will be executed at the beginning of the test file.

Examples

Some basic examples for using AutoDoc were already shown in Chapter .

AutoDoc-2023.06.19/tst/manual.expected/_Chapter_AutoDoc_worksheets.xml000644 000766 000024 00000001643 14444021247 026003 0ustar00mhornstaff000000 000000 AutoDoc worksheets
Worksheets The intention of these function is to create stand-alone pdf and html files using AutoDoc without having them associated to a package. It uses the same optional records as the &AutoDoc; command itself, but instead of a package name there should be a filename or a list of filenames containing AutoDoc text from which the documents are created. Please see the &AutoDoc; command for more information about this and have a look at for a simple worksheet example.
AutoDoc-2023.06.19/tst/worksheets/general.sheet/000755 000766 000024 00000000000 14444021247 021501 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/000755 000766 000024 00000000000 14444021247 022551 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/general.expected/000755 000766 000024 00000000000 14444021247 022172 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/update.sh000755 000766 000024 00000000504 14444021247 020575 0ustar00mhornstaff000000 000000 #!/bin/sh # This script copies actual files over to the expected files; # this is useful when adding new tests. for actual in *.actual ; do expected="$(basename $actual .actual).expected" rm -rf $expected mkdir $expected cp $actual/*.xml $expected/ mkdir $expected/tst cp $actual/tst/*.tst $expected/tst/ done AutoDoc-2023.06.19/tst/worksheets/autoplain.sheet/000755 000766 000024 00000000000 14444021247 022060 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/autoplain.sheet/plain.autodoc000644 000766 000024 00000000740 14444021247 024544 0ustar00mhornstaff000000 000000 @Title Plain file.autodoc Test @Date 2018-08-30 @Chapter Test Does AutoDoc have a way to allow that header block not to appear in the documentation generated from a .autodoc file like this? @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession Some text between two examples @BeginExampleSession gap> A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 @EndExampleSession And we wrap up with some dummy text AutoDoc-2023.06.19/tst/worksheets/general.expected/_entities.xml000644 000766 000024 00000000071 14444021247 024675 0ustar00mhornstaff000000 000000 General_Test'> AutoDoc-2023.06.19/tst/worksheets/general.expected/General_Test.xml000644 000766 000024 00000000466 14444021247 025276 0ustar00mhornstaff000000 000000 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2023.06.19/tst/worksheets/general.expected/_AutoDocMainFile.xml000644 000766 000024 00000000207 14444021247 026015 0ustar00mhornstaff000000 000000 <#Include SYSTEM "_Chapter_SomeChapter.xml"> AutoDoc-2023.06.19/tst/worksheets/general.expected/title.xml000644 000766 000024 00000000300 14444021247 024026 0ustar00mhornstaff000000 000000 General Test 30 August 2018 AutoDoc-2023.06.19/tst/worksheets/general.expected/_Chunks.xml000644 000766 000024 00000000423 14444021247 024305 0ustar00mhornstaff000000 000000 <#GAPDoc Label="MyChunk"> Hello, world. This line is indented! <#/GAPDoc> <#GAPDoc Label="MyCode"> 2"); fi; ]]> <#/GAPDoc> AutoDoc-2023.06.19/tst/worksheets/general.expected/_Chapter_SomeChapter.xml000644 000766 000024 00000013111 14444021247 026730 0ustar00mhornstaff000000 000000 SomeChapter This is dummy text S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 ]]> Some text between two examples A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 gap> # Test whether ]]]]> can be used safely gap> [[2]]]]>[[1]]; true ]]> And we wrap up with some dummy text
Some categories Intro text true or false

true or false

true or false

Let's wrap up with something, though.

SomeSection Some test just inside a section. SomeSubsection This is a subsection! MarkDown support

We can use test some markdown features here: This is a list item. This is a subitem We can also use math mode here: a^2+b^2=c^2. This is emphasized text in a list item. This is also emphasized text in a list item. This is inline code in a list item.

All of this can also be used outside of a list.

Testing various kinds of documentation true or false A category true or false A collection category over the category we just created; A collection category over the category we just created; A collection category over the category we just created; A representation An attribute true or false A property An operation A cConstructor A global function A global variable A global name A filter An info class A key dependent operation
Testing the group commands A family of operations First sentence. Second sentence. Third sentence.
Testing chunks This test comes after the chunk is declared, but before it is inserted. <#Include Label="MyChunk"> The text "Hello, world." is inserted right before this.
Testing code chunks This test comes after the code chunk is declared, but before it is inserted. <#Include Label="MyCode"> The text "Hello, world." is inserted right before this.
AutoDoc-2023.06.19/tst/worksheets/general.expected/tst/000755 000766 000024 00000000000 14444021247 023004 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/general.expected/tst/general_test01.tst000644 000766 000024 00000001415 14444021247 026356 0ustar00mhornstaff000000 000000 # General Test, chapter 1 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been generated by AutoDoc. It contains examples extracted from # the package documentation. Each example is preceded by a comment which gives # the name of a GAPDoc XML file and a line range from which the example were # taken. Note that the XML file in turn may have been generated by AutoDoc # from some other input. # gap> START_TEST("general_test01.tst"); # _Chapter_SomeChapter.xml:8-13 gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 # _Chapter_SomeChapter.xml:17-25 gap> A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 gap> # Test whether ]]> can be used safely gap> [[2]]>[[1]]; true # gap> STOP_TEST("general_test01.tst", 1); AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/_entities.xml000644 000766 000024 00000000117 14444021247 025255 0ustar00mhornstaff000000 000000 Plain_file.autodoc_Test'> AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/_AutoDocMainFile.xml000644 000766 000024 00000000200 14444021247 026365 0ustar00mhornstaff000000 000000 <#Include SYSTEM "_Chapter_Test.xml"> AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/title.xml000644 000766 000024 00000000313 14444021247 024411 0ustar00mhornstaff000000 000000 Plain file.autodoc Test 30 August 2018 AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/_Chunks.xml000644 000766 000024 00000000000 14444021247 024653 0ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/_Chapter_Test.xml000644 000766 000024 00000001065 14444021247 026021 0ustar00mhornstaff000000 000000 Test Does AutoDoc have a way to allow that header block not to appear in the documentation generated from a .autodoc file like this? S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 ]]> Some text between two examples A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 ]]> And we wrap up with some dummy text AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/Plain_file.autodoc_Test.xml000644 000766 000024 00000000501 14444021247 027765 0ustar00mhornstaff000000 000000 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/tst/000755 000766 000024 00000000000 14444021247 023363 5ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/tst/worksheets/autoplain.expected/tst/plain_file.autodoc_test01.tst000644 000766 000024 00000001336 14444021247 031061 0ustar00mhornstaff000000 000000 # Plain file.autodoc Test, chapter 1 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been generated by AutoDoc. It contains examples extracted from # the package documentation. Each example is preceded by a comment which gives # the name of a GAPDoc XML file and a line range from which the example were # taken. Note that the XML file in turn may have been generated by AutoDoc # from some other input. # gap> START_TEST("plain_file.autodoc_test01.tst"); # _Chapter_Test.xml:9-14 gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 # _Chapter_Test.xml:18-23 gap> A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 # gap> STOP_TEST("plain_file.autodoc_test01.tst", 1); AutoDoc-2023.06.19/tst/worksheets/general.sheet/worksheet.g000644 000766 000024 00000011733 14444021247 023671 0ustar00mhornstaff000000 000000 ############################################################################# ## ## AutoDoc package ## ############################################################################# Print( "Pretend this is a code file.\n" ); Print( "(Even though we never use it that way.\n" ); #! @Title General Test #! @Date 30/08/2018 #! @Chapter SomeChapter #! This is dummy text #! @BeginExampleSession #! gap> S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) #! gap> Size(S5); #! 120 #! @EndExampleSession #! Some text between two examples #! @BeginExampleSession #! gap> A5 := AlternatingGroup(5); #! Alt( [ 1 .. 5 ] ) #! gap> Size(A5); #! 60 #! gap> # Test whether ]]> can be used safely #! gap> [[2]]>[[1]]; #! true #! @EndExampleSession #! And we wrap up with some dummy text ############################################################################# #! @Section Some categories #! Intro text DeclareCategory("MyThings", IsObject); DeclareCategoryCollections("MyThings"); DeclareCategoryCollections("MyThingsCollection"); # Now here is some text with a bunch of &!$%*!/ weird things in it. But that # should be OK, nothing should end up in a weird place. #! Let's wrap up with something, though. ############################################################################# #! @Section SomeSection #! Some test just inside a section. #! @Subsection SomeSubsection #! This is a subsection! #! @Subsection MarkDown support #! #! We can use test some markdown features here: #! * This is a list item. #! * This is a subitem #! * We can also use math mode here: $a^2+b^2=c^2$. #! * This is __emphasized__ text in a list item. #! * This is also **emphasized** text in a list item. #! * This is `inline code` in a list item. #! #! All of this can **also** be __used__ outside of a `list`. #! @LatexOnly This text will only appear in the \LaTeX version. #! @BeginLatexOnly #! This text will only appear in the \LaTeX version, too. #! @EndLatexOnly #! @NotLatex This text will only appear in the HTML version and the text version. #! @BeginNotLatex #! This text will only appear in the HTML version and the text version, too. #! @EndNotLatex ############################################################################# #! @Section Testing various kinds of documentation #! @Description #! A category DeclareCategory( "SomeCategory", IsObject ); #! @Description #! A collection category over the category we just created; # will appear as SomeCategoryCollection DeclareCategoryCollections( "SomeCategory" ); #! @Description #! A collection category over the category we just created; # will appear as SomeCategoryCollColl DeclareCategoryCollections( "SomeCategoryCollection" ); #! @Description #! A collection category over the category we just created; # will appear as SomeCategoryCollCollColl DeclareCategoryCollections( "SomeCategoryCollColl" ); #! @Description #! A representation DeclareRepresentation( "SomeRepresentation", IsAttributeStoringRep, [] ); #! @Description #! An attribute DeclareAttribute( "SomeAttribute", IsGroup ); #! @Description #! A property DeclareProperty( "SomeProperty", IsGroup ); #! @Description #! An operation DeclareOperation( "SomeOperation", [ IsInt, IsGroup ] ); #! @Description #! A cConstructor DeclareConstructor( "SomeConstructor", [ IsGroup, IsInt ] ); #! @Description #! A global function DeclareGlobalFunction( "SomeGlobalFunction" ); #! @Description #! A global variable DeclareGlobalVariable( "SomeGlobalVariable" ); #! @Description #! A global name DeclareGlobalName( "SomeGlobalName" ); #! @Description #! A filter DeclareFilter( "SomeFilter" ); #! @Description #! An info class DeclareInfoClass( "SomeInfoClass"); #! @Description #! A key dependent operation KeyDependentOperation( "SomeKeyDependentOperation", IsGroup, IsInt, "prime" ); ############################################################################# #! @Section Testing the group commands #! @BeginGroup Group1 #! @GroupTitle A family of operations #! @Description #! First sentence. DeclareOperation( "FirstOperation", [ IsInt ] ); #! @Description #! Second sentence. DeclareOperation( "SecondOperation", [ IsInt, IsGroup ] ); #! @EndGroup ## .. Stuff .. #! @Description #! Third sentence. #! @Group Group1 DeclareOperation( "ThirdOperation", [ IsGroup, IsInt ] ); ############################################################################# #! @Section Testing chunks #! @BeginChunk MyChunk #! Hello, world. #! This line is indented! #! @EndChunk #! This test comes after the chunk is declared, but before it is inserted. #! @InsertChunk MyChunk #! The text "Hello, world." is inserted right before this. ############################################################################# #! @Section Testing code chunks #! @BeginCode MyCode #! Hello, world. x := 1 + 1; if x = 2 then Print("1 + 1 = 2 holds, all is good\n"); else Error("1+1 <> 2"); fi; #! @EndCode #! This test comes after the code chunk is declared, but before it is inserted. #! @InsertCode MyCode #! The text "Hello, world." is inserted right before this. AutoDoc-2023.06.19/doc/manual.six000644 000766 000024 00000045702 14444021302 016514 0ustar00mhornstaff000000 000000 #SIXFORMAT GapDocGAP HELPBOOKINFOSIXTMP := rec( encoding := "UTF-8", bookname := "AutoDoc", entries := [ [ "Title page", ".", [ 0, 0, 0 ], 1, 1, "title page", "X7D2C85EC87DD46E5" ], [ "Abstract", ".-1", [ 0, 0, 1 ], 43, 2, "abstract", "X7AA6C5737B711C89" ], [ "Copyright", ".-2", [ 0, 0, 2 ], 49, 2, "copyright", "X81488B807F2A1CF1" ] , [ "Acknowledgements", ".-3", [ 0, 0, 3 ], 57, 2, "acknowledgements", "X82A988D47DFAFCFA" ], [ "Table of Contents", ".-4", [ 0, 0, 4 ], 62, 3, "table of contents", "X8537FEB07AF2BEC8" ], [ "\033[1X\033[33X\033[0;-2YGetting started using \033[5XAutoDoc\033[105X\\ 033[101X\027\033[1X\027\033[133X\033[101X", "1", [ 1, 0, 0 ], 1, 4, "getting started using autodoc", "X7A0D7AA484F466E1" ], [ "\033[1X\033[33X\033[0;-2YCreating a package manual from scratch\033[133X\\ 033[101X", "1.1", [ 1, 1, 0 ], 23, 4, "creating a package manual from scratch" , "X7BFBC6907B26AA95" ], [ "\033[1X\033[33X\033[0;-2YDocumenting code with \033[5XAutoDoc\033[105X\\ 033[101X\027\033[1X\027\033[133X\033[101X", "1.2", [ 1, 2, 0 ], 94, 5, "documenting code with autodoc", "X87A00EED866E22E8" ], [ "\033[1X\033[33X\033[0;-2YUsing \033[5XAutoDoc\033[105X\033[101X\027\033[1X\ \027 in an existing \033[5XGAPDoc\033[105X\033[101X\027\033[1X\027 manual\033[\ 133X\033[101X", "1.3", [ 1, 3, 0 ], 154, 6, "using autodoc in an existing gapdoc manual", "X7FA614637B807F4D" ], [ "\033[1X\033[33X\033[0;-2YUsing \033[5XAutoDoc\033[105X\033[101X\027\033[1X\ \027 on a complete \033[5XGAPDoc\033[105X\033[101X\027\033[1X\027 manual\033[1\ 33X\033[101X", "1.3-1", [ 1, 3, 1 ], 171, 6, "using autodoc on a complete gapdoc manual", "X7F3CEB097AF47C1E" ], [ "\033[1X\033[33X\033[0;-2YSetting different \033[5XGAPDoc\033[105X\033[101X\ \027\033[1X\027 options\033[133X\033[101X", "1.3-2", [ 1, 3, 2 ], 225, 7, "setting different gapdoc options", "X7D0DDF2284F2D24A" ], [ "\033[1X\033[33X\033[0;-2YChecklist for converting an existing \033[5XGAPDo\ c\033[105X\033[101X\027\033[1X\027 manual to use \033[5XAutoDoc\033[105X\033[1\ 01X\027\033[1X\027\033[133X\033[101X", "1.3-3", [ 1, 3, 3 ], 287, 8, "checklist for converting an existing gapdoc manual to use autodoc", "X83448D91868D7994" ], [ "\033[1X\033[33X\033[0;-2YScaffolds\033[133X\033[101X", "1.4", [ 1, 4, 0 ], 355, 9, "scaffolds", "X8524193D824CDE0D" ], [ "\033[1X\033[33X\033[0;-2YGenerating a title page\033[133X\033[101X", "1.4-1", [ 1, 4, 1 ], 358, 9, "generating a title page", "X7CF22DE28478316F" ], [ "\033[1X\033[33X\033[0;-2YGenerating the main XML file\033[133X\033[101X", "1.4-2", [ 1, 4, 2 ], 407, 10, "generating the main xml file", "X7CD72CC780874FD5" ], [ "\033[1X\033[33X\033[0;-2YWhat data is used from \033[11XPackageInfo.g\033[\ 111X\033[101X\027\033[1X\027?\033[133X\033[101X", "1.4-3", [ 1, 4, 3 ], 434, 10, "what data is used from packageinfo.g?", "X799956EA85D3FC15" ], [ "\033[1X\033[33X\033[0;-2YAutoDoc worksheets\033[133X\033[101X", "1.5", [ 1, 5, 0 ], 475, 11, "autodoc worksheets", "X80ED3C2A78146AD1" ], [ "\033[1X\033[33X\033[0;-2Y\033[5XAutoDoc\033[105X\033[101X\027\033[1X\027 d\ ocumentation comments\033[133X\033[101X", "2", [ 2, 0, 0 ], 1, 13, "autodoc documentation comments", "X87668C487B1A2094" ], [ "\033[1X\033[33X\033[0;-2YDocumenting declarations\033[133X\033[101X", "2.1", [ 2, 1, 0 ], 21, 13, "documenting declarations", "X871482CE838C68F6" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Description \033[3Xdescr\033[103X\033[10\ 1X\027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[10\ 1X", "2.1-1", [ 2, 1, 1 ], 29, 13, "description descr", "X7F1D85188262A827" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Returns \033[3Xret_val\033[103X\033[101\ X\027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101\ X", "2.1-2", [ 2, 1, 2 ], 36, 13, "returns ret_val", "X7DCAB2F87E8FAE90" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Arguments \033[3Xargs\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "2.1-3", [ 2, 1, 3 ], 43, 13, "arguments args", "X81DAA454857F7971" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Group \033[3Xgrpname\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "2.1-4", [ 2, 1, 4 ], 53, 14, "group grpname", "X8677FE8F80C00B14" ] , [ "\033[1X\033[33X\033[0;-2Y\033[10X@Label \033[3Xlabel\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "2.1-5", [ 2, 1, 5 ], 59, 14, "label label", "X7B0E20A27D64DF6F" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@ChapterInfo \033[3Xchapter\033[103X\033\ [101X\027\033[1X\027\033[10X\027, \033[3Xsection\033[103X\033[101X\027\033[1X\ \027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X", "2.1-8", [ 2, 1, 8 ], 95, 14, "chapterinfo chapter section", "X78938EE37A532FFA" ], [ "\033[1X\033[33X\033[0;-2YOther documentation comments\033[133X\033[101X", "2.2", [ 2, 2, 0 ], 118, 15, "other documentation comments", "X8152FEF9844B1ACD" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Chapter \033[3Xname\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "2.2-1", [ 2, 2, 1 ], 125, 15, "chapter name", "X823E613385D09F6F" ] , [ "\033[1X\033[33X\033[0;-2Y\033[10X@Section \033[3Xname\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "2.2-2", [ 2, 2, 2 ], 156, 15, "section name", "X78AA98BA7E0635D0" ] , [ "\033[1X\033[33X\033[0;-2Y\033[10X@Subsection \033[3Xname\033[103X\033[101X\ \027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X\ ", "2.2-3", [ 2, 2, 3 ], 172, 16, "subsection name", "X7FD77434802A3580" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginGroup \033[3X[grpname]\033[103X\\ 033[101X\027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\ \033[101X", "2.2-4", [ 2, 2, 4 ], 191, 16, "begingroup [grpname]", "X7D3060C17EDBCED1" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@EndGroup\033[110X\033[101X\027\033[1X\\ 027\033[133X\033[101X", "2.2-5", [ 2, 2, 5 ], 201, 16, "endgroup", "X7C17EB007FD42C87" ], [ "\033[1X\033[33X\033[0;-2Y@GroupTitle \033[3Xtitle\033[103X\033[101X\027\\ 033[1X\027\033[133X\033[101X", "2.2-6", [ 2, 2, 6 ], 221, 16, "grouptitle title", "X82FB96F37FAE8167" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Level \033[3Xlvl\033[103X\033[101X\027\\ 033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X", "2.2-7", [ 2, 2, 7 ], 228, 16, "level lvl", "X7BF81EAF80D1A4B5" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@ResetLevel\033[110X\033[101X\027\033[1X\\ 027\033[133X\033[101X", "2.2-8", [ 2, 2, 8 ], 237, 17, "resetlevel", "X7C6723D57F424215" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginExample\033[110X\033[101X\027\033[1\ X\027 and \033[10X@EndExample\033[110X\033[101X\027\033[1X\027\033[133X\033[10\ 1X", "2.2-9", [ 2, 2, 9 ], 242, 17, "beginexample and endexample", "X83D6DA3B83D3436C" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginExampleSession\033[110X\033[101X\\ 027\033[1X\027 and \033[10X@EndExampleSession\033[110X\033[101X\027\033[1X\027\ \033[133X\033[101X", "2.2-10", [ 2, 2, 10 ], 275, 17, "beginexamplesession and endexamplesession", "X861E2E778510CAF7" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginLog\033[110X\033[101X\027\033[1X\\ 027 and \033[10X@EndLog\033[110X\033[101X\027\033[1X\027\033[133X\033[101X", "2.2-11", [ 2, 2, 11 ], 312, 18, "beginlog and endlog", "X81A2D44D834C0A17" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginLogSession\033[110X\033[101X\027\\ 033[1X\027 and \033[10X@EndLogSession\033[110X\033[101X\027\033[1X\027\033[133\ X\033[101X", "2.2-12", [ 2, 2, 12 ], 319, 18, "beginlogsession and endlogsession", "X7BADE876794FF309" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@DoNotReadRestOfFile\033[110X\033[101X\\ 027\033[1X\027\033[133X\033[101X", "2.2-13", [ 2, 2, 13 ], 327, 18, "donotreadrestoffile", "X78DC644E8519280C" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginChunk \033[3Xname\033[103X\033[101X\ \027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027, \033[10X@EndChun\ k\033[110X\033[101X\027\033[1X\027, and \033[10X@InsertChunk \033[3Xname\033[1\ 03X\033[101X\027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[1\ 33X\033[101X", "2.2-14", [ 2, 2, 14 ], 341, 18, "beginchunk name endchunk and insertchunk name", "X83C01F9B7FA1C973" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@BeginCode \033[3Xname\033[103X\033[101X\ \027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027, @EndCode, and \ \033[10X@InsertCode \033[3Xname\033[103X\033[101X\027\033[1X\027\033[10X\027\ \033[110X\033[101X\027\033[1X\027\033[133X\033[101X", "2.2-15", [ 2, 2, 15 ], 378, 19, "begincode name endcode and insertcode name", "X7D3671AF86B995B9" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@LatexOnly \033[3Xtext\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027, \033[10X@BeginLat\ exOnly\033[110X\033[101X\027\033[1X\027, and \033[10X@EndLatexOnly\033[110X\ \033[101X\027\033[1X\027\033[133X\033[101X", "2.2-16", [ 2, 2, 16 ], 394, 19, "latexonly text beginlatexonly and endlatexonly", "X8033B34F80A12A10" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@NotLatex \033[3Xtext\033[103X\033[101X\ \027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027, \033[10X@BeginNo\ tLatex\033[110X\033[101X\027\033[1X\027, and \033[10X@EndNotLatex\033[110X\033\ [101X\027\033[1X\027\033[133X\033[101X", "2.2-17", [ 2, 2, 17 ], 409, 19, "notlatex text beginnotlatex and endnotlatex", "X7EF303147F1BCC22" ], [ "\033[1X\033[33X\033[0;-2YTitle page commands\033[133X\033[101X", "2.3", [ 2, 3, 0 ], 424, 19, "title page commands", "X841E3AD584F5385C" ], [ "\033[1X\033[33X\033[0;-2YPlain text files\033[133X\033[101X", "2.4", [ 2, 4, 0 ], 461, 20, "plain text files", "X828AE38F80CB02E7" ], [ "\033[1X\033[33X\033[0;-2YGrouping\033[133X\033[101X", "2.5", [ 2, 5, 0 ], 470, 20, "grouping", "X7D7A38F87BC40C48" ], [ "\033[1X\033[33X\033[0;-2YA family of operations\033[133X\033[101X", "2.5-1", [ 2, 5, 1 ], 518, 21, "a family of operations", "X79BF060F8436C586" ], [ "\033[1X\033[33X\033[0;-2YLevel\033[133X\033[101X", "2.6", [ 2, 6, 0 ], 527, 21, "level", "X8209AFDE8209AFDE" ], [ "\033[1X\033[33X\033[0;-2YMarkdown-like formatting of text in \033[5XAutoDo\ c\033[105X\033[101X\027\033[1X\027\033[133X\033[101X", "2.7", [ 2, 7, 0 ], 547, 22, "markdown-like formatting of text in autodoc", "X79558A2F7FE187B4" ], [ "\033[1X\033[33X\033[0;-2YLists\033[133X\033[101X", "2.7-1", [ 2, 7, 1 ], 556, 22, "lists", "X7B256AE5780F140A" ], [ "\033[1X\033[33X\033[0;-2YMath modes\033[133X\033[101X", "2.7-2", [ 2, 7, 2 ], 593, 22, "math modes", "X871412737A0E12E2" ], [ "\033[1X\033[33X\033[0;-2YEmphasize\033[133X\033[101X", "2.7-3", [ 2, 7, 3 ], 614, 23, "emphasize", "X7ED0330479146EFC" ], [ "\033[1X\033[33X\033[0;-2YInline code\033[133X\033[101X", "2.7-4", [ 2, 7, 4 ], 632, 23, "inline code", "X838CCDEB7E0ECEE2" ], [ "\033[1X\033[33X\033[0;-2YDeprecated commands\033[133X\033[101X", "2.8", [ 2, 8, 0 ], 645, 23, "deprecated commands", "X78CA9E5C7F494C19" ], [ "\033[1X\033[33X\033[0;-2YAutoDoc worksheets\033[133X\033[101X", "3", [ 3, 0, 0 ], 1, 24, "autodoc worksheets", "X80ED3C2A78146AD1" ], [ "\033[1X\033[33X\033[0;-2YWorksheets\033[133X\033[101X", "3.1", [ 3, 1, 0 ], 4, 24, "worksheets", "X801D4A2F8292704C" ], [ "\033[1X\033[33X\033[0;-2YAutoDoc\033[133X\033[101X", "4", [ 4, 0, 0 ], 1, 25, "autodoc", "X7CBD8AAF7DCEF352" ], [ "\033[1X\033[33X\033[0;-2YThe AutoDoc() function\033[133X\033[101X", "4.1", [ 4, 1, 0 ], 4, 25, "the autodoc function", "X863584DB8497D8BA" ] , [ "\033[1X\033[33X\033[0;-2YExamples\033[133X\033[101X", "4.2", [ 4, 2, 0 ], 326, 29, "examples", "X7A489A5D79DA9E5C" ], [ "Bibliography", "bib", [ "Bib", 0, 0 ], 1, 30, "bibliography", "X7A6F98FD85F02BFE" ], [ "References", "bib", [ "Bib", 0, 0 ], 1, 30, "references", "X7A6F98FD85F02BFE" ], [ "Index", "ind", [ "Ind", 0, 0 ], 1, 31, "index", "X83A0356F839C696F" ], [ "\033[11Xmakedoc.g\033[111X", "1.1", [ 1, 1, 0 ], 23, 4, "makedoc.g", "X7BFBC6907B26AA95" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "", "1.3-3", [ 1, 3, 3 ], 287, 8, "", "X83448D91868D7994" ], [ "\033[10X@Description \033[3Xdescr\033[103X\033[10X\027\033[110X", "2.1-1", [ 2, 1, 1 ], 29, 13, "description descr", "X7F1D85188262A827" ] , [ "\033[10X@Returns \033[3Xret_val\033[103X\033[10X\027\033[110X", "2.1-2", [ 2, 1, 2 ], 36, 13, "returns ret_val", "X7DCAB2F87E8FAE90" ], [ "\033[10X@Arguments \033[3Xargs\033[103X\033[10X\027\033[110X", "2.1-3", [ 2, 1, 3 ], 43, 13, "arguments args", "X81DAA454857F7971" ], [ "\033[10X@Group \033[3Xgrpname\033[103X\033[10X\027\033[110X", "2.1-4", [ 2, 1, 4 ], 53, 14, "group grpname", "X8677FE8F80C00B14" ], [ "\033[10X@Label \033[3Xlabel\033[103X\033[10X\027\033[110X", "2.1-5", [ 2, 1, 5 ], 59, 14, "label label", "X7B0E20A27D64DF6F" ], [ "\033[2XAProperty\033[102X testlabel", "2.1-6", [ 2, 1, 6 ], 75, 14, "aproperty testlabel", "X83B63B847B5199CF" ], [ "\033[2XAProperty\033[102X for IsObject", "2.1-7", [ 2, 1, 7 ], 90, 14, "aproperty for isobject", "X78A9022A7D5CB20E" ], [ "\033[10X@ChapterInfo\033[110X", "2.1-8", [ 2, 1, 8 ], 95, 14, "chapterinfo", "X78938EE37A532FFA" ], [ "\033[10X@Chapter\033[110X", "2.2-1", [ 2, 2, 1 ], 125, 15, "chapter", "X823E613385D09F6F" ], [ "\033[10X@ChapterLabel\033[110X", "2.2-1", [ 2, 2, 1 ], 125, 15, "chapterlabel", "X823E613385D09F6F" ], [ "\033[10X@ChapterTitle\033[110X", "2.2-1", [ 2, 2, 1 ], 125, 15, "chaptertitle", "X823E613385D09F6F" ], [ "\033[10X@Section\033[110X", "2.2-2", [ 2, 2, 2 ], 156, 15, "section", "X78AA98BA7E0635D0" ], [ "\033[10X@SectionLabel\033[110X", "2.2-2", [ 2, 2, 2 ], 156, 15, "sectionlabel", "X78AA98BA7E0635D0" ], [ "\033[10X@SectionTitle\033[110X", "2.2-2", [ 2, 2, 2 ], 156, 15, "sectiontitle", "X78AA98BA7E0635D0" ], [ "\033[10X@Subsection\033[110X", "2.2-3", [ 2, 2, 3 ], 172, 16, "subsection", "X7FD77434802A3580" ], [ "\033[10X@SubsectionLabel\033[110X", "2.2-3", [ 2, 2, 3 ], 172, 16, "subsectionlabel", "X7FD77434802A3580" ], [ "\033[10X@SubsectionTitle\033[110X", "2.2-3", [ 2, 2, 3 ], 172, 16, "subsectiontitle", "X7FD77434802A3580" ], [ "\033[10X@BeginGroup\033[110X", "2.2-4", [ 2, 2, 4 ], 191, 16, "begingroup", "X7D3060C17EDBCED1" ], [ "\033[10X@EndGroup\033[110X", "2.2-5", [ 2, 2, 5 ], 201, 16, "endgroup", "X7C17EB007FD42C87" ], [ "\033[10X@GroupTitle\033[110X", "2.2-6", [ 2, 2, 6 ], 221, 16, "grouptitle", "X82FB96F37FAE8167" ], [ "\033[10X@Level\033[110X", "2.2-7", [ 2, 2, 7 ], 228, 16, "level", "X7BF81EAF80D1A4B5" ], [ "\033[10X@ResetLevel\033[110X", "2.2-8", [ 2, 2, 8 ], 237, 17, "resetlevel", "X7C6723D57F424215" ], [ "\033[10X@BeginExample\033[110X", "2.2-9", [ 2, 2, 9 ], 242, 17, "beginexample", "X83D6DA3B83D3436C" ], [ "\033[10X@EndExample\033[110X", "2.2-9", [ 2, 2, 9 ], 242, 17, "endexample", "X83D6DA3B83D3436C" ], [ "\033[10X@BeginExampleSession\033[110X", "2.2-10", [ 2, 2, 10 ], 275, 17, "beginexamplesession", "X861E2E778510CAF7" ], [ "\033[10X@EndExampleSession\033[110X", "2.2-10", [ 2, 2, 10 ], 275, 17, "endexamplesession", "X861E2E778510CAF7" ], [ "\033[10X@BeginLog\033[110X", "2.2-11", [ 2, 2, 11 ], 312, 18, "beginlog", "X81A2D44D834C0A17" ], [ "\033[10X@EndLog\033[110X", "2.2-11", [ 2, 2, 11 ], 312, 18, "endlog", "X81A2D44D834C0A17" ], [ "\033[10X@BeginLogSession\033[110X", "2.2-12", [ 2, 2, 12 ], 319, 18, "beginlogsession", "X7BADE876794FF309" ], [ "\033[10X@EndLogSession\033[110X", "2.2-12", [ 2, 2, 12 ], 319, 18, "endlogsession", "X7BADE876794FF309" ], [ "\033[10X@DoNotReadRestOfFile\033[110X", "2.2-13", [ 2, 2, 13 ], 327, 18, "donotreadrestoffile", "X78DC644E8519280C" ], [ "\033[10X@BeginChunk \033[3Xname\033[103X\033[10X\027\033[110X", "2.2-14", [ 2, 2, 14 ], 341, 18, "beginchunk name", "X83C01F9B7FA1C973" ], [ "\033[10X@EndChunk\033[110X", "2.2-14", [ 2, 2, 14 ], 341, 18, "endchunk", "X83C01F9B7FA1C973" ], [ "\033[10X@InsertChunk \033[3Xname\033[103X\033[10X\027\033[110X", "2.2-14", [ 2, 2, 14 ], 341, 18, "insertchunk name", "X83C01F9B7FA1C973" ], [ "\033[10X@BeginCode \033[3Xname\033[103X\033[10X\027\033[110X", "2.2-15", [ 2, 2, 15 ], 378, 19, "begincode name", "X7D3671AF86B995B9" ], [ "\033[10X@EndCode\033[110X", "2.2-15", [ 2, 2, 15 ], 378, 19, "endcode", "X7D3671AF86B995B9" ], [ "\033[10X@InsertCode \033[3Xname\033[103X\033[10X\027\033[110X", "2.2-15", [ 2, 2, 15 ], 378, 19, "insertcode name", "X7D3671AF86B995B9" ], [ "\033[10X@LatexOnly \033[3Xtext\033[103X\033[10X\027\033[110X", "2.2-16", [ 2, 2, 16 ], 394, 19, "latexonly text", "X8033B34F80A12A10" ] , [ "\033[10X@BeginLatexOnly\033[110X", "2.2-16", [ 2, 2, 16 ], 394, 19, "beginlatexonly", "X8033B34F80A12A10" ], [ "\033[10X@EndLatexOnly\033[110X", "2.2-16", [ 2, 2, 16 ], 394, 19, "endlatexonly", "X8033B34F80A12A10" ], [ "\033[10X@NotLatex \033[3Xtext\033[103X\033[10X\027\033[110X", "2.2-17", [ 2, 2, 17 ], 409, 19, "notlatex text", "X7EF303147F1BCC22" ], [ "\033[10X@BeginNotLatex\033[110X", "2.2-17", [ 2, 2, 17 ], 409, 19, "beginnotlatex", "X7EF303147F1BCC22" ], [ "\033[10X@EndNotLatex\033[110X", "2.2-17", [ 2, 2, 17 ], 409, 19, "endnotlatex", "X7EF303147F1BCC22" ], [ "\033[2XFirstOperation\033[102X for IsInt", "2.5-1", [ 2, 5, 1 ], 518, 21, "firstoperation for isint", "X79BF060F8436C586" ], [ "\033[2XSecondOperation\033[102X for IsInt, IsGroup", "2.5-1", [ 2, 5, 1 ], 518, 21, "secondoperation for isint isgroup", "X79BF060F8436C586" ], [ "\033[2XThirdOperation\033[102X for IsGroup, IsInt", "2.5-1", [ 2, 5, 1 ], 518, 21, "thirdoperation for isgroup isint", "X79BF060F8436C586" ], [ "\033[2XAutoDocWorksheet\033[102X", "3.1-1", [ 3, 1, 1 ], 7, 24, "autodocworksheet", "X809FE4137C08B28D" ], [ "\033[2XAutoDoc\033[102X", "4.1-1", [ 4, 1, 1 ], 7, 25, "autodoc", "X7CBD8AAF7DCEF352" ] ] ); AutoDoc-2023.06.19/doc/chapBib_mj.html000644 000766 000024 00000005237 14444021302 017415 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - References
Goto Chapter: Top 1 2 3 4 Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

References

[LN12] Lübeck, F. and Neunhöffer, M., GAPDoc (Version 1.5.1), RWTH Aachen (2012)
( GAP package, http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html ).

 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/_entities.xml000644 000766 000024 00000000306 14444021275 017217 0ustar00mhornstaff000000 000000 PackageName'> AutoDoc'> io'> AutoDoc-2023.06.19/doc/chap0_mj.html000644 000766 000024 00000040103 14444021302 017047 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Contents
Goto Chapter: Top 1 2 3 4 Bib Ind
 [Top of Book]  [Contents]   [Next Chapter] 

AutoDoc

Generate documentation from GAP source code

2023.06.19

19 June 2023

Sebastian Gutsche
Email: gutsche@mathematik.uni-siegen.de
Homepage: https://algebra.mathematik.uni-siegen.de/gutsche/
Address:
Department Mathematik
Universität Siegen
Walter-Flex-Straße 3
57072 Siegen
Germany

Max Horn
Email: mhorn@rptu.de
Homepage: https://www.quendi.de/math
Address:
Fachbereich Mathematik
RPTU Kaiserslautern-Landau
Gottlieb-Daimler-Straße 48
67663 Kaiserslautern
Germany

Abstract

AutoDoc is a GAP package whose purpose is to aid GAP package authors in creating and maintaining the documentation of their packages.

Copyright

© 2012-2022 by Sebastian Gutsche and Max Horn

This package may be distributed under the terms and conditions of the GNU Public License Version 2 or (at your option) any later version.

Acknowledgements

This documentation was prepared using the GAPDoc package [LN12].

Contents

1 Getting started using AutoDoc
2 AutoDoc documentation comments
3 AutoDoc worksheets
4 AutoDoc
References
Index

 [Top of Book]  [Contents]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chap2.html000644 000766 000024 00000123672 14444021302 016400 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 2: AutoDoc documentation comments
Goto Chapter: Top 1 2 3 4 Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

2 AutoDoc documentation comments
 2.1 Documenting declarations
 2.2 Other documentation comments
 2.3 Title page commands
 2.4 Plain text files
 2.5 Grouping
 2.6 Level
 2.7 Markdown-like formatting of text in AutoDoc
 2.8 Deprecated commands

2 AutoDoc documentation comments

You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declaration. An AutoDoc comment always starts with #!. This is also the smallest possible AutoDoc command. If you want your declaration documented, just write #! at the line before the documentation. For example:

#!
DeclareOperation( "AnOperation",
                  [ IsList ] );

This will produce a manual entry for the operation AnOperation.

Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces.

2.1 Documenting declarations

In the bare form above, the manual entry for AnOperation will not contain much more than the name of the operation. In order to change this, there are several commands you can put into the AutoDoc comment before the declaration. Currently, the following commands are provided:

2.1-1 @Description descr

Adds the text in the following lines of the AutoDoc to the description of the declaration in the manual. Lines are until the next AutoDoc command or until the declaration is reached.

2.1-2 @Returns ret_val

The string ret_val is added to the documentation, with the text "Returns: " put in front of it. This should usually give a brief hint about the type or meaning of the value returned by the documented function.

2.1-3 @Arguments args

The string args contains a description of the arguments the function expects, including optional parts, which are denoted by square brackets. The argument names can be separated by whitespace, commas or square brackets for the optional arguments, like "grp[, elm]" or "xx[y[z] ]". If GAP options are used, this can be followed by a colon : and one or more assignments, like "n[, r]: tries := 100".

2.1-4 @Group grpname

Adds the following method to a group with the given name. See section 2.5 for more information about groups.

2.1-5 @Label label

Adds label to the function as label. If this is not specified, then for declarations that involve a list of input filters (as is the case for DeclareOperation, DeclareAttribute, etc.), a default label is generated from this filter list.

#! @Label testlabel
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

2.1-6 AProperty
‣ AProperty( arg )( property )

Returns: true or false

while

#!
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

2.1-7 AProperty
‣ AProperty( arg )( property )

Returns: true or false

2.1-8 @ChapterInfo chapter, section

Adds the entry to the given chapter and section. Here, chapter and section are the respective titles.

As an example, a full AutoDoc comment with all options could look like this:

#! @Description
#! Computes the list of lists of degrees of ordinary characters
#! associated to the $p$-blocks of the group $G$
#! with $p$-modular character table <A>modtbl</A>
#! and underlying ordinary character table `ordtbl`.
#! @Returns a list
#! @Arguments modtbl
#! @Group CharacterDegreesOfBlocks
#! @Label chardegblocks
#! @ChapterInfo Blocks, Attributes
DeclareAttribute( "CharacterDegreesOfBlocks",
        IsBrauerTable );

2.2 Other documentation comments

There are also some commands which can be used in AutoDoc comments that are not associated to any declaration. This is useful for additional text in your documentation, examples, mathematical chapters, etc..

2.2-1 @Chapter name

Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their AutoDoc comment via @ChapterInfo will be added to this chapter. Also all text comments, i.e. lines that begin with #! without a command, and which do not follow after @Description, will be added to the chapter as regular text. Additionally, the chapters label will be set to Chapter_name. Example:

#! @Chapter My chapter
#!  This is my chapter.
#!  I document my stuff in it.

The @ChapterLabel label command can be used to set the label of the chapter to Chapter_label instead of Chapter_name. Additionally, the chapter will be stored as _Chapter_label.xml. The @ChapterTitle title command can be used to set a heading for the chapter that is different from name. Note that the title does not affect the label. If you use all three commands, i.e.,

#! @Chapter name
#! @ChapterLabel label
#! @ChapterTitle title

title is used for the headline, label for cross-referencing, and name for setting the same chapter as active chapter again.

2.2-2 @Section name

Sets an active section like @Chapter sets an active chapter. The section automatically ends with the next @Section or @Chapter command.

#! @Section My first manual section
#!  In this section I am going to document my first method.

The @SectionLabel label command can be used to set the label of the section to Section_label instead of Chapter_chaptername_Section_name. The @SectionTitle title command can be used to set a heading for the section that is different from name.

2.2-3 @Subsection name

Sets an active subsection like @Section sets an active section. The subsection automatically ends with the next @Subsection, @Section or @Chapter command. It also ends with the next documented function. Indeed, internally each function "manpage" is treated like a subsection.

#! @Subsection My first manual subsection
#!  In this subsection I am going to document my first example.

The @SubsectionLabel label command can be used to set the label of the subsection to Subsection_label instead of Chapter_chaptername_Section_sectionname_Subsection_name. The @SubsectionTitle title command can be used to set a heading for the subsection that is different from name.

2.2-4 @BeginGroup [grpname]

Starts a group. All following documented declarations without an explicit @Group command are grouped together in the same group with the given name. If no name is given, then a new nameless group is generated. The effect of this command is ended when an @EndGroup command is reached.

See section 2.5 for more information about groups.

2.2-5 @EndGroup

Ends the current group.

#! @BeginGroup MyGroup
#!
DeclareAttribute( "GroupedAttribute",
                  IsList );

DeclareOperation( "NonGroupedOperation",
                  [ IsObject ] );

#!
DeclareOperation( "GroupedOperation",
                  [ IsList, IsRubbish ] );
#! @EndGroup

2.2-6 @GroupTitle title

Sets the subsection heading for the current group to title. In the absence of any @GroupTitle command, the heading will be the name of the first entry in the group. See 2.5 for more information.

2.2-7 @Level lvl

Sets the current level of the documentation. All items created after this, chapters, sections, and items, are given the level lvl, until the @ResetLevel command resets the level to 0 or another level is set.

See section 2.6 for more information about levels.

2.2-8 @ResetLevel

Resets the current level to 0.

2.2-9 @BeginExample and @EndExample

@BeginExample marks the start of an example to be put into the manual. It differs from GAPDoc's <Example> (see GAPDoc: Log), in that it expects actual code (not in a comment) interspersed with comments, to allow for examples files that can be both executed by GAP, and parsed by AutoDoc. To achieve this, GAP commands are not preceded by a comment, while output has to be preceded by an AutoDoc comment. The gap> prompt for the display in the manual is added by AutoDoc. @EndExample ends the example block.

To illustrate this command, consider this input:

#! @BeginExample
S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
Order(S5);
#! 120
#! @EndExample

This results in the following output:

gap> S5 := SymmetricGroup(5);
Sym( [ 1 .. 5 ] )
gap> Order(S5);
120

The AutoDoc command @Example is an alias of @BeginExample.

2.2-10 @BeginExampleSession and @EndExampleSession

@BeginExampleSession marks the start of an example to be put into the manual, while @EndExampleSession ends the example block. It is the direct analog of GAPDoc's <Example> (see GAPDoc: Log).

To illustrate this command, consider this input:

#! @BeginExampleSession
#! gap> S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
#! gap> Order(S5);
#! 120
#! @EndExampleSession

This results in the following output:

gap> S5 := SymmetricGroup(5);
Sym( [ 1 .. 5 ] )
gap> Order(S5);
120

It inserts an example into the manual just as @Example would do, but all lines are commented and therefore not executed when the file is read. All lines that should be part of the example displayed in the manual have to start with an AutoDoc comment (#!). The comment will be removed, and, if the following character is a space, this space will also be removed. There is never more than one space removed. To ensure examples are correctly colored in the manual, there should be exactly one space between #! and the gap> prompt. The AutoDoc command @ExampleSession is an alias of @BeginExampleSession.

2.2-11 @BeginLog and @EndLog

Works just like the @BeginExample command, but the example will not be tested. See the GAPDoc manual for more information. The AutoDoc command @Log is an alias of @BeginLog.

2.2-12 @BeginLogSession and @EndLogSession

Works just like the @BeginExampleSession command, but the example will not be tested if manual examples are run. It is the direct analog of GAPDoc's <Log> (see GAPDoc: Log). The AutoDoc command @LogSession is an alias of @BeginLogSession.

2.2-13 @DoNotReadRestOfFile

Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files.

#! This will appear in the manual

#! @DoNotReadRestOfFile

#! This will not appear in the manual.

2.2-14 @BeginChunk name, @EndChunk, and @InsertChunk name

Text inside a @BeginChunk / @EndChunk part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. That chunk of text can then later on be inserted in any other place by using the @InsertChunk name command. If you do not provide an @EndChunk, the chunk ends at the end of the file.

#! @BeginChunk MyChunk
#! Hello, world.
#! @EndChunk

#! @InsertChunk MyChunk
## The text "Hello, world." is inserted right before this.

You can use this to define an example like this in one file:

#! @BeginChunk Example_Symmetric_Group
#! @BeginExample
S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
Order(S5);
#! 120
#! @EndExample
#! @EndChunk

And then later, insert the example in a different file, like this:

#! @InsertChunk Example_Symmetric_Group

2.2-15 @BeginCode name, @EndCode, and @InsertCode name

Inserts the text between @BeginCode and @EndCode verbatim at the point where @InsertCode is called. This is useful to insert code excerpts directly into the manual.

#! @BeginCode Increment
i := i + 1;
#! @EndCode

#! @InsertCode Increment
## Code is inserted here.

2.2-16 @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly

Code inserted between @BeginLatexOnly and @EndLatexOnly or after @LatexOnly is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary LaTeX-commands.

#! @BeginLatexOnly
#! \include{picture.tex}
#! @EndLatexOnly

#! @LatexOnly \include{picture.tex}

2.2-17 @NotLatex text, @BeginNotLatex, and @EndNotLatex

Code inserted between @BeginNotLatex and @EndNotLatex or after @NotLatex is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version.

#! @BeginNotLatex
#! For further information see the PDF version of this manual.
#! @EndNotLatex

#! @NotLatex For further information see the PDF version of this manual.

2.3 Title page commands

The following commands can be used to add the corresponding parts to the title page of the document which generated by AutoDoc if scaffolding is enabled.

Those add the following lines at the corresponding point of the title page. Please note that many of those things can be (better) extracted from the PackageInfo.g. In case you set some of those, the extracted or in scaffold defined items will be overwritten. While this is not very useful for documenting packages, they are necessary for worksheets created with AutoDocWorksheet (3.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted.

2.4 Plain text files

Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.1-1), resp. are contained in one of the directories listed in autodoc.scan_dirs, are treated as AutoDoc plain text files. These work exactly like AutoDoc comments, except that lines do not need to (and in fact, should not) start with #!.

2.5 Grouping

In GAPDoc, it is possible to make groups of manual items, i.e., when documenting a function, operation, etc., it is possible to group them into suitable chunks. This can be particularly useful if there are several definitions of an operation with several different argument types, all doing more or less the same to the arguments. Then their manual items can be grouped, sharing the same description and return type information. You can give a heading to the group in the manual with the @GroupTitle command; if that is not supplied, then the heading of the first manual item in the group will be used as the heading.

Note that group names are globally unique throughout the whole manual. That is, groups with the same name are in fact merged into a single group, even if they were declared in different source files. Thus you can have multiple @BeginGroup / @EndGroup pairs using the same group name, in different places, and these all will refer to the same group.

Moreover, this means that you can add items to a group via the @Group command in the AutoDoc comment of an arbitrary declaration, at any time.

The following code

#! @BeginGroup Group1
#! @GroupTitle A family of operations

#! @Description
#!  First sentence.
DeclareOperation( "FirstOperation", [ IsInt ] );

#! @Description
#!  Second sentence.
DeclareOperation( "SecondOperation", [ IsInt, IsGroup ] );

#! @EndGroup

## .. Stuff ..

#! @Description
#!  Third sentence.
#! @Group Group1
KeyDependentOperation( "ThirdOperation", IsGroup, IsInt, "prime );

produces the following:

2.5-1 A family of operations
‣ FirstOperation( arg )( operation )
‣ SecondOperation( arg1, arg2 )( operation )
‣ ThirdOperation( arg1, arg2 )( operation )

First sentence. Second sentence. Third sentence.

2.6 Level

Levels can be set to not write certain parts in the manual by default. Every entry has by default the level 0. The command @Level can be used to set the level of the following part to a higher level, for example 1, and prevent it from being printed to the manual by default. However, if one sets the level to a higher value in the autodoc option of AutoDoc, the parts will be included in the manual at the specific place.

#! This text will be printed to the manual.
#! @Level 1
#! This text will be printed to the manual if created with level 1 or higher.
#! @Level 2
#! This text will be printed to the manual if created with level 2 or higher.
#! @ResetLevel
#! This text will be printed to the manual.

2.7 Markdown-like formatting of text in AutoDoc

AutoDoc has some convenient ways to insert special format into text, like math formulas and lists. The syntax for them are inspired by Markdown and LaTeX, but do not follow them strictly. Neither are all features of the Markdown language supported. The following subsections describe what is possible.

2.7-1 Lists

One can create lists of items by beginning a new line with *, +, -, followed by one space. The first item starts the list. When items are longer than one line, the following lines have to be indented by at least two spaces. The list ends when a line which does not start a new item is not indented by two spaces. Of course lists can be nested. Here is an example:

#! The list starts in the next line
#! * item 1
#! * item 2
#!   which is a bit longer
#!   * and also contains a nested list
#!   * with two items
#! * item 3 of the outer list
#! This does not belong to the list anymore.

This is the output:
The list starts in the next line

This does not belong to the list anymore.
The *, -, and + are fully interchangeable and can even be used mixed, but this is not recommended.

2.7-2 Math modes

One can start an inline formula with a $, and also end it with $, just like in LaTeX. This will translate into GAPDocs inline math environment. For display mode one can use $$, also like LaTeX.

#! This is an inline formula: $1+1 = 2$.
#! This is a display formula:
#! $$ \sum_{i=1}^n i. $$

produces the following output:
This is an inline formula: 1+1 = 2. This is a display formula:

\sum_{i=1}^n i.

2.7-3 Emphasize

One can emphasize text by using two asterisks (**) or two underscores (__) at the beginning and the end of the text which should be emphasized. Example:

#! **This** is very important.
#! This is __also important__.
#! **Naturally, more than one line
#! can be important.**

This produces the following output:
This is very important. This is also important. Naturally, more than one line can be important.

2.7-4 Inline code

One can mark inline code snippets by using backticks (`) at the beginning and the end of the text which should be marked as code. Example:

#! Call function `foobar()` at the start.

This produces the following output:
Call function foobar() at the start.

2.8 Deprecated commands

The following commands used to be supported, but should not generally be used anymore. They will be removed in a future version of AutoDoc.

@EndSection

You can simply remove any use of this, AutoDoc ends sections automatically at the start of any new section or chapter.

@EndSubsection

You can simply remove any use of this, AutoDoc ends subsections automatically at the start of any new subsection, section or chapter.

@BeginAutoDoc and @EndAutoDoc

It suffices to prepend each declaration that is meant to be appear in the manual with a minimal AutoDoc comment #!.

@BeginSystem name, @EndSystem, and @InsertSystem name

Please use the chunk commands from subsection 2.2-14 instead.

@AutoDocPlainText and @EndAutoDocPlainText

Use .autodoc files or AutoDoc comments instead.

 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/_AutoDocMainFile.xml000644 000766 000024 00000000267 14444021275 020344 0ustar00mhornstaff000000 000000 <#Include SYSTEM "_Chapter_AutoDoc_worksheets.xml"> <#Include SYSTEM "_Chapter_AutoDoc.xml"> AutoDoc-2023.06.19/doc/chap3.html000644 000766 000024 00000007016 14444021302 016372 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 3: AutoDoc worksheets
Goto Chapter: Top 1 2 3 4 Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

3 AutoDoc worksheets
 3.1 Worksheets

3 AutoDoc worksheets

3.1 Worksheets

3.1-1 AutoDocWorksheet
‣ AutoDocWorksheet( list_of_filenames: options )( function )

The intention of these function is to create stand-alone pdf and html files using AutoDoc without having them associated to a package. It uses the same optional records as the AutoDoc command itself, but instead of a package name there should be a filename or a list of filenames containing AutoDoc text from which the documents are created. Please see the AutoDoc command for more information about this and have a look at 1.5 for a simple worksheet example.

 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chap1_mj.html000644 000766 000024 00000103320 14444021302 017051 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 1: Getting started using AutoDoc
Goto Chapter: Top 1 2 3 4 Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

1 Getting started using AutoDoc
 1.1 Creating a package manual from scratch
 1.2 Documenting code with AutoDoc
 1.3 Using AutoDoc in an existing GAPDoc manual
 1.4 Scaffolds
 1.5 AutoDoc worksheets

1 Getting started using AutoDoc

AutoDoc is a GAP package which is meant to aid GAP package authors in creating and maintaining the documentation of their packages. In this capacity it builds upon the GAPDoc package (see https://www.gap-system.org/Packages/gapdoc.html). As such, it is not a replacement for GAPDoc, but rather complements it.

In this chapter we describe how to get started using AutoDoc for your package. First, we explain in Section 1.1 how to write a new package manual from scratch.

Then we show in Section 1.3 how you might benefit from AutoDoc even if you already have a complete manual written using GAPDoc.

In Section 1.4, we explain how you may use AutoDoc to generate a title page and the main XML file for your manual.

Finally, Section 1.5, explains what AutoDoc worksheets are and how to use them.

1.1 Creating a package manual from scratch

Suppose your package is already up and running, but so far has no manual. Then you can rapidly generate a "scaffold" for a package manual using the AutoDoc (4.1-1) command like this, while running GAP from within your package's directory (the one containing the PackageInfo.g file):

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true ) );

This first reads the PackageInfo.g file from the current directory. It extracts information about package from it (such as its name and version, see Section 1.4-1). It then creates two XML files doc/NAME_OF_YOUR_PACKAGE.xml and doc/title.xml inside the package directory. Finally, it runs GAPDoc on them to produce a nice initial PDF and HTML version of your fresh manual.

To ensure that the GAP help system picks up your package manual, you should also add something like the following to your PackageInfo.g:

PackageDoc := rec(
  BookName  := ~.PackageName,
  ArchiveURLSubset := ["doc"],
  HTMLStart := "doc/chap0.html",
  PDFFile   := "doc/manual.pdf",
  SixFile   := "doc/manual.six",
  LongTitle := ~.Subtitle,
),

Congratulations, your package now has a minimal working manual. Of course it will be mostly empty for now, but it already should contain some useful information, based on the data in your PackageInfo.g. This includes your package's name, version and description as well as information about its authors. And if you ever change the package data, (e.g. because your email address changed), just re-run the above command to regenerate the two main XML files with the latest information.

Next of course you need to provide actual content (unfortunately, we were not yet able to automate that for you, more research on artificial intelligence is required). To add more content, you have several options: You could add further GAPDoc XML files containing extra chapters, sections and so on. Or you could use classic GAPDoc source comments. For details on either, please refer to GAPDoc: Distributing a Document into Several Files, as well as Section 1.3 of this manual on how to teach the AutoDoc (4.1-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 1.2).

You will probably want to re-run the AutoDoc (4.1-1) command frequently, e.g. whenever you modified your documentation or your PackageInfo.g. To make this more convenient and reproducible, we recommend putting its invocation into a file makedoc.g in your package directory, with content based on the following example:

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) );
QUIT;

Then you can regenerate the package manual from the command line with the following command, executed from within in the package directory:

gap makedoc.g

1.2 Documenting code with AutoDoc

To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an AutoDoc comment of the form #! directly in front of it. For example:

#!
DeclareOperation( "ToricVariety", [ IsConvexObject ] );

This tiny change is already sufficient to ensure that the operation appears in the manual. In general, you will want to add further information about the operation, such as in the following example:

#! @Arguments conv
#! @Returns a toric variety
#! @Description
#!  Creates a toric variety out
#!  of the convex object <A>conv</A>.
DeclareOperation( "ToricVariety", [ IsConvexObject ] );

For a thorough description of what you can do with AutoDoc documentation comments, please refer to chapter 2.

Suppose you have not been using GAPDoc before but instead used the process described in section 1.1 to create your manual. Then the following GAP command will regenerate the manual and automatically include all newly documented functions, operations etc.:

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true,
              autodoc := true ) );

If you are not using the scaffolding feature, e.g. because you already have an existing GAPDoc based manual, then you can still use AutoDoc documentation comments. Just make sure to first edit the main XML file of your documentation, and insert the line

<#Include SYSTEM "_AutoDocMainFile.xml">

in a suitable place. This means that you can mix AutoDoc documentation comment freely with your existing documentation; you can even still make use of any existing GAPDoc documentation comments in your code. The following command should be useful for you in this case; it still scans the package code for AutoDoc documentation comments and the runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) );

1.3 Using AutoDoc in an existing GAPDoc manual

Even if you already have an existing GAPDoc manual, it might be interesting for you to use AutoDoc for two purposes:

First off, with AutoDoc is very convenient to regenerate your documentation.

Secondly, the scaffolding feature which generates a title page with all the metadata of your package in a uniform way is very handy. The somewhat tedious process of keeping your title page in sync with your PackageInfo.g is fully automated this way (including the correct version, release data, author information and so on).

There are various examples of packages using AutoDoc for only this purpose, e.g. io and orb.

1.3-1 Using AutoDoc on a complete GAPDoc manual

Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your .g, .gd, and .gi files. Suppose the main XML file is named PACKAGENAME.xml and is in the /doc subdirectory of your package. Then you can rebuild your manual by executing the following two GAP commands from a GAP sessions started started in the root directory of your package:

LoadPackage( "AutoDoc" );
AutoDoc( );

In contrast, the RingsForHomalg currently uses essentially the following code in its makedoc.g file to achieve the same result

LoadPackage( "GAPDoc" );
SetGapDocLaTeXOptions( "utf8" );
bib := ParseBibFiles( "doc/RingsForHomalg.bib" );
WriteBibXMLextFile( "doc/RingsForHomalgBib.xml", bib );
list := [
         "../gap/RingsForHomalg.gd",
         "../gap/RingsForHomalg.gi",
         "../gap/Singular.gi",
         "../gap/SingularBasic.gi",
         "../examples/RingConstructionsExternalGAP.g",
         "../examples/RingConstructionsSingular.g",
         "../examples/RingConstructionsMAGMA.g",
         "../examples/RingConstructionsMacaulay2.g",
         "../examples/RingConstructionsSage.g",
         "../examples/RingConstructionsMaple.g",
         ];
MakeGAPDocDoc( "doc", "RingsForHomalg", list, "RingsForHomalg" );
GAPDocManualLab( "RingsForHomalg" );

Note that in particular, you do not have to worry about keeping a list of your implementation files up-to-date.

But there is more. AutoDoc can create .tst files from the examples in your manual to test your package. This can be achieved via

LoadPackage( "AutoDoc" );
AutoDoc( rec( extract_examples := true ) );

Now files PACKAGENAME01.tst, PACKAGENAME02.tst and so appear in the tst/ subdirectory of your package, and can be tested as usual using Test (Reference: Test) respectively TestDirectory (Reference: TestDirectory).

1.3-2 Setting different GAPDoc options

Sometimes, the default values for the GAPDoc command used by AutoDoc may not be suitable for your manual.

Suppose your main XML file is not named PACKAGENAME.xml, but rather something else, e.g. main.xml. Then you can tell AutoDoc to use this file as the main XML file via

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( main := "main" ) ) );

As explained above, by default AutoDoc scans all .g, .gd and .gi files it can find inside of your package root directory, and in the subdirectories gap, lib, examples and examples/doc as well. If you keep source files with documentation in other directories, you can adjust the list of directories AutoDoc scans via the scan_dirs option. The following example illustrates this by instructing AutoDoc to only search in the subdirectory package_sources of the packages root directory.

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( scan_dirs := [ "package_sources" ] ) ) );

You can also specify an explicit list of files containing documentation, which will be searched in addition to any files located within the scan directories:

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( files := [ "path/to/some/hidden/file.gds" ] ) ) );

Giving such a file does not prevent the standard scan_dirs from being scanned for other files.

Next, GAPDoc supports the documentation to be built with relative paths. This means, links to manuals of other packages or the GAP library will not be absolute, but relative from your documentation. This can be particularly useful if you want to build a release tarball or move your GAP installation around later. Suppose you are starting GAP in the root path of your package as always, and the standard call of AutoDoc (4.1-1) will then build the documentation in the doc subdirectory of your package. From this directory, the gap root directory has the relative path ../../... Then you can enable the relative paths by

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) );

or, since ../../.. is the standard option for gap_root_relative_path, by

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) );

1.3-3 Checklist for converting an existing GAPDoc manual to use AutoDoc

Here is a checklist for authors of a package PackageName, which already has a GAPDoc based manual, who wish to use AutoDoc to build the manual from now on. We assume that the manual is currently built by reading a file makedoc.g and that the main .xml file is named manual.xml.

The files PackageInfo.g, makedoc.g, doc/title.xml and doc/PackageName.xml (if it exists) will be altered by this procedure, so it may be wise to keep backup copies.

You should have copies of the AutoDoc files PackageInfo.g and makedoc.g to hand when reading these instructions.

You should now be ready to run GAP and Read("makedoc.g"); in your package root directory.

1.4 Scaffolds

1.4-1 Generating a title page

For most (if not all) GAP packages, the title page of the package manual lists information such as the release date, version, names and contact details of the authors, and so on. All this data is also contained in your PackageInfo.g, and whenever you make a change to that file, there is a risk that you forget to update your manual to match. And even if you don't forget it, you of course have to spend some time to adjust the manual. GAPDoc can help to a degree with this via entities. Thus, you will sometimes see code like this in PackageInfo.g files:

Version        := "1.2.3",
Date           := "20/01/2015",
##  <#GAPDoc Label="PKGVERSIONDATA">
##  <!ENTITY VERSION "1.2.3">
##  <!ENTITY RELEASEDATE "20 January 2015">
##  <!ENTITY RELEASEYEAR "2015">
##  <#/GAPDoc>

However, it is still easy to forget both of these versions. And it doesn't solve the problem of updating package authors addresses. Neither of these is a big issue, of course, but there have been plenty examples in the past where people forget either of these two things, and it can be slightly embarrassing. It may even require you to make a new release just to fix the issue, which in our opinion is a sad waste of your valuable time.

So instead of worrying about manually synchronising these things, you can instruct AutoDoc to generate a title page for your manual based on the information in your PackageInfo.g. The following commands do just that (in addition to building your manual), by generating a file called doc/title.xml.

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := rec( MainPage := false ) ) );

Note that this only outputs doc/title.xml but does not touch any other files of your documentation. In particular, you need to explicitly include doc/title.xml from your main XML file.

However, you can also tell AutoDoc to maintain the main XML file for you, in which case this is automatic. In fact, this is the default if you enable scaffolding; the above example command explicitly told AutoDoc not to generate a main page.

1.4-2 Generating the main XML file

The following generates a main XML file for your documentation in addition to the title page. The main XML file includes the title page by default, as well as any documentation generated from AutoDoc documentation comments.

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true ) );

You can instruct AutoDoc to include additional XML files by giving it a list of filenames, as in the following example:

LoadPackage( "AutoDoc" );
AutoDoc(rec(
    scaffold := rec(
        includes := [ "somefile.xml", "anotherfile.xml" ]
    )
));

For more information, please consult the documentation of the AutoDoc (4.1-1) function.

1.4-3 What data is used from PackageInfo.g?

AutoDoc can use data from PackageInfo.g in order to generate a title page. Specifically, the following components of the package info record are taken into account:

PackageName

This is used to set the <Title> element of the title page.

Subtitle

This is used to set the <Subtitle> element of the title page.

Version

This is used to set the <Version> element of the title page, with the string "Version " prepended.

Date

This is used to set the <Date> element of the title page.

Persons

This is used to generate <Author> elements in the generated title page.

PackageDoc

This is a record (or a list of records) which is used to tell the GAP help system about the package manual. Currently AutoDoc extracts the value of the PackageDoc.BookName component and then passes that on to GAPDoc when creating the HTML, PDF and text versions of the manual.

AutoDoc

This is a record which can be used to control the scaffolding performed by AutoDoc, specifically to provide extra information for the title page. For example, you can set AutoDoc.TitlePage.Copyright to a string which will then be inserted on the generated title page. Using this method you can customize the following title page elements: TitleComment, Abstract, Copyright, Acknowledgements and Colophon.

Note that AutoDoc.TitlePage behaves exactly the same as the scaffold.TitlePage parameter of the AutoDoc (4.1-1) function.

1.5 AutoDoc worksheets

AutoDoc worksheets can be used to create HTML and PDF documents using AutoDoc syntax and possibly including GAP examples and implementations without having them associated to a package. A file for a worksheet could look like this:

#! @Title My first worksheet
#! @Author Charlie Brown

#! @Chapter Some groups

#! @BeginExample
S3 := SymmetricGroup( 3 );;
S4 := SymmetricGroup( 4 );;
#! @EndExample

Now, one can create a PDF and HTML document, like a package documentation out of it. Suppose the document above is saved as worksheet.g. Then, when GAP is started in the directory of this file, the command

AutoDocWorksheet( "worksheet.g" );

will create a subdirectory called doc of the current directory in which it will create the documentation. There are several options to configure the output of the worksheet command, which are identical to the options of the AutoDoc (4.1-1) command. It is even possible to test the examples in the worksheet using the extract_examples option of the AutoDoc (4.1-1) command.

Since the worksheets do not have a PackageInfo.g to extract information, all possible tags that GAPDoc supports for the title page can be set into the document. A fully typed title page can look like this:

#! @Title My first worksheet
#! @Subtitle Some small examples
#! @Author Charlie Brown

#! @Version 0.1
#! @TitleComment Some worksheet
#! @Date 01/01/2016
#! @Address TU Kaiserslautern
#! @Abstract
#!  A worksheet showing some small examples about groups.
#! @Copyright 2016 Charlie Brown
#! @Acknowledgements Woodstock
#! @Colophon Some colophon

#! @Chapter Some groups

#! @BeginExample
S3 := SymmetricGroup( 3 );;
S4 := SymmetricGroup( 4 );;
#! @EndExample
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/title.xml000644 000766 000024 00000002663 14444021275 016365 0ustar00mhornstaff000000 000000 AutoDoc Generate documentation from &GAP; source code 2023.06.19 Sebastian Gutsche
Department Mathematik
Universität Siegen
Walter-Flex-Straße 3
57072 Siegen
Germany
gutsche@mathematik.uni-siegen.de https://algebra.mathematik.uni-siegen.de/gutsche/
Max Horn
Fachbereich Mathematik
RPTU Kaiserslautern-Landau
Gottlieb-Daimler-Straße 48
67663 Kaiserslautern
Germany
mhorn@rptu.de https://www.quendi.de/math
19 June 2023 &AutoDoc; is a &GAP; package whose purpose is to aid &GAP; package authors in creating and maintaining the documentation of their packages. ©right; 2012-2022 by Sebastian Gutsche and Max Horn

This package may be distributed under the terms and conditions of the GNU Public License Version 2 or (at your option) any later version. This documentation was prepared using the &GAPDoc; package .

AutoDoc-2023.06.19/doc/manual.js000644 000766 000024 00000010113 14444021302 016311 0ustar00mhornstaff000000 000000 /* manual.js Frank Lübeck */ /* This file contains a few javascript functions which allow to switch between display styles for GAPDoc HTML manuals. If javascript is switched off in a browser or this file in not available in a manual directory, this is no problem. Users just cannot switch between several styles and don't see the corresponding button. A style with name mystyle can be added by providing two files (or only one of them). mystyle.js: Additional javascript code for the style, it is read in the HTML pages after this current file. The additional code may adjust the preprocessing function jscontent() with is called onload of a file. This is done by appending functions to jscontentfuncs (jscontentfuncs.push(newfunc);). Make sure, that your style is still usable without javascript. mystyle.css: CSS configuration, read after manual.css (so it can just reconfigure a few details, or overwrite everything). Then adjust chooser.html such that users can switch on and off mystyle. A user can change the preferred style permanently by using the [Style] link and choosing one. Or one can append '?GAPDocStyle=mystyle' to the URL when loading any file of the manual (so the style can be configured in the GAP user preferences). */ /* generic helper function */ function deleteCookie(nam) { document.cookie = nam+"=;Path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT"; } /* read a value from a "nam1=val1;nam2=val2;..." string (e.g., the search part of an URL or a cookie */ function valueString(str,nam) { var cs = str.split(";"); for (var i=0; i < cs.length; i++) { var pos = cs[i].search(nam+"="); if (pos > -1) { pos = cs[i].indexOf("="); return cs[i].slice(pos+1); } } return 0; } /* when a non-default style is chosen via URL or a cookie, then the cookie is reset and the styles .js and .css files are read */ function overwriteStyle() { /* style in URL? */ var style = valueString(window.location.search, "GAPDocStyle"); /* otherwise check cookie */ if (style == 0) style = valueString(document.cookie, "GAPDocStyle"); if (style == 0) return; if (style == "default") deleteCookie("GAPDocStyle"); else { /* ok, we set the cookie for path "/" */ var path = "/"; /* or better like this ??? var here = window.location.pathname.split("/"); for (var i=0; i+3 < here.length; i++) path = path+"/"+here[i]; */ document.cookie = "GAPDocStyle="+style+";Path="+path; /* split into names of style files */ var stlist = style.split(","); /* read style's css and js files */ for (var i=0; i < stlist.length; i++) { document.writeln(''); document.writeln(''); } } } /* this adds a "[Style]" link next to the MathJax switcher */ function addStyleLink() { var line = document.getElementById("mathjaxlink"); var el = document.createElement("a"); var oncl = document.createAttribute("href"); var back = window.location.protocol+"//" if (window.location.protocol == "http:" || window.location.protocol == "https:") { back = back+window.location.host; if (window.location.port != "") { back = back+":"+window.location.port; } } back = back+window.location.pathname; oncl.nodeValue = "chooser.html?BACK="+back; el.setAttributeNode(oncl); var cont = document.createTextNode(" [Style]"); el.appendChild(cont); line.appendChild(el); } var jscontentfuncs = new Array(); jscontentfuncs.push(addStyleLink); /* the default jscontent() only adds the [Style] link to the page */ function jscontent () { for (var i=0; i < jscontentfuncs.length; i++) jscontentfuncs[i](); } AutoDoc-2023.06.19/doc/bib.xml.bib000644 000766 000024 00000001233 14444021275 016523 0ustar00mhornstaff000000 000000 @manual{ GAPDoc, author = {L{\"u}beck, F. and Neunh{\"o}ffer, M.}, title = {{GAPDoc (Version 1.5.1)}}, organization = {RWTH Aachen}, year = {2012}, note = {GAP package, \href {http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html} {\texttt{http://www.math.rwth-aachen.de/}\discretionary {}{}{}\texttt{\texttt{\symbol{126}}Frank.Luebeck/}\discretionary {}{}{}\texttt{GAPDoc/}\discretionary {}{}{}\texttt{index.html}}}, printedkey = {LN12} } AutoDoc-2023.06.19/doc/chapInd.html000644 000766 000024 00000016407 14444021302 016746 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Index

Goto Chapter: Top 1 2 3 4 Bib Ind

Index

@Arguments args 2.1-3
@BeginChunk name 2.2-14
@BeginCode name 2.2-15
@BeginExample 2.2-9
@BeginExampleSession 2.2-10
@BeginGroup 2.2-4
@BeginLatexOnly 2.2-16
@BeginLog 2.2-11
@BeginLogSession 2.2-12
@BeginNotLatex 2.2-17
@Chapter 2.2-1
@ChapterInfo 2.1-8
@ChapterLabel 2.2-1
@ChapterTitle 2.2-1
@Description descr 2.1-1
@DoNotReadRestOfFile 2.2-13
@InsertChunk name 2.2-14
@EndChunk 2.2-14
@EndCode 2.2-15
@EndExample 2.2-9
@EndExampleSession 2.2-10
@EndGroup 2.2-5
@EndLatexOnly 2.2-16
@EndLog 2.2-11
@EndLogSession 2.2-12
@EndNotLatex 2.2-17
@Group grpname 2.1-4
@GroupTitle 2.2-6
@InsertCode name 2.2-15
@Label label 2.1-5
@LatexOnly text 2.2-16
@Level 2.2-7
@NotLatex text 2.2-17
@ResetLevel 2.2-8
@Returns ret_val 2.1-2
@Section 2.2-2
@SectionLabel 2.2-2
@SectionTitle 2.2-2
@Subsection 2.2-3
@SubsectionLabel 2.2-3
@SubsectionTitle 2.2-3
1.3-3 1.3-3
AProperty, for IsObject 2.1-7
    testlabel 2.1-6
AutoDoc 4.1-1
AutoDocWorksheet 3.1-1
1.3-3 1.3-3 1.3-3
FirstOperation, for IsInt 2.5-1
1.3-3
makedoc.g 1.1
1.3-3
SecondOperation, for IsInt, IsGroup 2.5-1
ThirdOperation, for IsGroup, IsInt 2.5-1

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chap3_mj.html000644 000766 000024 00000007351 14444021302 017062 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 3: AutoDoc worksheets
Goto Chapter: Top 1 2 3 4 Bib Ind

3 AutoDoc worksheets

3.1 Worksheets

3.1-1 AutoDocWorksheet
‣ AutoDocWorksheet( list_of_filenames: options )( function )

The intention of these function is to create stand-alone pdf and html files using AutoDoc without having them associated to a package. It uses the same optional records as the AutoDoc command itself, but instead of a package name there should be a filename or a list of filenames containing AutoDoc text from which the documents are created. Please see the AutoDoc command for more information about this and have a look at 1.5 for a simple worksheet example.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/bib.xml000644 000766 000024 00000001012 14444021247 015762 0ustar00mhornstaff000000 000000 FrankLübeck MaxNeunhöffer <C>GAPDoc (Version 1.5.1)</C> RWTH Aachen 2012 GAP package, http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html AutoDoc-2023.06.19/doc/chapInd.txt000644 000766 000024 00000004011 14444021275 016616 0ustar00mhornstaff000000 000000 Index @Arguments args 2.1-3 @BeginChunk name 2.2-14 @BeginCode name 2.2-15 @BeginExample 2.2-9 @BeginExampleSession 2.2-10 @BeginGroup 2.2-4 @BeginLatexOnly 2.2-16 @BeginLog 2.2-11 @BeginLogSession 2.2-12 @BeginNotLatex 2.2-17 @Chapter 2.2-1 @ChapterInfo 2.1-8 @ChapterLabel 2.2-1 @ChapterTitle 2.2-1 @Description descr 2.1-1 @DoNotReadRestOfFile 2.2-13 @InsertChunk name 2.2-14 @EndChunk 2.2-14 @EndCode 2.2-15 @EndExample 2.2-9 @EndExampleSession 2.2-10 @EndGroup 2.2-5 @EndLatexOnly 2.2-16 @EndLog 2.2-11 @EndLogSession 2.2-12 @EndNotLatex 2.2-17 @Group grpname 2.1-4 @GroupTitle 2.2-6 @InsertCode name 2.2-15 @Label label 2.1-5 @LatexOnly text 2.2-16 @Level 2.2-7 @NotLatex text 2.2-17 @ResetLevel 2.2-8 @Returns ret_val 2.1-2 @Section 2.2-2 @SectionLabel 2.2-2 @SectionTitle 2.2-2 @Subsection 2.2-3 @SubsectionLabel 2.2-3 @SubsectionTitle 2.2-3 1.3-3 1.3-3 AProperty, for IsObject 2.1-7 testlabel 2.1-6 AutoDoc 4.1-1 AutoDocWorksheet 3.1-1 1.3-3 1.3-3 1.3-3 FirstOperation, for IsInt 2.5-1 1.3-3 makedoc.g 1.1 1.3-3 SecondOperation, for IsInt, IsGroup 2.5-1 ThirdOperation, for IsGroup, IsInt 2.5-1 ------------------------------------------------------- AutoDoc-2023.06.19/doc/_Chunks.xml000644 000766 000024 00000000000 14444021275 016615 0ustar00mhornstaff000000 000000 AutoDoc-2023.06.19/doc/chap4.html000644 000766 000024 00000053120 14444021302 016370 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 4: AutoDoc
Goto Chapter: Top 1 2 3 4 Bib Ind

4 AutoDoc

4.1 The AutoDoc() function

4.1-1 AutoDoc
‣ AutoDoc( [packageOrDirectory][,] [optrec] )( function )

Returns: nothing

This is the main function of the AutoDoc package. It can perform any combination of the following tasks:

  1. It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in GAPDoc format to be used as part of your manual: First, a file named doc/PACKAGENAME.xml (with your package's name substituted) which is used as main XML file for the package manual, i.e. this file sets the XML doctype and defines various XML entities, includes other XML files (both those generated by AutoDoc as well as additional files created by other means), tells GAPDoc to generate a table of contents and an index, and more. Secondly, it creates a file doc/title.xml containing a title page for your documentation, with information about your package (name, description, version), its authors and more, based on the data in your PackageInfo.g.

  2. It can scan your package for AutoDoc based documentation (by using AutoDoc tags and the Autodoc command. This will produce further XML files to be used as part of the package manual.

  3. It can use GAPDoc to generate PDF, text and HTML (with MathJaX enabled) documentation from the GAPDoc XML files it generated as well as additional such files provided by you. For this, it invokes MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc) to convert the XML sources, and it also instructs GAPDoc to copy supplementary files (such as CSS style files) into your doc directory (see CopyHTMLStyleFiles (GAPDoc: CopyHTMLStyleFiles)).

For more information and some examples, please refer to Chapter 1.

The parameters have the following meanings:

packageOrDirectory

The purpose of this parameter is twofold: to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. The parameter is either a string, an IsDirectory object, or omitted. If it is a string, AutoDoc interprets it as the name of a package, uses the metadata of the first package known to GAP with that name, and uses the InstallationPath specified in that metadata as the package directory. If packageOrDirectory is an IsDirectory object, this is used as package directory; if the argument is omitted, then the current directory is used. In the last two cases, the specified directory must contain a PackageInfo.g file, and AutoDoc extracts all needed metadata from that. The IsDirectory form is for example useful if you have multiple versions of the package around and want to make sure the documentation of the correct version is built.

Note that when using AutoDocWorksheet (see 3.1), there is no parameter corresponding to packageOrDirectory and so the "package directory" is always the current directory, and there is no metadata.

optrec

optrec can be a record with some additional options. The following are currently supported:

dir

This should either be a string, in which case it must be a path relative to the specified package directory, or a Directory() object. (Thus, the only way to designate an absolute directory is with a Directory() object.) This option specifies where the package documentation (e.g. the GAPDoc XML or the manual PDF, etc.) files are stored and/or will be generated.
Default value: "doc/".

scaffold

This controls whether and how to generate scaffold XML files for the package documentation.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.scaffold is missing but the package's info record in PackageInfo.g has an AutoDoc entry. In all other cases (in particular if opt.scaffold is false), scaffolding is disabled.

If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings.

If opt.scaffold is a record, it may contain the following entries.

includes

A list of XML files to be included in the body of the main XML file. If you specify this list and also are using AutoDoc to document your operations with AutoDoc comments, you can add _AutoDocMainFile.xml to this list to control at which point the documentation produced by AutoDoc is inserted. If you do not do this, it will be added after the last of your own XML files.

index

By default, the scaffold creates an index. If you do not want an index, set this to false.

appendix

This entry is similar to opt.scaffold.includes but is used to specify files to include after the main body of the manual, i.e. typically appendices.

bib

The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file doc/PACKAGENAME.bib then it is assumed that you want to use this as your bibliography.

entities

A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record "SomePackage",

             rec( SomePackage := "<Package>SomePackage</Package>",
                  RELEASEYEAR := "2015" )

then the following entity definitions are added to the XML preamble:

<!ENTITY SomePackage '<Package>SomePackage</Package>'>
             <!ENTITY RELEASEYEAR '2015'>

This allows you to write "&SomePackage;" and "&RELEASEYEAR;" in your documentation, which will be replaced by respective values specified in the entities definition.

TitlePage

A record whose entries are used to embellish the generated title page for the package manual with extra information, such as a copyright statement or acknowledgments. To this end, the names of the record components are used as XML element names, and the values of the components are outputted as content of these XML elements. For example, you could pass the following record to set a custom acknowledgements text:

             rec( Acknowledgements := "Many thanks to ..." )

For a list of valid entries in the title page, please refer to the GAPDoc manual, specifically section GAPDoc: TitlePage.

MainPage

If scaffolding is enabled, by default a main XML file is generated (this is the file which contains the XML doctype and more). If you do not want this (e.g. because you have a handwritten main XML file), but still want AutoDoc to generate a title page for you, you can set this option to false

document_class

Sets the document class of the resulting PDF. The value can either be a string which has to be the name of the new document class, a list containing this string, or a list of two strings. Then the first one has to be the document class name, the second one the option string ( contained in [ ] ) in LaTeX.

latex_header_file

Replaces the standard header from GAPDoc completely with the header in this LaTeX file. Please be careful here, and look at GAPDoc's latexheader.tex file for an example.

autodoc

This controls whether and how to generate additional XML documentation files by scanning for AutoDoc documentation comments.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.autodoc is missing but the package depends (directly) on the AutoDoc package. In all other cases (in particular if opt.autodoc is false), this feature is disabled.

If opt.autodoc is a record, it may contain the following entries.

files

A list of files (given by paths relative to the package directory) to be scanned for AutoDoc documentation comments. Usually it is more convenient to use autodoc.scan_dirs, see below.

scan_dirs

A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].

level

This defines the level of the created documentation. The default value is 0. When parts of the manual are declared with a higher value they will not be printed into the manual.

gapdoc

This controls whether and how to invoke GAPDoc to create HTML, PDF and text files from your various XML files.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.gapdoc is missing. In all other cases (in particular if opt.gapdoc is false), this feature is disabled.

If opt.gapdoc is a record, it may contain the following entries.

main

The name of the main XML file of the package manual. This exists primarily to support packages with existing manual which use a filename here which differs from the default. In particular, specifying this is unnecessary when using scaffolding.
Default value: PACKAGENAME.xml.

files

A list of files (given by paths relative to the package directory) to be scanned for GAPDoc documentation comments. Usually it is more convenient to use gapdoc.scan_dirs, see below.

scan_dirs

A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].

LaTeXOptions

Must be a record with entries which can be understood by SetGapDocLaTeXOptions (GAPDoc: SetGapDocLaTeXOptions). Each entry can be a string, which will be given to GAPDoc directly, or a list containing of two entries: The first one must be the string "file", the second one a filename. This file will be read and then its content is passed to GAPDoc as option with the name of the entry.

gap_root_relative_path

Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to false), references in the generated documentation referring to external documentation (such as the GAP manual) are encoded using absolute paths. This is fine as long as the documentation stays on only a single computer, but is problematic when preparing documentation that should be used on multiple computers, e.g., when creating a distribution archive of a GAP package.
Thus, if a relative path is provided via this option (or if it is set to true, in which case the relative path ../../.. is used), then AutoDoc and GAPDoc attempt to replace all absolute paths in references to GAP manuals by paths based on this relative path.

On a technical level, AutoDoc passes the relative path to the gaproot parameter of MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc)

extract_examples

Either true or a record. If set to true, then all manual examples are extracted and placed into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... and so on, with one file for each chapter. For chapters with no examples, no file is created.

As a record, the entry can have the following entries itself, to specify some options.

units

This controls how examples are grouped into files. Recognized values are "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, one file is created for each chapter, each section, each subsection or each example. For all other values only a single file is created.

On a technical level, AutoDoc passes the value to the units parameter of ExtractExamples (GAPDoc: ExtractExamples).

skip_empty_in_numbering

If set to true (the default), the generated files use filenames with strictly sequential numbering; that means that if chapter 1 (or whatever units are being used) contains no examples but chapter 2 does, then the examples for chapter 2 are put into the file tst/PACKAGENAME01.tst. If this option is set to false, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file tst/PACKAGENAME02.tst.

maketest

This option is deprecated. Please use extract_examples instead.

Either true or a record. When it is true, a simple maketest.g file is created in the main package directory, which can be used to test the examples from the manual. As a record, the entry can have the following entries itself, to specify some options.

filename

Sets the name of the test file.

commands

A list of strings, each one a command, which will be executed at the beginning of the test file.

4.2 Examples

Some basic examples for using AutoDoc were already shown in Chapter 1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/Comments.xml000644 000766 000024 00000063540 14444021247 017031 0ustar00mhornstaff000000 000000 &AutoDoc; documentation comments You can document declarations of global functions and variables, operations, attributes etc. by inserting &AutoDoc; comments into your sources before these declaration. An &AutoDoc; comment always starts with #!. This is also the smallest possible &AutoDoc; command. If you want your declaration documented, just write #! at the line before the documentation. For example: This will produce a manual entry for the operation AnOperation.

Inside of &AutoDoc; comments, &AutoDoc; commands starting with @ can be used to control the output &AutoDoc; produces.

Documenting declarations In the bare form above, the manual entry for AnOperation will not contain much more than the name of the operation. In order to change this, there are several commands you can put into the &AutoDoc; comment before the declaration. Currently, the following commands are provided: @Description descr @Description descr Adds the text in the following lines of the &AutoDoc; to the description of the declaration in the manual. Lines are until the next &AutoDoc; command or until the declaration is reached. @Returns ret_val @Returns ret_val The string ret_val is added to the documentation, with the text Returns: put in front of it. This should usually give a brief hint about the type or meaning of the value returned by the documented function. @Arguments args @Arguments args The string args contains a description of the arguments the function expects, including optional parts, which are denoted by square brackets. The argument names can be separated by whitespace, commas or square brackets for the optional arguments, like grp[, elm] or xx[y[z] ]. If &GAP; options are used, this can be followed by a colon : and one or more assignments, like n[, r]: tries := 100. @Group grpname @Group grpname Adds the following method to a group with the given name. See section for more information about groups. @Label label @Label label Adds label to the function as label. If this is not specified, then for declarations that involve a list of input filters (as is the case for DeclareOperation, DeclareAttribute, etc.), a default label is generated from this filter list. leads to this: true or false while leads to this: true or false @ChapterInfo @ChapterInfo chapter, section Adds the entry to the given chapter and section. Here, chapter and section are the respective titles. As an example, a full &AutoDoc; comment with all options could look like this: modtbl #! and underlying ordinary character table `ordtbl`. #! @Returns a list #! @Arguments modtbl #! @Group CharacterDegreesOfBlocks #! @Label chardegblocks #! @ChapterInfo Blocks, Attributes DeclareAttribute( "CharacterDegreesOfBlocks", IsBrauerTable ); ]]>
Other documentation comments There are also some commands which can be used in &AutoDoc; comments that are not associated to any declaration. This is useful for additional text in your documentation, examples, mathematical chapters, etc.. @Chapter @ChapterLabel @ChapterTitle @Chapter name Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their &AutoDoc; comment via @ChapterInfo will be added to this chapter. Also all text comments, i.e. lines that begin with #! without a command, and which do not follow after @Description, will be added to the chapter as regular text. Additionally, the chapters label will be set to Chapter_name. Example: The @ChapterLabel label command can be used to set the label of the chapter to Chapter_label instead of Chapter_name. Additionally, the chapter will be stored as _Chapter_label.xml. The @ChapterTitle title command can be used to set a heading for the chapter that is different from name. Note that the title does not affect the label. If you use all three commands, i.e., title is used for the headline, label for cross-referencing, and name for setting the same chapter as active chapter again. @Section @SectionLabel @SectionTitle @Section name Sets an active section like @Chapter sets an active chapter. The section automatically ends with the next @Section or @Chapter command. The @SectionLabel label command can be used to set the label of the section to Section_label instead of Chapter_chaptername_Section_name. The @SectionTitle title command can be used to set a heading for the section that is different from name. @Subsection @SubsectionLabel @SubsectionTitle @Subsection name Sets an active subsection like @Section sets an active section. The subsection automatically ends with the next @Subsection, @Section or @Chapter command. It also ends with the next documented function. Indeed, internally each function manpage is treated like a subsection. The @SubsectionLabel label command can be used to set the label of the subsection to Subsection_label instead of Chapter_chaptername_Section_sectionname_Subsection_name. The @SubsectionTitle title command can be used to set a heading for the subsection that is different from name. @BeginGroup @BeginGroup [grpname] Starts a group. All following documented declarations without an explicit @Group command are grouped together in the same group with the given name. If no name is given, then a new nameless group is generated. The effect of this command is ended when an @EndGroup command is reached.

See section for more information about groups. @EndGroup @EndGroup Ends the current group.

@GroupTitle @GroupTitle title Sets the subsection heading for the current group to title. In the absence of any @GroupTitle command, the heading will be the name of the first entry in the group. See for more information. @Level @Level lvl Sets the current level of the documentation. All items created after this, chapters, sections, and items, are given the level lvl, until the @ResetLevel command resets the level to 0 or another level is set.

See section for more information about levels. @ResetLevel @ResetLevel Resets the current level to 0.

@BeginExample @EndExample @BeginExample and @EndExample @BeginExample marks the start of an example to be put into the manual. It differs from &GAPDoc;'s <Example> (see ), in that it expects actual code (not in a comment) interspersed with comments, to allow for examples files that can be both executed by &GAP;, and parsed by &AutoDoc;. To achieve this, &GAP; commands are not preceded by a comment, while output has to be preceded by an &AutoDoc; comment. The gap> prompt for the display in the manual is added by &AutoDoc;. @EndExample ends the example block.

To illustrate this command, consider this input:

This results in the following output: gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120 The &AutoDoc; command @Example is an alias of @BeginExample.
@BeginExampleSession @EndExampleSession @BeginExampleSession and @EndExampleSession @BeginExampleSession marks the start of an example to be put into the manual, while @EndExampleSession ends the example block. It is the direct analog of &GAPDoc;'s <Example> (see ).

To illustrate this command, consider this input:

S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) #! gap> Order(S5); #! 120 #! @EndExampleSession ]]> This results in the following output: gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120 It inserts an example into the manual just as @Example would do, but all lines are commented and therefore not executed when the file is read. All lines that should be part of the example displayed in the manual have to start with an &AutoDoc; comment (#!). The comment will be removed, and, if the following character is a space, this space will also be removed. There is never more than one space removed. To ensure examples are correctly colored in the manual, there should be exactly one space between #! and the gap> prompt. The &AutoDoc; command @ExampleSession is an alias of @BeginExampleSession.
@BeginLog @EndLog @BeginLog and @EndLog Works just like the @BeginExample command, but the example will not be tested. See the &GAPDoc; manual for more information. The &AutoDoc; command @Log is an alias of @BeginLog. @BeginLogSession @EndLogSession @BeginLogSession and @EndLogSession Works just like the @BeginExampleSession command, but the example will not be tested if manual examples are run. It is the direct analog of &GAPDoc;'s <Log> (see ). The &AutoDoc; command @LogSession is an alias of @BeginLogSession. @DoNotReadRestOfFile @DoNotReadRestOfFile Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files. @BeginChunk name @EndChunk @InsertChunk name @BeginChunk name, @EndChunk, and @InsertChunk name Text inside a @BeginChunk / @EndChunk part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. That chunk of text can then later on be inserted in any other place by using the @InsertChunk name command. If you do not provide an @EndChunk, the chunk ends at the end of the file. You can use this to define an example like this in one file: And then later, insert the example in a different file, like this: @BeginCode name @EndCode @InsertCode name @BeginCode name, @EndCode, and @InsertCode name Inserts the text between @BeginCode and @EndCode verbatim at the point where @InsertCode is called. This is useful to insert code excerpts directly into the manual. @LatexOnly text @BeginLatexOnly @EndLatexOnly @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly Code inserted between @BeginLatexOnly and @EndLatexOnly or after @LatexOnly is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary &LaTeX;-commands. @NotLatex text @BeginNotLatex @EndNotLatex @NotLatex text, @BeginNotLatex, and @EndNotLatex Code inserted between @BeginNotLatex and @EndNotLatex or after @NotLatex is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version.
Title page commands The following commands can be used to add the corresponding parts to the title page of the document which generated by &AutoDoc; if scaffolding is enabled. @Title @Subtitle @Version @TitleComment @Author @Date @Address @Abstract @Copyright @Acknowledgements @Colophon Those add the following lines at the corresponding point of the title page. Please note that many of those things can be (better) extracted from the PackageInfo.g. In case you set some of those, the extracted or in scaffold defined items will be overwritten. While this is not very useful for documenting packages, they are necessary for worksheets created with , since worksheets do not have a PackageInfo.g file from which this information could be extracted.
Plain text files Files that have the suffix .autodoc and are listed in the autodoc.files option of , resp. are contained in one of the directories listed in autodoc.scan_dirs, are treated as &AutoDoc; plain text files. These work exactly like &AutoDoc; comments, except that lines do not need to (and in fact, should not) start with #!.
Grouping In &GAPDoc;, it is possible to make groups of manual items, i.e., when documenting a function, operation, etc., it is possible to group them into suitable chunks. This can be particularly useful if there are several definitions of an operation with several different argument types, all doing more or less the same to the arguments. Then their manual items can be grouped, sharing the same description and return type information. You can give a heading to the group in the manual with the @GroupTitle command; if that is not supplied, then the heading of the first manual item in the group will be used as the heading.

Note that group names are globally unique throughout the whole manual. That is, groups with the same name are in fact merged into a single group, even if they were declared in different source files. Thus you can have multiple @BeginGroup / @EndGroup pairs using the same group name, in different places, and these all will refer to the same group.

Moreover, this means that you can add items to a group via the @Group command in the &AutoDoc; comment of an arbitrary declaration, at any time.

The following code

produces the following: A family of operations First sentence. Second sentence. Third sentence.
Level Levels can be set to not write certain parts in the manual by default. Every entry has by default the level 0. The command @Level can be used to set the level of the following part to a higher level, for example 1, and prevent it from being printed to the manual by default. However, if one sets the level to a higher value in the autodoc option of &AutoDoc;, the parts will be included in the manual at the specific place.
Markdown-like formatting of text in &AutoDoc; &AutoDoc; has some convenient ways to insert special format into text, like math formulas and lists. The syntax for them are inspired by Markdown and &LaTeX;, but do not follow them strictly. Neither are all features of the Markdown language supported. The following subsections describe what is possible. Lists One can create lists of items by beginning a new line with *, +, -, followed by one space. The first item starts the list. When items are longer than one line, the following lines have to be indented by at least two spaces. The list ends when a line which does not start a new item is not indented by two spaces. Of course lists can be nested. Here is an example: This is the output:
The list starts in the next line item 1 item 2 which is a bit longer and also contains a nested list with two items item 3 of the outer list This does not belong to the list anymore.
The *, -, and + are fully interchangeable and can even be used mixed, but this is not recommended.
Math modes One can start an inline formula with a $, and also end it with $, just like in &LaTeX;. This will translate into &GAPDoc;s inline math environment. For display mode one can use $$, also like &LaTeX;. produces the following output:
This is an inline formula: 1+1 = 2. This is a display formula: \sum_{i=1}^n i.
Emphasize One can emphasize text by using two asterisks (**) or two underscores (__) at the beginning and the end of the text which should be emphasized. Example: This produces the following output:
This is very important. This is also important. Naturally, more than one line can be important.
Inline code One can mark inline code snippets by using backticks (`) at the beginning and the end of the text which should be marked as code. Example: This produces the following output:
Call function foobar() at the start.
Deprecated commands The following commands used to be supported, but should not generally be used anymore. They will be removed in a future version of &AutoDoc;. @EndSection You can simply remove any use of this, &AutoDoc; ends sections automatically at the start of any new section or chapter. @EndSubsection You can simply remove any use of this, &AutoDoc; ends subsections automatically at the start of any new subsection, section or chapter. @BeginAutoDoc and @EndAutoDoc It suffices to prepend each declaration that is meant to be appear in the manual with a minimal &AutoDoc; comment #!. @BeginSystem name, @EndSystem, and @InsertSystem name Please use the chunk commands from subsection instead. @AutoDocPlainText and @EndAutoDocPlainText Use .autodoc files or &AutoDoc; comments instead.
AutoDoc-2023.06.19/doc/_Chapter_AutoDoc.xml000644 000766 000024 00000042763 14444021275 020414 0ustar00mhornstaff000000 000000 AutoDoc
The AutoDoc() function nothing This is the main function of the &AutoDoc; package. It can perform any combination of the following tasks: It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in &GAPDoc; format to be used as part of your manual: First, a file named doc/PACKAGENAME.xml (with your package's name substituted) which is used as main XML file for the package manual, i.e. this file sets the XML doctype and defines various XML entities, includes other XML files (both those generated by &AutoDoc; as well as additional files created by other means), tells &GAPDoc; to generate a table of contents and an index, and more. Secondly, it creates a file doc/title.xml containing a title page for your documentation, with information about your package (name, description, version), its authors and more, based on the data in your PackageInfo.g. It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; tags and the Autodoc command. This will produce further XML files to be used as part of the package manual. It can use &GAPDoc; to generate PDF, text and HTML (with MathJaX enabled) documentation from the &GAPDoc; XML files it generated as well as additional such files provided by you. For this, it invokes to convert the XML sources, and it also instructs &GAPDoc; to copy supplementary files (such as CSS style files) into your doc directory (see ). For more information and some examples, please refer to Chapter .

The parameters have the following meanings: packageOrDirectory The purpose of this parameter is twofold: to determine the package directory in which &AutoDoc; will operate, and to find the metadata concerning the package being documented. The parameter is either a string, an IsDirectory object, or omitted. If it is a string, &AutoDoc; interprets it as the name of a package, uses the metadata of the first package known to &GAP; with that name, and uses the InstallationPath specified in that metadata as the package directory. If packageOrDirectory is an IsDirectory object, this is used as package directory; if the argument is omitted, then the current directory is used. In the last two cases, the specified directory must contain a PackageInfo.g file, and &AutoDoc; extracts all needed metadata from that. The IsDirectory form is for example useful if you have multiple versions of the package around and want to make sure the documentation of the correct version is built.

Note that when using AutoDocWorksheet (see ), there is no parameter corresponding to packageOrDirectory and so the package directory is always the current directory, and there is no metadata. optrec optrec can be a record with some additional options. The following are currently supported: dir This should either be a string, in which case it must be a path relative to the specified package directory, or a Directory() object. (Thus, the only way to designate an absolute directory is with a Directory() object.) This option specifies where the package documentation (e.g. the &GAPDoc; XML or the manual PDF, etc.) files are stored and/or will be generated.
Default value: "doc/".
scaffold This controls whether and how to generate scaffold XML files for the package documentation.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.scaffold is missing but the package's info record in PackageInfo.g has an AutoDoc entry. In all other cases (in particular if opt.scaffold is false), scaffolding is disabled.

If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings.

If opt.scaffold is a record, it may contain the following entries.

includes A list of XML files to be included in the body of the main XML file. If you specify this list and also are using &AutoDoc; to document your operations with &AutoDoc; comments, you can add _AutoDocMainFile.xml to this list to control at which point the documentation produced by &AutoDoc; is inserted. If you do not do this, it will be added after the last of your own XML files. index By default, the scaffold creates an index. If you do not want an index, set this to false. appendix This entry is similar to opt.scaffold.includes but is used to specify files to include after the main body of the manual, i.e. typically appendices. bib The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file doc/PACKAGENAME.bib then it is assumed that you want to use this as your bibliography. entities A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record SomePackage,

SomePackage", RELEASEYEAR := "2015" )]]> then the following entity definitions are added to the XML preamble: SomePackage'> ]]> This allows you to write &SomePackage; and &RELEASEYEAR; in your documentation, which will be replaced by respective values specified in the entities definition. TitlePage A record whose entries are used to embellish the generated title page for the package manual with extra information, such as a copyright statement or acknowledgments. To this end, the names of the record components are used as XML element names, and the values of the components are outputted as content of these XML elements. For example, you could pass the following record to set a custom acknowledgements text: For a list of valid entries in the title page, please refer to the &GAPDoc; manual, specifically section . MainPage If scaffolding is enabled, by default a main XML file is generated (this is the file which contains the XML doctype and more). If you do not want this (e.g. because you have a handwritten main XML file), but still want &AutoDoc; to generate a title page for you, you can set this option to false document_class Sets the document class of the resulting PDF. The value can either be a string which has to be the name of the new document class, a list containing this string, or a list of two strings. Then the first one has to be the document class name, the second one the option string ( contained in [ ] ) in &LaTeX;. latex_header_file Replaces the standard header from &GAPDoc; completely with the header in this &LaTeX; file. Please be careful here, and look at &GAPDoc;'s latexheader.tex file for an example. autodoc This controls whether and how to generate additional XML documentation files by scanning for &AutoDoc; documentation comments.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.autodoc is missing but the package depends (directly) on the &AutoDoc; package. In all other cases (in particular if opt.autodoc is false), this feature is disabled.

If opt.autodoc is a record, it may contain the following entries.

files A list of files (given by paths relative to the package directory) to be scanned for &AutoDoc; documentation comments. Usually it is more convenient to use autodoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for &AutoDoc; documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].
level This defines the level of the created documentation. The default value is 0. When parts of the manual are declared with a higher value they will not be printed into the manual.
gapdoc This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text files from your various XML files.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.gapdoc is missing. In all other cases (in particular if opt.gapdoc is false), this feature is disabled.

If opt.gapdoc is a record, it may contain the following entries.

main The name of the main XML file of the package manual. This exists primarily to support packages with existing manual which use a filename here which differs from the default. In particular, specifying this is unnecessary when using scaffolding.
Default value: PACKAGENAME.xml.
files A list of files (given by paths relative to the package directory) to be scanned for &GAPDoc; documentation comments. Usually it is more convenient to use gapdoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans for .gi, .gd and .g files; all of these files are then scanned for &GAPDoc; documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].
LaTeXOptions Must be a record with entries which can be understood by . Each entry can be a string, which will be given to &GAPDoc; directly, or a list containing of two entries: The first one must be the string "file", the second one a filename. This file will be read and then its content is passed to &GAPDoc; as option with the name of the entry. gap_root_relative_path Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to false), references in the generated documentation referring to external documentation (such as the &GAP; manual) are encoded using absolute paths. This is fine as long as the documentation stays on only a single computer, but is problematic when preparing documentation that should be used on multiple computers, e.g., when creating a distribution archive of a &GAP; package.
Thus, if a relative path is provided via this option (or if it is set to true, in which case the relative path ../../.. is used), then &AutoDoc; and &GAPDoc; attempt to replace all absolute paths in references to &GAP; manuals by paths based on this relative path.

On a technical level, &AutoDoc; passes the relative path to the gaproot parameter of

extract_examples Either true or a record. If set to true, then all manual examples are extracted and placed into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... and so on, with one file for each chapter. For chapters with no examples, no file is created.

As a record, the entry can have the following entries itself, to specify some options. units This controls how examples are grouped into files. Recognized values are "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, one file is created for each chapter, each section, each subsection or each example. For all other values only a single file is created.

On a technical level, &AutoDoc; passes the value to the units parameter of . skip_empty_in_numbering If set to true (the default), the generated files use filenames with strictly sequential numbering; that means that if chapter 1 (or whatever units are being used) contains no examples but chapter 2 does, then the examples for chapter 2 are put into the file tst/PACKAGENAME01.tst. If this option is set to false, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file tst/PACKAGENAME02.tst. maketest This option is deprecated. Please use extract_examples instead.

Either true or a record. When it is true, a simple maketest.g file is created in the main package directory, which can be used to test the examples from the manual. As a record, the entry can have the following entries itself, to specify some options. filename Sets the name of the test file. commands A list of strings, each one a command, which will be executed at the beginning of the test file.

Examples

Some basic examples for using AutoDoc were already shown in Chapter .

AutoDoc-2023.06.19/doc/nocolorprompt.css000644 000766 000024 00000000313 14444021302 020126 0ustar00mhornstaff000000 000000 /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000000; font-weight: normal; } span.GAPbrkprompt { color: #000000; font-weight: normal; } span.GAPinput { color: #000000; } AutoDoc-2023.06.19/doc/lefttoc.css000644 000766 000024 00000000474 14444021302 016661 0ustar00mhornstaff000000 000000 /* leftmenu.css Frank Lübeck */ /* Change default CSS to show section menu on left side */ body { padding-left: 28%; } body.chap0 { padding-left: 2%; } div.ChapSects div.ContSect:hover div.ContSSBlock { left: 15%; } div.ChapSects { left: 1%; width: 25%; } AutoDoc-2023.06.19/doc/chap2_mj.html000644 000766 000024 00000124440 14444021302 017060 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 2: AutoDoc documentation comments
Goto Chapter: Top 1 2 3 4 Bib Ind

2 AutoDoc documentation comments

You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declaration. An AutoDoc comment always starts with #!. This is also the smallest possible AutoDoc command. If you want your declaration documented, just write #! at the line before the documentation. For example:

#!
DeclareOperation( "AnOperation",
                  [ IsList ] );

This will produce a manual entry for the operation AnOperation.

Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces.

2.1 Documenting declarations

In the bare form above, the manual entry for AnOperation will not contain much more than the name of the operation. In order to change this, there are several commands you can put into the AutoDoc comment before the declaration. Currently, the following commands are provided:

2.1-1 @Description descr

Adds the text in the following lines of the AutoDoc to the description of the declaration in the manual. Lines are until the next AutoDoc command or until the declaration is reached.

2.1-2 @Returns ret_val

The string ret_val is added to the documentation, with the text "Returns: " put in front of it. This should usually give a brief hint about the type or meaning of the value returned by the documented function.

2.1-3 @Arguments args

The string args contains a description of the arguments the function expects, including optional parts, which are denoted by square brackets. The argument names can be separated by whitespace, commas or square brackets for the optional arguments, like "grp[, elm]" or "xx[y[z] ]". If GAP options are used, this can be followed by a colon : and one or more assignments, like "n[, r]: tries := 100".

2.1-4 @Group grpname

Adds the following method to a group with the given name. See section 2.5 for more information about groups.

2.1-5 @Label label

Adds label to the function as label. If this is not specified, then for declarations that involve a list of input filters (as is the case for DeclareOperation, DeclareAttribute, etc.), a default label is generated from this filter list.

#! @Label testlabel
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

2.1-6 AProperty
‣ AProperty( arg )( property )

Returns: true or false

while

#!
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

2.1-7 AProperty
‣ AProperty( arg )( property )

Returns: true or false

2.1-8 @ChapterInfo chapter, section

Adds the entry to the given chapter and section. Here, chapter and section are the respective titles.

As an example, a full AutoDoc comment with all options could look like this:

#! @Description
#! Computes the list of lists of degrees of ordinary characters
#! associated to the $p$-blocks of the group $G$
#! with $p$-modular character table <A>modtbl</A>
#! and underlying ordinary character table `ordtbl`.
#! @Returns a list
#! @Arguments modtbl
#! @Group CharacterDegreesOfBlocks
#! @Label chardegblocks
#! @ChapterInfo Blocks, Attributes
DeclareAttribute( "CharacterDegreesOfBlocks",
        IsBrauerTable );

2.2 Other documentation comments

There are also some commands which can be used in AutoDoc comments that are not associated to any declaration. This is useful for additional text in your documentation, examples, mathematical chapters, etc..

2.2-1 @Chapter name

Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their AutoDoc comment via @ChapterInfo will be added to this chapter. Also all text comments, i.e. lines that begin with #! without a command, and which do not follow after @Description, will be added to the chapter as regular text. Additionally, the chapters label will be set to Chapter_name. Example:

#! @Chapter My chapter
#!  This is my chapter.
#!  I document my stuff in it.

The @ChapterLabel label command can be used to set the label of the chapter to Chapter_label instead of Chapter_name. Additionally, the chapter will be stored as _Chapter_label.xml. The @ChapterTitle title command can be used to set a heading for the chapter that is different from name. Note that the title does not affect the label. If you use all three commands, i.e.,

#! @Chapter name
#! @ChapterLabel label
#! @ChapterTitle title

title is used for the headline, label for cross-referencing, and name for setting the same chapter as active chapter again.

2.2-2 @Section name

Sets an active section like @Chapter sets an active chapter. The section automatically ends with the next @Section or @Chapter command.

#! @Section My first manual section
#!  In this section I am going to document my first method.

The @SectionLabel label command can be used to set the label of the section to Section_label instead of Chapter_chaptername_Section_name. The @SectionTitle title command can be used to set a heading for the section that is different from name.

2.2-3 @Subsection name

Sets an active subsection like @Section sets an active section. The subsection automatically ends with the next @Subsection, @Section or @Chapter command. It also ends with the next documented function. Indeed, internally each function "manpage" is treated like a subsection.

#! @Subsection My first manual subsection
#!  In this subsection I am going to document my first example.

The @SubsectionLabel label command can be used to set the label of the subsection to Subsection_label instead of Chapter_chaptername_Section_sectionname_Subsection_name. The @SubsectionTitle title command can be used to set a heading for the subsection that is different from name.

2.2-4 @BeginGroup [grpname]

Starts a group. All following documented declarations without an explicit @Group command are grouped together in the same group with the given name. If no name is given, then a new nameless group is generated. The effect of this command is ended when an @EndGroup command is reached.

See section 2.5 for more information about groups.

2.2-5 @EndGroup

Ends the current group.

#! @BeginGroup MyGroup
#!
DeclareAttribute( "GroupedAttribute",
                  IsList );

DeclareOperation( "NonGroupedOperation",
                  [ IsObject ] );

#!
DeclareOperation( "GroupedOperation",
                  [ IsList, IsRubbish ] );
#! @EndGroup

2.2-6 @GroupTitle title

Sets the subsection heading for the current group to title. In the absence of any @GroupTitle command, the heading will be the name of the first entry in the group. See 2.5 for more information.

2.2-7 @Level lvl

Sets the current level of the documentation. All items created after this, chapters, sections, and items, are given the level lvl, until the @ResetLevel command resets the level to 0 or another level is set.

See section 2.6 for more information about levels.

2.2-8 @ResetLevel

Resets the current level to 0.

2.2-9 @BeginExample and @EndExample

@BeginExample marks the start of an example to be put into the manual. It differs from GAPDoc's <Example> (see GAPDoc: Log), in that it expects actual code (not in a comment) interspersed with comments, to allow for examples files that can be both executed by GAP, and parsed by AutoDoc. To achieve this, GAP commands are not preceded by a comment, while output has to be preceded by an AutoDoc comment. The gap> prompt for the display in the manual is added by AutoDoc. @EndExample ends the example block.

To illustrate this command, consider this input:

#! @BeginExample
S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
Order(S5);
#! 120
#! @EndExample

This results in the following output:

gap> S5 := SymmetricGroup(5);
Sym( [ 1 .. 5 ] )
gap> Order(S5);
120

The AutoDoc command @Example is an alias of @BeginExample.

2.2-10 @BeginExampleSession and @EndExampleSession

@BeginExampleSession marks the start of an example to be put into the manual, while @EndExampleSession ends the example block. It is the direct analog of GAPDoc's <Example> (see GAPDoc: Log).

To illustrate this command, consider this input:

#! @BeginExampleSession
#! gap> S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
#! gap> Order(S5);
#! 120
#! @EndExampleSession

This results in the following output:

gap> S5 := SymmetricGroup(5);
Sym( [ 1 .. 5 ] )
gap> Order(S5);
120

It inserts an example into the manual just as @Example would do, but all lines are commented and therefore not executed when the file is read. All lines that should be part of the example displayed in the manual have to start with an AutoDoc comment (#!). The comment will be removed, and, if the following character is a space, this space will also be removed. There is never more than one space removed. To ensure examples are correctly colored in the manual, there should be exactly one space between #! and the gap> prompt. The AutoDoc command @ExampleSession is an alias of @BeginExampleSession.

2.2-11 @BeginLog and @EndLog

Works just like the @BeginExample command, but the example will not be tested. See the GAPDoc manual for more information. The AutoDoc command @Log is an alias of @BeginLog.

2.2-12 @BeginLogSession and @EndLogSession

Works just like the @BeginExampleSession command, but the example will not be tested if manual examples are run. It is the direct analog of GAPDoc's <Log> (see GAPDoc: Log). The AutoDoc command @LogSession is an alias of @BeginLogSession.

2.2-13 @DoNotReadRestOfFile

Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files.

#! This will appear in the manual

#! @DoNotReadRestOfFile

#! This will not appear in the manual.

2.2-14 @BeginChunk name, @EndChunk, and @InsertChunk name

Text inside a @BeginChunk / @EndChunk part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. That chunk of text can then later on be inserted in any other place by using the @InsertChunk name command. If you do not provide an @EndChunk, the chunk ends at the end of the file.

#! @BeginChunk MyChunk
#! Hello, world.
#! @EndChunk

#! @InsertChunk MyChunk
## The text "Hello, world." is inserted right before this.

You can use this to define an example like this in one file:

#! @BeginChunk Example_Symmetric_Group
#! @BeginExample
S5 := SymmetricGroup(5);
#! Sym( [ 1 .. 5 ] )
Order(S5);
#! 120
#! @EndExample
#! @EndChunk

And then later, insert the example in a different file, like this:

#! @InsertChunk Example_Symmetric_Group

2.2-15 @BeginCode name, @EndCode, and @InsertCode name

Inserts the text between @BeginCode and @EndCode verbatim at the point where @InsertCode is called. This is useful to insert code excerpts directly into the manual.

#! @BeginCode Increment
i := i + 1;
#! @EndCode

#! @InsertCode Increment
## Code is inserted here.

2.2-16 @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly

Code inserted between @BeginLatexOnly and @EndLatexOnly or after @LatexOnly is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary LaTeX-commands.

#! @BeginLatexOnly
#! \include{picture.tex}
#! @EndLatexOnly

#! @LatexOnly \include{picture.tex}

2.2-17 @NotLatex text, @BeginNotLatex, and @EndNotLatex

Code inserted between @BeginNotLatex and @EndNotLatex or after @NotLatex is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version.

#! @BeginNotLatex
#! For further information see the PDF version of this manual.
#! @EndNotLatex

#! @NotLatex For further information see the PDF version of this manual.

2.3 Title page commands

The following commands can be used to add the corresponding parts to the title page of the document which generated by AutoDoc if scaffolding is enabled.

Those add the following lines at the corresponding point of the title page. Please note that many of those things can be (better) extracted from the PackageInfo.g. In case you set some of those, the extracted or in scaffold defined items will be overwritten. While this is not very useful for documenting packages, they are necessary for worksheets created with AutoDocWorksheet (3.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted.

2.4 Plain text files

Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.1-1), resp. are contained in one of the directories listed in autodoc.scan_dirs, are treated as AutoDoc plain text files. These work exactly like AutoDoc comments, except that lines do not need to (and in fact, should not) start with #!.

2.5 Grouping

In GAPDoc, it is possible to make groups of manual items, i.e., when documenting a function, operation, etc., it is possible to group them into suitable chunks. This can be particularly useful if there are several definitions of an operation with several different argument types, all doing more or less the same to the arguments. Then their manual items can be grouped, sharing the same description and return type information. You can give a heading to the group in the manual with the @GroupTitle command; if that is not supplied, then the heading of the first manual item in the group will be used as the heading.

Note that group names are globally unique throughout the whole manual. That is, groups with the same name are in fact merged into a single group, even if they were declared in different source files. Thus you can have multiple @BeginGroup / @EndGroup pairs using the same group name, in different places, and these all will refer to the same group.

Moreover, this means that you can add items to a group via the @Group command in the AutoDoc comment of an arbitrary declaration, at any time.

The following code

#! @BeginGroup Group1
#! @GroupTitle A family of operations

#! @Description
#!  First sentence.
DeclareOperation( "FirstOperation", [ IsInt ] );

#! @Description
#!  Second sentence.
DeclareOperation( "SecondOperation", [ IsInt, IsGroup ] );

#! @EndGroup

## .. Stuff ..

#! @Description
#!  Third sentence.
#! @Group Group1
KeyDependentOperation( "ThirdOperation", IsGroup, IsInt, "prime );

produces the following:

2.5-1 A family of operations
‣ FirstOperation( arg )( operation )
‣ SecondOperation( arg1, arg2 )( operation )
‣ ThirdOperation( arg1, arg2 )( operation )

First sentence. Second sentence. Third sentence.

2.6 Level

Levels can be set to not write certain parts in the manual by default. Every entry has by default the level 0. The command @Level can be used to set the level of the following part to a higher level, for example 1, and prevent it from being printed to the manual by default. However, if one sets the level to a higher value in the autodoc option of AutoDoc, the parts will be included in the manual at the specific place.

#! This text will be printed to the manual.
#! @Level 1
#! This text will be printed to the manual if created with level 1 or higher.
#! @Level 2
#! This text will be printed to the manual if created with level 2 or higher.
#! @ResetLevel
#! This text will be printed to the manual.

2.7 Markdown-like formatting of text in AutoDoc

AutoDoc has some convenient ways to insert special format into text, like math formulas and lists. The syntax for them are inspired by Markdown and LaTeX, but do not follow them strictly. Neither are all features of the Markdown language supported. The following subsections describe what is possible.

2.7-1 Lists

One can create lists of items by beginning a new line with *, +, -, followed by one space. The first item starts the list. When items are longer than one line, the following lines have to be indented by at least two spaces. The list ends when a line which does not start a new item is not indented by two spaces. Of course lists can be nested. Here is an example:

#! The list starts in the next line
#! * item 1
#! * item 2
#!   which is a bit longer
#!   * and also contains a nested list
#!   * with two items
#! * item 3 of the outer list
#! This does not belong to the list anymore.

This is the output:
The list starts in the next line

This does not belong to the list anymore.
The *, -, and + are fully interchangeable and can even be used mixed, but this is not recommended.

2.7-2 Math modes

One can start an inline formula with a $, and also end it with $, just like in LaTeX. This will translate into GAPDocs inline math environment. For display mode one can use $$, also like LaTeX.

#! This is an inline formula: $1+1 = 2$.
#! This is a display formula:
#! $$ \sum_{i=1}^n i. $$

produces the following output:
This is an inline formula: \(1+1 = 2\). This is a display formula:

\[ \sum_{i=1}^n i. \]

2.7-3 Emphasize

One can emphasize text by using two asterisks (**) or two underscores (__) at the beginning and the end of the text which should be emphasized. Example:

#! **This** is very important.
#! This is __also important__.
#! **Naturally, more than one line
#! can be important.**

This produces the following output:
This is very important. This is also important. Naturally, more than one line can be important.

2.7-4 Inline code

One can mark inline code snippets by using backticks (`) at the beginning and the end of the text which should be marked as code. Example:

#! Call function `foobar()` at the start.

This produces the following output:
Call function foobar() at the start.

2.8 Deprecated commands

The following commands used to be supported, but should not generally be used anymore. They will be removed in a future version of AutoDoc.

@EndSection

You can simply remove any use of this, AutoDoc ends sections automatically at the start of any new section or chapter.

@EndSubsection

You can simply remove any use of this, AutoDoc ends subsections automatically at the start of any new subsection, section or chapter.

@BeginAutoDoc and @EndAutoDoc

It suffices to prepend each declaration that is meant to be appear in the manual with a minimal AutoDoc comment #!.

@BeginSystem name, @EndSystem, and @InsertSystem name

Please use the chunk commands from subsection 2.2-14 instead.

@AutoDocPlainText and @EndAutoDocPlainText

Use .autodoc files or AutoDoc comments instead.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/_Chapter_AutoDoc_worksheets.xml000644 000766 000024 00000001643 14444021275 022662 0ustar00mhornstaff000000 000000 AutoDoc worksheets
Worksheets The intention of these function is to create stand-alone pdf and html files using AutoDoc without having them associated to a package. It uses the same optional records as the &AutoDoc; command itself, but instead of a package name there should be a filename or a list of filenames containing AutoDoc text from which the documents are created. Please see the &AutoDoc; command for more information about this and have a look at for a simple worksheet example.
AutoDoc-2023.06.19/doc/AutoDoc.xml000644 000766 000024 00000000644 14444021275 016577 0ustar00mhornstaff000000 000000 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "Tutorials.xml"> <#Include SYSTEM "Comments.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2023.06.19/doc/manual.lab000644 000766 000024 00000016616 14444021302 016451 0ustar00mhornstaff000000 000000 \GAPDocLabFile{autodoc} \makelabel{autodoc:Title page}{}{X7D2C85EC87DD46E5} \makelabel{autodoc:Abstract}{}{X7AA6C5737B711C89} \makelabel{autodoc:Copyright}{}{X81488B807F2A1CF1} \makelabel{autodoc:Acknowledgements}{}{X82A988D47DFAFCFA} \makelabel{autodoc:Table of Contents}{}{X8537FEB07AF2BEC8} \makelabel{autodoc:Getting started using AutoDoc}{1}{X7A0D7AA484F466E1} \makelabel{autodoc:Creating a package manual from scratch}{1.1}{X7BFBC6907B26AA95} \makelabel{autodoc:Documenting code with AutoDoc}{1.2}{X87A00EED866E22E8} \makelabel{autodoc:Using AutoDoc in an existing GAPDoc manual}{1.3}{X7FA614637B807F4D} \makelabel{autodoc:Using AutoDoc on a complete GAPDoc manual}{1.3.1}{X7F3CEB097AF47C1E} \makelabel{autodoc:Setting different GAPDoc options}{1.3.2}{X7D0DDF2284F2D24A} \makelabel{autodoc:Checklist for converting an existing GAPDoc manual to use AutoDoc}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:Scaffolds}{1.4}{X8524193D824CDE0D} \makelabel{autodoc:Generating a title page}{1.4.1}{X7CF22DE28478316F} \makelabel{autodoc:Generating the main XML file}{1.4.2}{X7CD72CC780874FD5} \makelabel{autodoc:What data is used from PackageInfo.g?}{1.4.3}{X799956EA85D3FC15} \makelabel{autodoc:AutoDoc worksheets}{1.5}{X80ED3C2A78146AD1} \makelabel{autodoc:AutoDoc documentation comments}{2}{X87668C487B1A2094} \makelabel{autodoc:Documenting declarations}{2.1}{X871482CE838C68F6} \makelabel{autodoc:@Description descr}{2.1.1}{X7F1D85188262A827} \makelabel{autodoc:@Returns retval}{2.1.2}{X7DCAB2F87E8FAE90} \makelabel{autodoc:@Arguments args}{2.1.3}{X81DAA454857F7971} \makelabel{autodoc:@Group grpname}{2.1.4}{X8677FE8F80C00B14} \makelabel{autodoc:@Label label}{2.1.5}{X7B0E20A27D64DF6F} \makelabel{autodoc:@ChapterInfo chapter, section}{2.1.8}{X78938EE37A532FFA} \makelabel{autodoc:Other documentation comments}{2.2}{X8152FEF9844B1ACD} \makelabel{autodoc:@Chapter name}{2.2.1}{X823E613385D09F6F} \makelabel{autodoc:@Section name}{2.2.2}{X78AA98BA7E0635D0} \makelabel{autodoc:@Subsection name}{2.2.3}{X7FD77434802A3580} \makelabel{autodoc:@BeginGroup [grpname]}{2.2.4}{X7D3060C17EDBCED1} \makelabel{autodoc:@EndGroup}{2.2.5}{X7C17EB007FD42C87} \makelabel{autodoc:@GroupTitle title}{2.2.6}{X82FB96F37FAE8167} \makelabel{autodoc:@Level lvl}{2.2.7}{X7BF81EAF80D1A4B5} \makelabel{autodoc:@ResetLevel}{2.2.8}{X7C6723D57F424215} \makelabel{autodoc:@BeginExample and @EndExample}{2.2.9}{X83D6DA3B83D3436C} \makelabel{autodoc:@BeginExampleSession and @EndExampleSession}{2.2.10}{X861E2E778510CAF7} \makelabel{autodoc:@BeginLog and @EndLog}{2.2.11}{X81A2D44D834C0A17} \makelabel{autodoc:@BeginLogSession and @EndLogSession}{2.2.12}{X7BADE876794FF309} \makelabel{autodoc:@DoNotReadRestOfFile}{2.2.13}{X78DC644E8519280C} \makelabel{autodoc:@BeginChunk name, @EndChunk, and @InsertChunk name}{2.2.14}{X83C01F9B7FA1C973} \makelabel{autodoc:@BeginCode name, @EndCode, and @InsertCode name}{2.2.15}{X7D3671AF86B995B9} \makelabel{autodoc:@LatexOnly text, @BeginLatexOnly, and @EndLatexOnly}{2.2.16}{X8033B34F80A12A10} \makelabel{autodoc:@NotLatex text, @BeginNotLatex, and @EndNotLatex}{2.2.17}{X7EF303147F1BCC22} \makelabel{autodoc:Title page commands}{2.3}{X841E3AD584F5385C} \makelabel{autodoc:Plain text files}{2.4}{X828AE38F80CB02E7} \makelabel{autodoc:Grouping}{2.5}{X7D7A38F87BC40C48} \makelabel{autodoc:A family of operations}{2.5.1}{X79BF060F8436C586} \makelabel{autodoc:Level}{2.6}{X8209AFDE8209AFDE} \makelabel{autodoc:Markdown-like formatting of text in AutoDoc}{2.7}{X79558A2F7FE187B4} \makelabel{autodoc:Lists}{2.7.1}{X7B256AE5780F140A} \makelabel{autodoc:Math modes}{2.7.2}{X871412737A0E12E2} \makelabel{autodoc:Emphasize}{2.7.3}{X7ED0330479146EFC} \makelabel{autodoc:Inline code}{2.7.4}{X838CCDEB7E0ECEE2} \makelabel{autodoc:Deprecated commands}{2.8}{X78CA9E5C7F494C19} \makelabel{autodoc:AutoDoc worksheets}{3}{X80ED3C2A78146AD1} \makelabel{autodoc:Worksheets}{3.1}{X801D4A2F8292704C} \makelabel{autodoc:AutoDoc}{4}{X7CBD8AAF7DCEF352} \makelabel{autodoc:The AutoDoc() function}{4.1}{X863584DB8497D8BA} \makelabel{autodoc:Examples}{4.2}{X7A489A5D79DA9E5C} \makelabel{autodoc:Bibliography}{Bib}{X7A6F98FD85F02BFE} \makelabel{autodoc:References}{Bib}{X7A6F98FD85F02BFE} \makelabel{autodoc:Index}{Ind}{X83A0356F839C696F} \makelabel{autodoc:makedoc.g}{1.1}{X7BFBC6907B26AA95} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:}{1.3.3}{X83448D91868D7994} \makelabel{autodoc:@Description descr}{2.1.1}{X7F1D85188262A827} \makelabel{autodoc:@Returns retval}{2.1.2}{X7DCAB2F87E8FAE90} \makelabel{autodoc:@Arguments args}{2.1.3}{X81DAA454857F7971} \makelabel{autodoc:@Group grpname}{2.1.4}{X8677FE8F80C00B14} \makelabel{autodoc:@Label label}{2.1.5}{X7B0E20A27D64DF6F} \makelabel{autodoc:AProperty testlabel}{2.1.6}{X83B63B847B5199CF} \makelabel{autodoc:AProperty for IsObject}{2.1.7}{X78A9022A7D5CB20E} \makelabel{autodoc:@ChapterInfo}{2.1.8}{X78938EE37A532FFA} \makelabel{autodoc:@Chapter}{2.2.1}{X823E613385D09F6F} \makelabel{autodoc:@ChapterLabel}{2.2.1}{X823E613385D09F6F} \makelabel{autodoc:@ChapterTitle}{2.2.1}{X823E613385D09F6F} \makelabel{autodoc:@Section}{2.2.2}{X78AA98BA7E0635D0} \makelabel{autodoc:@SectionLabel}{2.2.2}{X78AA98BA7E0635D0} \makelabel{autodoc:@SectionTitle}{2.2.2}{X78AA98BA7E0635D0} \makelabel{autodoc:@Subsection}{2.2.3}{X7FD77434802A3580} \makelabel{autodoc:@SubsectionLabel}{2.2.3}{X7FD77434802A3580} \makelabel{autodoc:@SubsectionTitle}{2.2.3}{X7FD77434802A3580} \makelabel{autodoc:@BeginGroup}{2.2.4}{X7D3060C17EDBCED1} \makelabel{autodoc:@EndGroup}{2.2.5}{X7C17EB007FD42C87} \makelabel{autodoc:@GroupTitle}{2.2.6}{X82FB96F37FAE8167} \makelabel{autodoc:@Level}{2.2.7}{X7BF81EAF80D1A4B5} \makelabel{autodoc:@ResetLevel}{2.2.8}{X7C6723D57F424215} \makelabel{autodoc:@BeginExample}{2.2.9}{X83D6DA3B83D3436C} \makelabel{autodoc:@EndExample}{2.2.9}{X83D6DA3B83D3436C} \makelabel{autodoc:@BeginExampleSession}{2.2.10}{X861E2E778510CAF7} \makelabel{autodoc:@EndExampleSession}{2.2.10}{X861E2E778510CAF7} \makelabel{autodoc:@BeginLog}{2.2.11}{X81A2D44D834C0A17} \makelabel{autodoc:@EndLog}{2.2.11}{X81A2D44D834C0A17} \makelabel{autodoc:@BeginLogSession}{2.2.12}{X7BADE876794FF309} \makelabel{autodoc:@EndLogSession}{2.2.12}{X7BADE876794FF309} \makelabel{autodoc:@DoNotReadRestOfFile}{2.2.13}{X78DC644E8519280C} \makelabel{autodoc:@BeginChunk name}{2.2.14}{X83C01F9B7FA1C973} \makelabel{autodoc:@EndChunk}{2.2.14}{X83C01F9B7FA1C973} \makelabel{autodoc:@InsertChunk name}{2.2.14}{X83C01F9B7FA1C973} \makelabel{autodoc:@BeginCode name}{2.2.15}{X7D3671AF86B995B9} \makelabel{autodoc:@EndCode}{2.2.15}{X7D3671AF86B995B9} \makelabel{autodoc:@InsertCode name}{2.2.15}{X7D3671AF86B995B9} \makelabel{autodoc:@LatexOnly text}{2.2.16}{X8033B34F80A12A10} \makelabel{autodoc:@BeginLatexOnly}{2.2.16}{X8033B34F80A12A10} \makelabel{autodoc:@EndLatexOnly}{2.2.16}{X8033B34F80A12A10} \makelabel{autodoc:@NotLatex text}{2.2.17}{X7EF303147F1BCC22} \makelabel{autodoc:@BeginNotLatex}{2.2.17}{X7EF303147F1BCC22} \makelabel{autodoc:@EndNotLatex}{2.2.17}{X7EF303147F1BCC22} \makelabel{autodoc:FirstOperation for IsInt}{2.5.1}{X79BF060F8436C586} \makelabel{autodoc:SecondOperation for IsInt, IsGroup}{2.5.1}{X79BF060F8436C586} \makelabel{autodoc:ThirdOperation for IsGroup, IsInt}{2.5.1}{X79BF060F8436C586} \makelabel{autodoc:AutoDocWorksheet}{3.1.1}{X809FE4137C08B28D} \makelabel{autodoc:AutoDoc}{4.1.1}{X7CBD8AAF7DCEF352} AutoDoc-2023.06.19/doc/chapBib.txt000644 000766 000024 00000000467 14444021275 016613 0ustar00mhornstaff000000 000000 References [LN12] Lübeck, F. and Neunhöffer, M., GAPDoc (Version 1.5.1), RWTH Aachen (2012), ( GAP package, http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html ).  AutoDoc-2023.06.19/doc/clean000755 000766 000024 00000000242 14444021247 015520 0ustar00mhornstaff000000 000000 #!/bin/sh rm -f *.{aux,lab,log,dvi,ps,pdf,bbl,ilg,ind,idx,out,html,tex,pnr,txt,blg,toc,six,brf,css,js} _Chapter*.xml title.xml _AutoDocMainFile.xml AutoDoc.xml AutoDoc-2023.06.19/doc/rainbow.js000644 000766 000024 00000005336 14444021302 016510 0ustar00mhornstaff000000 000000 function randchar(str) { var i = Math.floor(Math.random() * str.length); while (i == str.length) i = Math.floor(Math.random() * str.length); return str[i]; } hexdigits = "0123456789abcdef"; function randlight() { return randchar("cdef")+randchar(hexdigits)+ randchar("cdef")+randchar(hexdigits)+ randchar("cdef")+randchar(hexdigits) } function randdark() { return randchar("012345789")+randchar(hexdigits)+ randchar("012345789")+randchar(hexdigits)+ randchar("102345789")+randchar(hexdigits) } document.write('\n'); AutoDoc-2023.06.19/doc/manual.pdf000644 000766 000024 00001321145 14444021302 016461 0ustar00mhornstaff000000 000000 %PDF-1.5 % 97 0 obj << /Length 647 /Filter /FlateDecode >> stream x͕]O0+r\W+"6 v1v&8Ǧch]9OT#-fo)' Fۈb$"G<*%Gweiy>i(GyI%G(e/t{euRV]96ʚG}BkB7eB@^ORD))+/q\벫tP ¡D2/ 0"r+ I,'-'` *dP9ms=a G rDxY ܍^Qa&fr@/Bzg1ۭDRP1 9a}tr  _zIL}fG:=\8V0Z%aF×I׺E~M[0JCtg]Za@`FCw|^ 0d :8I|TUcH[b\lg3! a׀ [,֯y_!$A8V}BqSCze{uXf;8/d}dPm7r7&/COl6]wvoG_FVU߁vJڔWv~y*3o6}J{ 謭^4ucȅ`^Ok'w,, endstream endobj 108 0 obj << /Length 591 /Filter /FlateDecode >> stream xڝTr +XJ @B;4in,Dd& T_؍SuBp\@lo5! '@rzu G< vlxEz0 <+ ,3 W`m9XI"2P*_ÌS&jHYJ -^An"~~ ُ ~iu .F&R]])`;v+}4֜œ8%әF%]{NX1(O*̘c;ŘhT35Pɒ B²:Y*3یv]9bď`|ЦJ,NZ!n`T(7J;5xO|V}d wFFN {:ک:7Rq"0=$r \q"aCzާc)IlNXq߽;DsSN63]nfN^i@].rp7uL .7 w_>x/> stream xMs0>HӖivZ:==xLW2$ȐLR80{v_qp]zp#0$$`H8`Q04Y9~ >a9 ˠ}k6I0X/M  Qkkd n"&or]F1pˤ(ͰX̫֒퍮FD Qp,4(шIf[73*Ą"ΚEA;/yauI:IKS_̒lL"LLǞ a{B(E<m5`*Ns֕ɀf++8i>tHLq!eۧdcY{TiL &x)Rj M"!yxZL喞1_~˶^8"6ϹHA3$( (p;js=e8|lLفhn oSiĊOaե;Kk;[sW&b|9t҃򧤸?Y<\U0\Gy1K m}5%fpHޖ_MPa{W;uadUﮓ@T }4 ӋjF4 7f>~I?"֧/e[}w]1Vs0)y9`S7폸e_}̫&]w:TJ.NfG1W32EDTh%8P#_ ܛgCspm)~'%$BR{/iԯ endstream endobj 152 0 obj << /Length 2326 /Filter /FlateDecode >> stream xڭn_A%EIhMQ&TyY/3gH~8<3<;ww>qvnN3k}ś&fs+fnqw_u _?H=@ܙ{ "|Ҧɋ;W7qդ zik Bd0\nweBX/"ws7-P}y,uG(gs%7c"b\臋)|g^ɏ.%,O2Z]q)-|1I\,A=n|yA*6H:΋~sZ՚A̅bڳ^bnlQ&:,h\+Yj6kD>UKéy/򆠷3 W#,LL1'@ i+׼Nӽ(@h0#Tfƪ˚fS9?np]uYYݝ_!}-ezG-\ Pp =n&ܓ n*NR%wYVS[#hY2OxM)K%mIfex 7sGpr덚IմJvI,r)=iT}ʙ~Y.mh1HT0QU ez,QM$z#V +z`:2^tNy&m!~lʮӜBY@[j*oRZ(>em*׶$`$# E*r%%!I Ԥ2,+~ Uo_VQZwYC۴Hr.1Ly.=;4?l;Z?_1 }/I&QPWU]̈́iФMZr0'Qb|i)՟qZ I ƳFcH]ht ,/BA )8+G7+ ؐ ,ϟt0!(oqm}x]EZ=|ݥ?IQ6oԷFWN۶3ݲQgiUUaĆ'@UْPMH 44v}<0~}[Dv- I^<@3 ]MidSs ؔPPElAU8(p.[Y\( 9\qmeBx/VJỀ (UJU',W xhbwr'|v~fwNL}8♘AƟKki7k2 c;BABi$Rtӆfߧ]M@O:Vi`\䕲zWԊtE5fC1S!슨},%S˅&Q.wD7(+PKOg_qg{LE5'8M(X p(.Y {`$0pD1ܑ@&:EAa G13( ;LGDp>$xF2^XHkW-L&^MCSuݡ{ %<`'vAt/>!kaƢ7gSN)d'X#3(l!?a Jx!3Aa 3G?L["]{H !GDafpL6I|ܡ! ʜHRUE7@)Mc '{(:KTSIc΁jlUH<>;2XK5WX6n.xm?$XR^:pԞ9}P L?]A>T7CD\mÆZAzي6;.erz_?/>gt3on~u?(f&`xt 4?|wSv4\,~/N?ޠn e4Ż,vTMeɻ^4%fۇ~:;2gawФE "_>r@"?LP6&O~n6b6w1f{F\Yb 񪶲ċ.)6iw6)H ˎ0h%meՊF]KV=6izz#`ב= -l(@1V|Ehd2 AWˣ= ʤ=@> stream xZr8}W1IU@-xM6U3$S{IȌ-y%y=MӰiI3}ARAUFyFeWYEereW֩QH&UdUv<"R9!H]hekI( N?9)RTB#'A_ ^PIygh~R x0 h(=>![/zRbB }ЗoY%AM *ahDڐTha!L!*@f9`?L?,p`qݎcr @㶈9CXqF  4x<$Yp9ʓr'|'0 fCU`_ m~=1?c^ˡêrX3.Xr<~t[oѵ_ s9,gkCX֓t>v ^&=ƤM 瑁wnpg@(7Kw&ސwZ:IԛN<L&ڔ0펣2SL+H֧2:~KW2iltuκ yy>X7gӖP,>Y5}k-OsIxS@{uz ěk(Nlʤ} 7^ Mwֆ6݉ߑm1o 5PVUCѱ7y^`|\٪ Gz9XL͝WAvV|8uW>H!,]>kw9u4ό_拣ztcUo@x(&+ioQGaz"AŧtVNg_j1d=9OOWTj99>Nj_l|9>7b%`1bt8!ѣdCVK@ןc XG`nkS^"CRdg'bc .QdƼgGS[[O/[ [jvqzzM2\IrƤ+|%[_ƴ)V6Qd/d *z:X'j_WwNP[`ղa!zA5nXSlt0cDaXSrWk9wIo|!ht[WcK6 }d=Sd X"ng| ƫ6mjɴm[j[n[׶m[}Vǭ>nq[}V6׼mȕI1q#Hʹl"["|@(;dG :%ڈߠ8>1sGb4< F`.<< : Zrn<Mwp(Hja')KIG6 %$zo GIVI֠,V'%H;`|s8cȭdjENJc,aBFL͂,(*/ 2݁D,)ktf# p !b],:Y# <='i CS0&^3H=`=PaF`ְQ'yc-E,HR5Y' l%s}|NݼGij|=`w ,22ɺYAR1sʳ0ד Q{nZ˹ee˛G]-w\[qmɵˏyw^A r=eҷϟ/\3=_c/0ܲDNEK3Wk?T" V>!ma)Ǖ(dIYwY LZɹ~\ba.$-Egq5 Cfjf n(CDzF McTd|҆Bcp!4=t(|z,l,&>> stream xZ[sܶ~ׯغx\yqLU;8Ivq@qZ:\RŊ^{JL4  pOn&|߮.zk$aYj1I7$,zr5|.yOWV,WeLs._۫.pO Kt,''>TNΆ͍T?O22M,U33*NgF_WGe_:ٶd2"eFg$2Lf<Go/9O,0J%@P"{l%|~[Sb әVYt -n⃌f sG#˼FN.WyE}wSocC^,u~Al޿YV~k?jG'r3>궿TƣEbC2&Be}=<z.{W-@}^5+KS.zv[9-:K<8:HMh#6BD10`_gղHhuQ sO n~?M`/Sa"v%*zN`-o΢6{6|7n_7 (evm %hEG{QiX5*:c@%E-\":;n=VyYQg>2N~v}yP-ãڡ6 P&ᩫhV+23Nl8r,S, r_)obNL%!߀fA!MFm14ۖ4.~n^s~aˀC BS*K)!hΝm}nk7n լ~. o6gh^C&2&$$)T >Œ0[7oR:yU¿K+6-Ř R]MSp|NތNMebMd:6S' m٢q޽d2T`̡jNM'6C lOAIMdw?>@a"A hp| 2^cg 6YPF=觢D @ۦpUj3\_w]Y;KYOPZuXEXf by2DbcEfR86ӛW]OXÊrz@u-1cBD0 ľPpc_>Pg@ܟW7펟|t/ 8v= <20&7g)؁HNƣ#މ 'i&ؙb$(R*(pR8tāw180%[ (@7x[[P/0ʾ J@v* mTcn.\; / &ٟxQqne'JIw1z5l?xq iF (ErƤ90Ȝ }]5sW ߉*lCD^$LC<ǠS(*ա#,$"ܓuPn03o(nEyw3 ±-Dv=#[qP)BiUCfgJ [0asm,wrd0UM; *N xMH!#._4UEH|̈́?8sw4聹x_diq ]rqAY&gp}90rW_/.)bԃ(/n_A-YYdk ÃvH?8]4-gIz+T=?]=&K.dI %\ ~TVч{Ƴ}`nh`6 UYn̈́i ~nOX"( _@n[¤8ʼn>ɖ_"Ds|v9?ͬ[ɘX5H6!8|2E3ׇD"LiH4  eȮ@FS[XЯx8MEP^6Yc~}'k wB6;4րx~w EYw<2?hm+bC,;3LdW x%ps&]0{z2!+> ]OZ#7)pA@%dnz0:cBc[lG\s6?|ܱm7;hfVh y\e8K5㵏= $=ђ+ ԓL,Ien:/eVJWX&Qhw<^S\kp&i%Bne?~H endstream endobj 174 0 obj << /Length 2870 /Filter /FlateDecode >> stream xڭZms۸_I3gxKۋӤNڸ3n:4[H_w $:R6pX,.A-eIă@$v| ..}FG,2e)n2FȱYyp%5KcMD7\usy%8nY7uite]@}Od_yG#uO"w4єݒDSQEʒ,^_(_RLE'^E6U"G[Csod\D2KUF:TGa7Q^D, OC0hHLU)dv&L&y>MmJSXe~)3n{U5շepH\e,pysaN)>(׍; ?qn7M]%b;OT:a[S\9us08%58s[v!g|G01yg.hu^]^i%*B^KyXBr|K\ ;04×rIAӰ2  J-)N`~r8k0"_d˪X CFe+6'j%via 5MGm2%h"p <Ab܀s,3e0]L?:Տx=ˋ9ypS ^=]e‰9?K[pPOs8yYBڦ?c';{YAp˖F&\<2|Z䜑%+ q>j=>t䁨scghՋH^!j&JBg2ɏRj˒M^y C[zmq@<1*L$Gi2ld-I '#R;}9$tz I9M1GS)˺_q߯0tΚevba:UGBMhl!vvNoqlNv x2bAC H`rTnP C*Sd};cq&Ecu_,D݃xԠK6 JX$<=s` ^ xUQLZOnv,Qϲ@!$s9ީ +g,Mϊ`ph\1bm}Li1rCEQx 6kpJ̻1U >L4 yv Os$C!U˞^J,4C,!KLe,J1?;?қo\ggQ jtQ " sˇeG'vՙƸXJ)OJE`p<2 Fa`7Xo_͖oJT nB-9@| KZ ܭG?,4۩'|40X(_K,%i,ѮVF66_pRaf閎jm|wsq#>m:R}U cM :yy&+kX#xgɧ昤!?҂Rck(tD.tٻڛ%6(bRDa8̽]Ζeiw pˡӺRWWz}ϸyvz|#VWbrFg/D!/VW>̜CΔcYeЬ@i\ ŁOdYKOF -4( l =D#ɨ`$ւ)9v0ygLwʟ3d'EI1mp,9Uh;hǰ ۳)6jns6 .ex`o` /cvXv.6^, iJZ7DLH|~Echs`~86g#A6izzH#糷NCy_)0˝=*D9 &Qi˗ͱg, $4ƣ2~_[t^=MYm2ZX}foJ6|r10%Mm xğ,WR!ll'2ִZï$Ï4Fa]QlV]@!Z7_S.C<҉Em7ɒ(e}<|q\켺YL\B/> ^ b%g.8YLfFZɩb/4gO)#_ endstream endobj 181 0 obj << /Length 2703 /Filter /FlateDecode >> stream xڭZmo8_! 4 _Ei!msW[$-$oEj-BSpP8x pp{`D$"!A1*<ٕ/r뷜n#i IJ ]9HwKo:ߨ=z]8Q9t6SJߩEC@Gk9+.FB(23E],qT*a"Bq|~J=bTiZLVe4 9۹Q̍d'5ؔL6'?nv{y֖3NK#{p=0o3l7%ԕl] ,)~WevRF1PF*)5Sbr cu t`3`O5Y9EV+WE~+hsI՝?6i]yRbX%efS[LrI> Qgsm&St,|zv _pwllCXX{7-hksH{CaAsf31BR$Dz,Xz-.iyIH gqДUA*Бk8oK`'ƍ+jfɅZ9a [ ^,e? ??^ٔf6UP+^$FS~p~H9a]UPѹHI!8I|)ceօڄh*s  !ҝB]cm2 5r:5kunEٷ$Г$m}Y$[2nhKJS^ u1& ~qfZ+ivv&>ǝ@ SY`tAmZ5.ZiſqU@*9؃ h+s4p„ٓ;Oڿ#R pkCc}A憿Si{ R`T 8bGevE@+Z:_i x9ѧRxE)żQ)M{O EUWЉ0'ڮ ;5@$~ĥmYfuZX|sND<y=Vi1CB_ئ`뚂.2'g7L*QqYRʬ/%qV?x6l "V-d5(%F}=\IiE0);g>ɦH7loq)1bXxC Sgyf+1VP] sUm#ftuбi)O z˂=<$BzMbRPEy̫1!{)z5hhpD2~_m.&k~O/{Rnj-)\ u;2Ϛ(sfFvVݹ/qU-Zp-jk??? M?lcϡP0ډ+X3f{rYlȚGժź$M8JyOesR]UoDowC|/[*_>vEۅ!;BZO _ t8E/Ed K.ݴR> stream xڽZ[o6~ϯ0$wJ]lmQ E[ K%$O&~yH]lٓ30EQ<\x\Ň]P{XpAhF&w^| FIB\/IbخwWEp/V D$ɭ,8S$6ⷫhIyD DO % >I$JyNa.hX7Lp/u>T*~[)gSDQ={>:I y#ޚcX݋z@E*>eEw/-JS[U^?͍NB&Lsl quRNQC'ڜE f8Aug4rpmvg?_K۲XΔEGA)/>hUW] .PTES`'M]/F2=)<eiae6uDQY7Ld*Ͳ+j8,Wpg|Ogzv}x*u>]8hdl7_uuSwvD,cy8{`RUl$! JQn.DZhC` оt rFaC$QEp=oz߮,˫[K }D h,2ݷn cyUL{~( / ,9㓇:UUw86#` 0t&ä16&^|8S "Kz}npPQ 7\jG ';<&*g#0vmt6c].%Ѯ(;F| Uqֺ0wօpUk-r0@DAC/}fYٌИr$mY7it}腑39;p]{BH//fFF0cGϐǰOk d( e()HծLaW]c%@QW{)?y}OQ,+@D2:p+HVMX椡pmQGeZ0w=+̃(6oݡ%3@ ;l1߶!.:d(:t 3dZZ堆w3l^W9̑znz4eG 2*=^-K\|uu6+aNʸIY$ pnd˾+agql=07m7C<` }-:y": J"g~kG]" 4p/*J8F~"Zm ?;< ݌@4`=ܺJW蹺C%%&( *A3g]2I,,"3+irNzvp(dH1PKV?!$aP+p`'뤟[[kBswqPH^2T`goN!x-P]BzEB"Sj6p^{1=sb\TX42e=Z68  &g_v8D8D/ (6pF/ʨ'6v.b|9*AjzVcD獏PQh٩ϿD%tSLo4~>cہB'cŖ$9M)WCn|b„bDy)vkhv0GKaKP5A)\ QBpWj}tM;HwݺnZW  \o"пZ+[/>|.J⡖"x5Z*{`?V,4{ZH1:emSjnԠO<@2p4`|@ΰ'8Tf ۽P~qIVj7csz f8F톡  \dl&0rlffQS9pe6a*?U5yެ<%d,zH˔C]T{11 t]x gEdkK4>gB`AbL3%!~jVJ+g{ /Yw[x ´tC30Ϧ;1^ٮCL~ɧ賋֯w0Eh&b92pN`us=WS}+5 pю7 BPjO6DΗ|l ҡ0:meQ#FaU^lO+/w ISnv+[á%r\51o͛5YDkVnǙM ٢Z'E w1 $Rǖy>㔰!x>N0(L#Gy18 }2a{(3frdt/yix7̸L-<7$sn8 {[նVW^%N!|7Vjh] ^*C3{ 8Qp%'$F3'?;!/Daq/F2f{T5`m?T,/U_@PQAńxu6+)H(،bÂg&Ƕ{.U6f7HFKl$3E՚!zhܝHtNcZblT]`>үȊćg endstream endobj 196 0 obj << /Length 3269 /Filter /FlateDecode >> stream xڭZYsF~ׯ`䇅ќ l7NkR9 $.Fro1$[, #>zqϫF&\f#Lq3JbRGWxՓ?xHp+R+[wWxHl>tҘ)0z)waٹItWi0GU";p) xgF$Wfn/CKS{e^Ni")tt.3:GI6;&<~'VEyvEuH:Rn~\e7~TmLFiA櫼Bښ{ꪼ;L3V[i^;m) _ύvU,rРigӿ=a>T巓bTwly௢^7N*lAEG zDDxnvLoV9 nPՕy4O;4gn@vK V&쾥 :UF. nyT#x(uӮ6;ULD`_4b[Of813z~yP rp#*o:aTB;<o `? }>~M.?ch_+{Zxv RK恃뜮&Ҩ\ݦ<͆Y m“ͮ'/ì^ݬKAcI,ޗyF;귀 )nEpaI߰vRj-qÇ*p1g*g)D>/",Iv"C); ?Oܭ=M[)îIUH9$Yb"%2wScla4ajU f8ف4=h H<[xlj;tĂXtʴ|(wCg!u,C i` }Y躤  Lx/tQAT09d}(إoΠ(&x}rcά~ ϕP\syFǸJ¢'pF2.%jVFh!e!%E"hӰ.wQGbyË/߾{PU0.YJ86YOZQ:kǂ4 Q@YyVy`3ÂU[TsXL);.Eh孼+ B$j7;.׬1QքR=;o0~qz#?qHR6۷ .PsĀGKYnʳU}UH v)7Hp$%g:` ֈxuF]axD2C' `:d`> 6,`pCxzftm,3Li0 Aw0U1_Y̐d%lk ѓ %{fy#lf7h0 JD;ͶT֡AG߀YH 8B!TD"h=t\Ͳ9t;Ӊ4L ڈV *LPO;=UXUkpo Ƅ.Ψmn ;Hd6jly;w)9%M*1xѰZWA.}GA ' ux-12ߔrQWA Vmjf] Ro.~f `&aN%]8-R`҅kP'g|aF^4ʗuS8]%P `: oO6~<$: Ulslyc=5 stɓ RG2Ͷl䠮Y&}( evK9.漇`ߴKk%qI^י.' MTrTV7t=ݯS_WӁ@M-C=0,bu`jq0yŤ[59,㿞 B:^ dӻO$T+c`bX'V8q5ҝö!:UcUzaᴀ!/La/SԌEi-Go5m}Lpwl^m%w0RcnܝTi E^嫬 "ZR/&t rqM)ԍ bF>C*Kv!3Y<4 :aȥJupގo_ኲhچ 5pp"1ʺֽHIh-MJG)$VJ.=GD_/o{ ($y!r$jp]8|SYIta[) ZS&z' endstream endobj 205 0 obj << /Length 2564 /Filter /FlateDecode >> stream xڭZY~_K* Jd+eh,.aë ]|5=_7Vx͛ n /dJ./o䳯xO )2PAL)pҍ`xysIҬ m&ChgFgsF~3Td# .v&EwMfI3UD⽺`6ESt's욊ƫ&n*ֻYd}YߣsФ&aN i;XE(T,cQ6- "k|x}㮼wn(FFRy3#͔~2UNS˳(jzTE?ө߲5@o 5> @Yb"O\cNyvs"2~Ipt0ve &~W.k۬Gde'`u(-V/ 4Ƨ] [Яe@?ڢ?]?e?!7&s1Wؚ)kuh"C-h5'8_kzUCvg\d>>7C?\d+ N BgWmS8^94Yݼ2X8`A.i<O廹"0*ҩ6P=)ڧGSjޒȲFDĂf,3)kX4cG`FYﰲ2'DC98(}6cz:PqK0/Կ]Qp˦(L g=~\tDX46G[ P!'"WY-x~CBN#Maben7cPR40MS¢Xv%7H OzxЋDXo|:M;s) fk}-\eL@ ZS<4I82`!T$9H@% baы^)O@&[pc|!w=寈qݡ~Kw`"aSNV@ϳ% )+O617eU]5ͱS:[Cs\#Oq0F)biB`faHr e?e--H }w,5I =NnZcr:Bx ݒ N|IaR \W{P`.eQ' ,|XzDPdm_CmK ^X0hItSyI.2Eqfp$:fQ tKmEdӏBva#4z?N1"S-ӀJNHU gU0JsfT_{_R@Bgͤ*O/Z`,!'!#vFI#9^ʽLFVt \HgI3*"kI0$rjhndiTc />w+*F0U2y$Κ iSPSAKx0h1 X8!DMMt ̫ϗ@A$Ak(SeJP  Tn .`gN'pN|//gCOjmN_~YbOp9vd7_j xj[ xɔǍv -ZSlkll]`JchnlpمFl!o̓Z#җ%ʋQ,Qz<cb<[C*~p7j%ːOkq jǗIJ OO5GOiuHZ)us*3[kŲo5VH|}hx&uk%?{C#c?^dڊLR8#ð(^!:A}5fp= 76-0J}y+:I&f[Ao&%5lQ@rcʶ|lZA 0*zg6z&P7`WztKaUvaGD\5_S,8WxC1< nn7"Š۶:?hyB%ٴ ^U;Epq~|Ƃ)enFm* 1T`sבs 0#{X_6Fo @8sv,ϛ~~GzG'F*'=ەubuE㧦[ȟ?EU`byžί'M2Q-2EYpG\^jĉr,a4Yn{ endstream endobj 217 0 obj << /Length 2549 /Filter /FlateDecode >> stream xZYs~`6/TnVvj;Mk(R!8>h%*.@C<x b\W#f$#RUkro|O߿:TD^?BiNo#Y:=(ғھR ۮ)k?IBgحVv-555:R2#"MOLkx؏޴@9Hʼn;L Ef̱ͪY3O7+hևq;DžtVW<&׶7=7,{@f&:f<4Jyu`~7)顑3s7ť 1y,D{EYQSU kNf])>{mYzwN3$L0޿8 h7ږ[b޶x/]G6`xgPl ;|~ c5C] ɓ2rf["*o=";:|z0,Gumu70.p ÀEL2$Y)\*G$PƢjm+OBI눘TǝN/D#o4?[%hqi>B\ѬN:LkzS< x_Yތ,}d_eJkc9 ٰ抍r5f +6{Z<I&QQbAah `/Yc%!t?:JR~+:kko{{l)*m8G/?!HX:ۺNt^ozm:VOŐ)(z sj3O-^[*wbk(d94 ;xirHH-":Ȧߣ8~e,鱲bycq ۹~>Yce $yN620&>Z=OXDS ,P(Ҿ \MJ谮r2=: 0vQW=,Գ軷w`oଃfn29QGO+ΓNҔx]4W~u;w{@ mMHdž\/ֶ֦&fX3(eOU4(wusK?ݵ=_'Cߛ̂k 4p}"R'XBYHbJ&͂~y~SeQSzuEyAyRcE .ASr?FVv)9ԐV WF_5U#Y4{ }9~_:ӽhw]u q0WZKA"AvP~c5A%{{̵sŰN:@ endstream endobj 222 0 obj << /Length 1145 /Filter /FlateDecode >> stream xڭMo6,z7]ݢqv؂eѕz;|HպD Egf8C5"fr\|il4hqVXiE-VK0?]N.>]|Q 1~>gR&MHmKf\PI?6ɖtƴ M}sR|[l,kfKL E^TRc-i#sF_n'erVѲV|~PQG{[]ڀEAJ|I UhF9o_qXOSDFʤL=(Cw".$s +<әP44=3OxZ>FWK:"H8M.o-$^L D]x$H+r7<&Dj1 Rt; N>ѕE aIChDh^(ld)kՆlS. A1uDn:L?-|X'w}:6۵ Ui H0Uy{+N]M\쪭nonE`]PIblP)0#hB߸:Ry԰=f=xuxcA6 t/si{8/;l"8u. W-(4 R;-.dhPq#~ A[%AQ(F4 ގ|![G3e꺀OB82,t;j^,K p5 &X'aN;f'A57=&ٺۓcODwPtþ=Lu 4^ T;Wvʓ.:Նk@ *8&l  +(<^n3{L:A@#m`q]>x#z@rv S4y,KQZu֙ 1'}P7*zž8x0Ι,crN/u]z;rh q@+=Ȼҵdy/EQ==va(eH**:ThUh:N\EhJl9X s>za,P{8U%z|l endstream endobj 226 0 obj << /Length 1895 /Filter /FlateDecode >> stream xڭXIs6W酚P$^M&tq2$p߇DJMxxx{{pQ nLx Q%޽z훴Z,>]| #uV3e(!L I,~۔eYj% I uR.-;=S[U1^2l`[^-~j6ԏ#Ï"tyTq)U=불G$Q~Te*Ok:~n"j*[-vC8MKF:ؙӪYj+ C#Ɋudl4 ESGO< Lq%4ʶ#0SGJeqMk797-&bN4'kI~>cWk4c΢}9,԰.mc01s;WeƮtE%:`뮀sR9!0jn@&C#sU?qTu& 4,L Bq,*Fs*x;B 42> ]ݞWs\9Ď P6u002'ࢨl}9b-L~(P֛°F=&x@ z9W%("7kƳK9`j]v\ 00鱳sѪ-jl‚aC\K.5WA]CPLrecC2g®NF x0MGsQ+2> 1 (\4miIcIrѬ*:ΣqLIeh 4ӑ, D\Ri_눆۪=a|]y~vd֝HoPCFGi:%@| P^ݦu\e! iYS?qK`&zb Ĺ.Ѝez|9XӘ&buG _>(YecMN;cV2G(+]K|D .?sۜ٘!"7oT+05&:Rʜg^B3\BWUaTpLxFWXi"i^Mlwм+c~Qꗋ}f9Е[_d'XUQ~JZw?=UEfk5Xhդ> V9מKBi!lBWQH endstream endobj 242 0 obj << /Length 1985 /Filter /FlateDecode >> stream xYYD~_! rz2 GaXBQmU+"KFI_O%Kl.FV_O{k{7W^=!`^Dwh ($H.;Wbr8F CJ)WEMY00TE92J]RJÄ`_֕!ʑi'K n#󺺆=,5< ue-nYӧǻ͆Ai@(tfaB;ofoM rKE0DyM CtW%HL Y-,\WE\'7＀ςURel;IUܙTM;2V_+Xx* T(@A6nܯ\{w76S37eۚ gB"O6}M_G̓Ry i6[Y?KKWkb.k-^~Lu9!/sTҒUrbgBc2FK̼Vhj氹I'љ̋]m\Nz8{8N2{3GDҮeƅܹ]nUa^VF=T:?7D)_EcbJڟ Y&YZmҫDr. EV˲2O'PvfK Gm.c^i 䛭DU#"8s;k7j`@%r\ˬ]\ P>SYHD'2*Mz;Z:k㊀xB^xAXbsuw%<'"xQSnˡÀzO7aki3M"zh mz,j&)׃LC*qDN my* mQߣNGwwy+Ѥ.wR(j'PNP '@KJj4BY`LJ4G!cq,^GeVLj㋠@&xqG+<2bHn#A|5 9#ف c>bK1p<&Gɮ80(1ZhL FHDW'_ 3 j +zz,io$DD(Ky=9a +P}hT7Ri)$nk :f6qEV.7֕Ofw˲POلaQwQlԀ7sHA Y#2;ȊLБQL,g`ᄀnY].<㕬em|8_CE" Ub_|SzWjvr]JYur*Y*HLЃ:[CCAx> stream xڵZK6ϯf/TMp:NM*u\"Ie 4@FCfFwiw&EUMTbD32-ѧ~V|⇷%)Mq`3;M1Is"5ݧ_h"JDjg7skgו6ǻF)I5)7 kBefsUcv8mr3DI YMnIBS9u-ݪ=2~@}[CyG(u mr„߾EC?(pYOuQ4?7oN#\cBz~2 c23>4l_ԋqSZ3.f "8IMz$"l`JH %*hEp(=` L8' 0OERԮz6*o]eîڞfƱFs.t`7y!ƦT[gEgecߒy]¾CroyI~)*w~(GX-%A&wv#wUi*/6VV:7b͙0ͅfjgW2k)Jec W WUl, и-?Ztϯl!Dad/] v9P#nhsB%?\<<r*:#cPPhv$x"cO*E콟ٯGK Dƪl*}:]Д Ѳ3SȪ a rtwQR16Xh\;a5k^j;T:bL+0GB V}EtϦhFդ"ws'| 2Ǔ,HaPqӲLax % Us_HQ%T(vZaFclaX ȼ^D B _ ㆰphJ,% gG֋dM,ЅF T5sW_Ceo;~N0XFc}zRDWA5F5m.R.3eRO_!$M0*)v?Ӵ+>m;k}WxǶئmJ]CNZsg!] (┫K)ݖݼ#WSJYwe0>{-1s#nDBxZbUH&W7A!Dqi'0]1(a#M0IˇiL <SN`T H*@B"U0a?2^.t+AG}1Q`7FF.>U匼=86ckzZdPD件tM]m}렖ӾQ0cOF f*Y*T&{~TP)G>VHm{J^63fɝL34; SyCO 튴c}[yvjUU_ xb^ U- *+}8ܤ̄ymUO[ " ℜ,H8詘 Jb|5܄?R5揂 UY7v.3 /0KmtZ(cs)-/ցYjz+@d[|>U.TR aYMۢ]W3d0',ňWW𧕹lnC0 j(1\ /jWj4( xi@q5c}G'W3_\d8lbsAQ4LArS G`v \!%\I]ȹm<4,4GMC CP<Á uwPz`LoX SSv] endstream endobj 269 0 obj << /Length 2180 /Filter /FlateDecode >> stream xڵr6_v_ō1}IM3XoN&CI]t)*n7D)Q>x~qp$,HIL*RD)£2z_jqqpVDvD4`JjW"g JEQDs_ 6BpE"ݯ^4yU:J \.JqlǴ8'X!!ItOa0wQ7{Jp 7$|KXVo]CDi'W}$q)RnI<=)ޔg'@۬YQ|q \+^fcHQO)8Kmb)YrT[CVE`n @oZRdUO+yMvKmqRȊ]VNfehW^X^VV^:9SڗA P.^ށp.]g[S ~޹gS̐`_Zo{tfqcT:$Zlo>h ~'f*^,6|W/ǛP0 "@d0HNE*U~ ”Ga2ǑBJPaN| $|Pw`t}G }XqKP>+:"[&s^s2VĘcD>=ו\{Kl\htB`gs;!08eG|0@X86M} d@fz3g"r鯧>ٜ"6H6pLQHF/l4Nچ݃DB2ˉGi< n]<ȷ4 qPkN&0HV yktH I62&3yg?ɐj>zJĕeU&JI%$??jOȠfySIR$QIb) ’3+X}Fek(T?n@ J6]C7zsÇe2eJ6Y4u $VL)𡮄s:/ul8xNIO5Ym*iqks-0(*jlj6EVgFQ)}㱗"_ӕ2(ɮTIad)"PUk }zM[kڽߵU*,v@ʞrK_ֶֽ@\a?[Ƃߙ䞜VBvO<[OkEֺԵ)n}< ޥ,m,w؄>s9!̥i*M<ӄ!d` 7צ7|8SǨQx!ttQ!K p(8nӶuh:`su)[s7,CH9h9+Dthݿqn?.uR}\8pNe}EH|! PD`f%{cQ>YOKL5Xb*:}d9*`)c~Nn:z2ߺ~gSwȠH酤Z% 7wyh= 6ΦᐍD $Z2.v+Iv%R^Sdگ'Ml 4|Jc2K^%y M![(88ET^e,M7ʳ< *ʬ^Ot1;L똽jDٛy^nI~?MJ'O ](&ebcPdNsq6 \3SL/.@Zu@pد{dL!& ~h?~[ yG9=T;95p'&~냼\XA XkxV;1/C0¼&T31#"|HPL>ݟ¿Ζ ;6/a GG1MFhJֻQ+5rfҟpn60ɻ6t&87?NÕWpX|p!g> stream xڽZۊG}Wcv7/8 $l?$1~E$&fekp>FYiq$۰LOϙSnSId=z"/JIpd#oMDjMTK0m `URo ǫrx* 3*cz|a9F]qcP6Hj:6oA婵r'fXw"+1IFb+ruA3C 0Ac@L` !'OX9CKà'1вHExVK/EcFNKTrD*-ž?Ux޲`f.I+p6æӵZZq(=P025̪,lUc| ++^oL,:,jXrz87fa=91@Nb l`H(\np;~ Ky3$  {b}c걾(_yT'j+CwQkFwo|߇UZbh}qWD)Vo߽z^LrMM)rI..֐bkLqg^_Mw||\^.^|􂦛UzkdzVx #Xŵ*pҽ{i,-Z?_Gn})ˏ ZEҒ' n@\,يV/(i#,YAWJfH%C5WgTLG0X"KRlǰT7(_f$؋O߿ (wD a3Ģl|YMrcۛvMr- &b7V'b||u3nuս|bPlXĔ:!ejorBWVj\PϐE+S;"kVI tO gA،`(CX䟳z7n,F{};mjގYZ Li9,7Ͻ֞AdML1I5ϙb=#D/KtPs&S,7ara[sAAkCCFirUQQm3藆Bm K`grCZqnw̍ڧϗ# Fy (- ˨OՆTIF8n}4uw`;ϵ8ԟ[qq*q϶눣m..ܧ@Q w""sNHdccX| +YC3"tqZ(7hD J'Ρ@ӰC2uoϐ…iu7F 9%ט$]nyywS]+'Y3c``J?gԂdG.=셕Cۋp_i8Dg -Gưse -1,jTcX+yLuP1#Lm-h;fqVÚXlN=AۅԐĆ\#S|;eƣÆIuމ{=1oy#9w?v5$6EpG"m]UⰳB{ߺ3t^Ӿ"_,Bl#!)"~qV02 ZAo endstream endobj 284 0 obj << /Length 2080 /Filter /FlateDecode >> stream xZKs6WC Aii:M>[ktΣ,wc9GpW $Kj+p&ZDPW'7֣7qad-k9*_sfUװfИH ~%Y>RIױՍa՝I4m~9p*GۮEBYYVW9-*D^y2-Ңr=n4\>Ġ$mr"v~wy kD˙*"N~ltfnMk#?Wl!fv:EE>mrx3(bVdJvιgwo*rؿ"ǜ'nŒr2q ̆icT֞\kJt]vĉRcJ$4d*r_{Yz6AQVq)E=ܥ8MW/ڶmƟ ?0gXU/uZo-% 'At#ii~n!RB#94n5zЃc~R=A;VRr[25M^! מ?nK_7|[%&- cb)0 T]  ظ aX(@;g@ 4,v<cNJ\(`؁vAz澫Q"\P+u—=uq%ѽ{ۥmZAV%*aom=5 ! zjֿeBnLT,JX9X/ځ= dD"]tvR®Or]-.j vo\!olGonm{ʶ"z-7] IJ{ɎRnR9LF ƮCzG{= ޅ[e^' nE,Iw}iiD87P;BG Mp'"{ q{k P_z 8B"{b|Hpa6Q2[J)Շꏵ.׃] { hb0] a{ObjkF5_ 4~^La;uiHC#lEON,8C`UKhy0R@jT숥ێ;'`K(!`Ń9ۥmZ< <`QN1L!dŃ׿mBl p~ܒ0}R;ZBYPǂ,iGk endstream endobj 294 0 obj << /Length 2593 /Filter /FlateDecode >> stream xڭZsM>}L&viRq<ywFM%\Ln'2II =O>Eo7m]5~wZOghLN+E?<'ʰ46C;VJDEغm&/jDUmEڅ*/74\i㐃$Y8{O{D'aT,D}^Th\z6Eib8=jekA9:FmrJ  тǏ [sR LĹt:ɢs66JGo,p Ewi^RDyLu?ثo$z?YE+Ua9N@k:vA&rg93LvDV@~>E\mߌɖ$@1mc*p )kP9["m^yc&xFTixu j"E@SE^t9]u> , =Ʋht XuoVZ䉖y>VUX~.“*yn$Qe&–ͦv64=YUv.k8鴊XВLݩHB\B~@={F.%d-/Ng/"6@X:F(BBvG;2iXպE#gP9Z45T>I_̴$~c*B]y"(ڹ%_yCCo#{^[oCQqgBHmF`~L#&aѵXbbZ*dBP-e|I{(B.=-XS?qalk2[U^˹-C57 BћrZ(_eB9gCȁPpܹ,_Ȩ vtj>\1ƩmZ=ny3Hho< qXj^Ӏr'&Wy >*0h#S%imfk<в;R(p<M.^ z&xtK1g:1'/s.;uS O ?J9@|&c({Q &@L.a 㱀݀ 5:ɡ$pA'Y }M/ 27M6+K=X2/>| ї!$!yScѾJob Jy0ú虝XY8}XTEb O.W{;AΗ Y=\RRݤt3c :hrhSp4%BK)u4] Gi]ApF$z Ǻu :VWZκƅ~i.4 4aܔGY4 ']:4W^J@}$  +|է|2g!Gr5(ėth(.Y >r` 4?BO$l)>q>:ݣ< wФ$@_ v,m͵Wu]q=,f|#u6i3/, vo'3/(_Eb4񀾈9xXVW ɤ!~jϡHX_޽a#朼r dq|$GAnbTM})pŦzobXeSt ^X$]tg-5_)pGG6{ frN6B14GAx:(=&C췏࠙xh<xt ϯqDXy5!u@=McC`.^+Brv}S@CJnLgxmZs%tݷ&{q;Te/DgNcn\hH;tva)m]ŧ ?,K: ÅYmU :b2#?׀gGw$}' ]ɃuMG ƀ!x?^6*.%A, YÖmQ:K<| _diMs*$&sy C`X['S:𷧭c9 Iy`1OB.a'<#htv%R1e̤250S7Hq2 RḦ́gsh6/_D*_'/DE%ipCҒX_+24uh,Ƈ+8Q b_PkQ4"d#Y  ~c~JrĠq-J pXil(ѡAέ?ㆉ)|L_^}s D&;E$xB,OYI&ti"9}GꙺP|Zٶ.f?p̝ᾐ*")Ih:ƾ$_\&C]:1~1wG;}ˋ˰T b;9;.(Ov_^?\4Eyh's8)5 endstream endobj 306 0 obj << /Length 2032 /Filter /FlateDecode >> stream xڭZێ6}߯P/) M  [r6APdɒ+K. 3pp㗂 I0_TI$$̗ɳ].o< l\{FZc]`9)@"D(E\`xKM3:+Znlk]`Yq`T^ ׀H%ܸ}7 *&†F߂h$89^`5#lxk]G'x6C0f|>΢ ,hB[q6,&))XyݗT)dϒtF7QaeS'?8FY^r'є"CwXƫ)*ʢ?c<:<%'a, TAQD X~ tT@X CFpԌ1 0z]YpO|fY*Kw']o;X OP(9'h}tO:x $ˮ_\Gi^çϣ8y.#W9 it-Bp5 0Vjg[_%| s CD9Q iܲjf.U>_՗M5:Z<1" I :R J#3\B A=ϑNYUhoR3Hb2 +YJkԓ_~﨑OpmP(쪈A-hI!y~Q%V2TA¾M-Z(aϋ59Z%Qdqeh:3o^֠zXa8Ҏ -#H {%~i-H. gn!LޛH yID(&P E5WT8j?IŇI8slt"X'41w*2&pe=,# &4 4)TX`CJKw6N}tթ;5~}DQR&]=0,̼,|[okMėgjܾټai(_!WB8-E(Ef R&UldPR=BTR9H %DVNBߖ6 1AF) ʍk :qXѿ"F;(zp mLLzf#&q)Й{Oj0h1- )!/!eϵ^S>\1"sM ~Kb*]Se]\[> stream xڵYY~P X慼xֻ6 vC)RꪦH jJlybI<r?l4 4ۤ s7j{p7Omi"EN # he$p+sRQlv*$՟(^.K0J'o~;fREQtmo?٣.olw2hV xjbxqUUgU(_1ocgs>Ԧ:bęi7۶n/'ʦ'NSCF(EU!ÉGm](ls6=yymri@a.nRMLkSxv0^$ڹh2 /9)5RR D-ODR emw.l@َH3E|H*DeqNIzЍB}4 XeMF|!#f|2!uc~t}YhBbZ*uhATt )S /ʡY&:Xљ+D淴h b[U x?Uru X1N <z«Yx SU}UvRՓy(Ed{Wd_`j.j*_ f/$4JϻcmvI1y(] b9BDZh$x ^ϸ+񺕨oXPSZxujCB)֙Cyʶ^Xp v/6hb1Z?+{_PtAU))S,/kK93ea S{x2 C_E'dP,#SFFR~rxczd|B:5fM4Y㢡aln%&k>ZE.bi e eȤun d*o>*> stream xZKs6WɅA$MNߜh 9C*E)Ji3d9xbom˳wWg/  jP%PQ$Aj\owe~/f߮>< ixF ؍:^4q@+@Q(cQp_\)+4 Ւ0ET㄀"R!,D"A"$8!VDc^De1Z@$ /w6.|vύ)2ɳ)Dh!VC )x*B=lEt9T. !%dËؖu&+M0`uAI Y[,Ҹ0N9\/*͋ C z`&0bdZ 'Ә6> Gd] q9M8 by|~ V3$p4 "(q {aA3O p4cdj(2"bDA>[:z%s ]R!G9BFHFӐ)4_td"_jpu8HbGȨՀ|X&GRp-@ GNQnKtA>E`TIڗŌ5pu:pFs0fc%إޗOiEeΞ7f.)y֖5 bޥlLQ=BaT9EN=<70)na9@*k4g@}IZa8S0=9E 6h|y\Cblkj_ڶqa[߼}}AX"HǸf}ӳ/1 ɪGZ#Gfb\ܞ.+󃬧6M)[p:ؑ19<8ql&HDK=ѲEaJmSK 5ϓphi%* [,g:qYP-wq: ~{1.1!`E8~"9 O|23"fI{ـ(&ADVdZ7~XPbTFYqB*íǽQ^twMRٯlYEE!aW=^oR4EKhVQeUkscf$˶tvj҃;tDZqz咕gy{=25mlUStgܫ͡۹9tĻ2_ כWkāא(w3?p 3FE}}ƿLE[ZODE]:aJCHbL.md]U^߁=hb1'"j% 5G G߁` ںVi_ƗM4Vs7r \Rc$eUew EvO8X.3=]; +si6epO b02mN|*%v;}`-8$NAtq8Ù)'C$ ѱW|6pRhNwDI>0#C\o"J/?B?Y endstream endobj 334 0 obj << /Length 2187 /Filter /FlateDecode >> stream xڽY[ۺ~_ 'ËKs6k~^ *(q/گmuE@k=]YQY j, S:u@>,#Dz?p$V3 ~U:Z$<4q68y&Ddw .P[άk_֖ &U9eIa]Sii- K !J-TVeuYoq2كvuk!R5Z4.eZڼUS,Ǎ0Iv]ݶŲ̙d+ZR4ty/!+}ZZƳij cۖ(cDCQU! H↙;0W;2_Qn@1iw tƂp.;uhx 5=xd"D” !oRT0AolRصrd7,ۚƥ.5;\}y2Z;Lj#"mA TI]8- |eOjCu[zh̏d$,; ~(~٪7eN7<9n>ora9] vWLD}wwpOxX(3%CoGCk=jt%\eL@ѐ(Tt&-Ьn?(Y 4聅GB/Z~[->q3v2 >0bl+Ť/nW "D$N9[C8j:"P߀#O9[C8P% K٫0׍ k["m=,b3B9dy;;8oFk53|r(VЩ>ٲgWC̾M}̽-=!\0zۮ=zȳ^?lu5zzI*-k{HJ-*&Nzqb f[*f6z5xO#+a |zYdU[⫑ 9l5}+) >aCKgyk^i'Cq\g蹵 uipY{p{fGb( e1EI0='t4:JA)9-~,Z& rT nkAiAޞ(&GpM<[cYgy(4 ?Y/B~-_9GyG`*%5Y999Z1bk*7'gz~&.o!0e:vt]>{R(r'xiD+#8~~}ECb\`_0Cٍe;8*Gx/Hલ}C/$#dI'"X 'QMjA7B( p endstream endobj 346 0 obj << /Length 1862 /Filter /FlateDecode >> stream xڵXIs6W \rJ8Ц{$`cTq}6J(۲܃-xx8p~|`A*qDqDPJxp>>z[eӯ翾xy@0Jqj3(hv&ez;04 A(1HE(Fn?O31ϊB6j{e8Qx#n{30~yD?Z;xyg]VN ++M꼹i, 'vv\MVժzŅ_CٺU 06]e鬀˹3ga~Oʌ Zea .laE-ݪK7Mg |8!R41?;3!5H+ J MQ_q0! 4 n"ZY&l`B9G3bm&1O(JtG đq~ \8$r(h7 Q?Mg|7''ycU}gbUխ,[˃muS@",n " N:Ņ\6Ֆynr0~lrDdr;nv]hOUD˼T{&=C3ҥrܗ+~6kij8px T>v)X(g;ho^fscϋU]ͻL5[-Z.)D&vյ/moY1 @$3owl @2dm9ܚ {,J!nS!S?;m>zS!S )C74*A18лC(戤`&@0?,'4,d}cE RH2_T7C`#-Mg f5QCj!o=ǐs1`h1#a eGpF4E9ZAN}l +<]Uեubfltie} :܃ 3c2q WZ*<ȳtiSjAJM> P&a`(y hEcR}%&`[*Ǖ* A\(>ڈD:xky[KVnc]kx˪תTw-(;G5@rf ";~C2GVE[6“)}@VИSn&qb;)D9^Ovt7 `iFVu7#InjRFW'ޜ݆-{Jak,  & \ î2- 4yl`I%jc7]hZo3̜1+6ztu@!dX$@5tSk^V՚=6uZtsp'y ['&~Kcp}&7c??m`Mqĝ81mxo{%hFq![- w#1[O҅so"{,kwcj;$ @V+KhEI *[Z(Ś"K-w :eZW)^9 7K|nC2/r`/Aݦ zn7 (cA.t MrP Ѥo,X Quy$_7 4zbLmhoOa G=P6n)A)%>b#ǥk](Tʛ-nc{w]< Ӏ>i%PzPRD`7൜?'asˌXa!O GFmEHc|^;KmG6(lZON endstream endobj 356 0 obj << /Length 788 /Filter /FlateDecode >> stream xڕUKo0Wp Z+m;fLQ7f4hvuAd,mVD u?dW4 Jh*9+l'5@ s kCh{Y<H).$BfxT xm_/Cr0\TD^Vǽ^>ӖO^7KDKо(vzqr ؁\k^&P@#{OVqm"q%#и)~ź)R0_L?DnD. ]2?4D{T6sqNoO5>IO>c:^`N]InL!ok'M9xm܁eպRpH+[d?s  J<7936oJ~<%5ugvpͱn.7Z?\ endstream endobj 363 0 obj << /Length 2217 /Filter /FlateDecode >> stream xڕr8m! sq6ćTyr$F"U$8vdl ]=ՇWiyMW"ey.~sZ3)~u{4'gF4nyta5^!1]hMVK:j nvtX`oY.6ᐰ-cWwirh?R}_\ 7 h{<m 6~v5OP~8.T/T0W7ny 74 fihZzAN ޔ0FM [^$7U9/uATAG/+ݛW}0\}z:O{|0̂V*<Ѭ뷝\>h>=VpLvHN sP\ \D >]1@-r، Ȣygt8<5)@MچD_7mᜰLl ڨ,zq&$86eX#E m rMgiCpOy & 4X4fOpY$eûN t;t2چX\ff$d-xd'A47:-\TځOhŴ ±iTƓ/\% bᤅ%-bنȅ: zpPǠ_ w  }L)9(CBQ6@P쏠 _Pg ījJ!6#9KŸ-%q9Gvmu 3!B* kl1(`nMgs cH:ghVݞ[̂3t`ƐC͊d!X,g Uc!d2 ]$Ÿ*`64Rk ېe{\LmB%!&M-FjB씦*0\N &ؒ)T W8q~CGm!>_߬!ῦɿn}/qO=b֘csQfаm}ϵd"qy1*jk*A*ŒK~SCe]?}< Gry 6 >iB; *@u&d[ҵOo9\&Ct]9<G"HhT6XjpEp$.m$LF OST!zDPyb] u~[EUfV.] p&]:LQ>/_й3vtFb8:JC;3;n/ nHYz91迸oVMu73q g$~t$Pވ(J] ?6Njz_%ǎf`5ǀCY>"SӅ߭uޓaOxӗ+6y}B^&>+d8ROmLn֏EP`)^!a1{njY&/&Dtٻ"frHԷ'O<]J8^-fKAF?{D>Vu8 .lY /d } \_l"zԪd:/F)}FsZ]\Aٖn4;tv@eb %JM0fP+o)ٵ@{t樓RCF.3[|NoX9BC1xOPXDv#s`q͡3߸5> stream xڕY۸¸/5#O R]bpW%Ȓ+ɷ3^+g7 C7M7o?IDrsܨ$&I7I,E&}=xwaE,hB!T1.z]F"TzFUe( lO=Dj{b;:vsLzf4n5 nifQ*0UY"1/z,y=!$FD&&h!^/9077;+Mge Ou۪}lw2?[8{,_uPd >7V^@(Le[}&tgF΢fwt$TS5уyJz^2 ȤLAkS}(s K6RT6 =3Z'( +#Yśkd$Qv KFNKe9pIXxը6e%#"q+@ւqSxԖ.\ߓU zŝɂCSvM]2LELT5IO ]Lbkw[1/b+MoUEw"Gp7 gmsf K Cܯ$Ej0Ǧ=*s6OKwKU XZ#-zjD8٭ ?^~V}9|L3mW6uG6GqV/=(m\ Y{d~AzA/yspn0Yq4]shZ$ &7 8k~YUbCi{:6UE3wSpriZo?  f"S󞂸kۀϗD$fyY OD\PC mVgiՔԈ$Xl: L,V54`Ϡ ,#N32FQs* o`xFF$7Rf<0thI8 ?]tCm{^,}T{$$tFIF CSaL _wi#d[dxq1' UƩ.Ts;.._w!#Åxc7$&(.tu}Y|q 2Av(wD^:ˬ ˊ{}LPE 5[3[]}HfE e?mHGy "S&h`K7[Wm*9ဂqÀF#9N /`@eci2qYnl 3,H18%k%iطUEЌ[ P;hn%T88X$9 $8fcLfj*հƝ&->TsʠD E}Ԛ3u|Jh <0 _=ybQ}HS?=4u` %jy%1DVeiZxjhևȒ\veYʵCO3]/[شt%.NzM{ӐY&lHzxF'̮7M H"aFc0R M!Эqc  MTGT4ƒBїkey-}%gbKiRDI6QZMQo.IgXIN7eI:Cd4HtVOv;nR^nY74,i獐;t%/r9]%t1Nrc$T  9ݢP/,[TԖs$ʋ ǸH vXD;}BnihMڙ2b2s)_6*;/y%AmV/t̲^JCR`EeaP]!vExqPxu$2 |jN)W;nY?ͷ$ZC&nH .x TPZMr _Eg13AǑ\H<Uh }Գj6-:n`F8q%&4Sӌՙ МWA}B=z9ÐuMc z! *LqoleJs2G<;^kdq-r#C6@-_V%Aߗmo+x3?SǗԌX;R xާϿݿ?1zP endstream endobj 379 0 obj << /Length 2882 /Filter /FlateDecode >> stream xڵZsHLJEJK*w(`-(*d+濿Yr`Fǯ[ gWpߋ'/,C>[f"Yqr5[O_PjC)͗ L㤓џIHHl$4[DEK Q| CQ(!'o3z]Srhw,Y6&nzGs|Vk -YZcv#9UАLr LaE}d\Hl$'/8ã!9Bw3ꊮ0;U&Α(h̲nrj]t(5sLԓ5nhrnܲqM*ۘ$њέsƍiuu} uv CS_s< Nve3 ܼ@Vk'Uf[S)VnZ4zI@}1oR]RV?OPq0&(çp0d̾ڙO@ e r )(ȇ c!."L4Io<ǐМ(7I4R,ei$"r+xVKBiP {Ct;ءG\gO1?f~B2e#GJZx}q⏋wtV: Gg=ELfO7: BdCA‘S''j#bUe++4A;7*u| Llqź!߼v>14O2&wyxX"~թc:w8ph)ItL:DDD TLx": t>%4MV]S[g7ʁ c򕇟fB""f:*_9D@+X?L(.lЬY< tBo!nȩ{Eن3 :*u7feܖa\m+pz2u¢H bN< Tng Vd.B(\:"]gv"ń<)Usؚߕ6 nïG5r@=o #@ QyZ%S!M&* C Ȱ77+{]QGF6*vP,C_D4F=ؙ"C`s\ZC4v[KmƐTD0ZEϪFY^]9RfaYwk.`x@+%T9"K*=^<"HlhYhk{JL^IVy_>GŭeN@o MHeqgq-YYmE•F:j?!hg\rGcs? 6;slMaNlx˒ X7; A$k .,+ PAErf<T2A q- իtT3W}J2rɘAnvzb5gj=02%c$/X=h_%A@KYt3TEaN6Sd{G#!Coχ|p?S?_ǵd)U"_8>t `.w*gʛLw ~)C,ymܠI6WE* x9_@ɂlvFV $>CH6d{OLJ6`'ʢ>7w{K\[[s*,Q\uXO ]IW]P e]l2hDr4ܼsM  gdPm8%=rs(Gkhxp$&o9g88f9v?W O4uiIK jss+oz-7P* cc1z4?b͠qp@7*a ]#r[LZ W]L pN'e`q6$6̈&pO a_4`G=>MQv^`xCڝLG12\%Z'yפCnѐOmZTL2YVx.B n< PŊ$q`7<Ա3T)Yڧ%7[Sn1?/@]yq ,ԭHm9ۍn r+ej #/לs@k=e5]ܕY1%m.%ifi=! Cu $^մs:]yXR+ endstream endobj 281 0 obj << /Type /ObjStm /N 100 /First 869 /Length 1551 /Filter /FlateDecode >> stream xYn[7+l7I0Z Hhkd8B4?{FKiK+3g+JIMMiD$%Akz2k3n5y+-35e&[Vmk+VCXjٔzF zlvL9:UJ5z Y)Tvmv]'njFw z8j p>%'wFf xݢ8ێy}Ukke2E⾗ka7Vܲm}\ŧU5x7p9؟Qºcr%D7JHc{ccMwBx703E+O4LuOe^ixÅ&^<"8=x0H7ƙ>%lcX#y$:&1,ZDM5} Dž¶lfF֡xwǸ'e^4L6yl> stream xۮ۸=_a'uI6ME.٦maeɕs g(K|.A>qH}L`O=ErLT '8"d6=՛j5}Wp")k)JEO: D4F$!JJտ+iTZwߍ 9ofseiFCmWU~IqXUe%Mڝ%`SE5Sfz[Ze[z#)j2~G&/lsq-L+aNijC+  I4D!kwY"k{ti[ѮcNȶl`z]X(iH9#pjU\JNiYQhmTX9 h9@;sд(b x bZ~wkƸIcsXֹeEfI_#dэ(5t V@TG*c*ޘ~Vw(%:e]nLKF&#S=`iޭ!bB Ml@V;%7c E~pZ1iնC(%͙sAB<ѸB0qoNé 60!ٕXˊ}( !_ lNqmv"_vn,ZWhz\LNYb c {g'ZYhM^:kC=[@A{Ne`qa6kQ(0nfv{j>OttiLH}V%i/k*`}]ٚI^`O|uY,Pe`u>?Q a<㺔/l(g2e[5n`~ޡ sD%hǣ'xr~RN "_>o)D@콕sMŁu'?Uǚ Ϋ#c~H':bciŚb!C` xR2*m[hʪ]L ^<|E,&3rP8E=¦W=nʸUCvtc$nBm-ם\L^ó˓T*B*ߜ(IyVhD -w-jڀ^#_e,,ZC;9T1_-gQjPZ@zϛFBB]#6U5_a `"w::2D$ ʼnR$~#ZlaASنXQ.dx^>Nv29}xv)wW5fbpjAzw3h4[PSLk/w<9EOs0-FZ6nhEr;)$4c?"l"/i4?!;_٦j֮{rtt 'JbsnJ?hv&\> stream xYݏ8_StTɒ;^v(QN"x};`)(GRJ>7CEK߯8aHTno|yoJIʔk% ieWnu(8IҪ]_N겮me(K~g*B pqQHPEd%Q,4U^^ڍZՁ޲m[؊ͭQX٫[eRaZ&%KTyhhO,k~D]AoPMԶy'UAfc5vz[;Y0DEi.!Ad{/厨[KKkBt)[6HV#؁Ƃt$h୲`ɏ&_7pn]a N]/:g`BDS{/n:\(^+8<[n&:ͻ'-]`#|Vy@Šf2cIk;RNxD8裭k.v +;eMEλɳ֒D(d*@uVYP2B+.'ĩ#ҙ "8ޱF-%T LF=3TV-Q)fQ3:{:w;[\f97H`jܬ,d7l4,8l @ew&Ƥ?*vx6#0eeػZWN_gDf0/N2, ͏Ug%Qz~m+J^~20!"vu bջ!dEeHdPNSc(IZh?g_,ͭZ/JëxSJ,Di#FRԤ2xH"TTg[dy~p?'Ėg0i2P|-C>&H9@΁;A a I q%{TA (Niڢ~L̕O0)gM8W3G;(F 2 *!ݛw?û_~~'ꢳD ]`Nq^2ZkD`o-ﱮxC"=:dsa8T%C޹ l)cvX=_ ,FU͌Fgz:5ו\v'j,cTs{A01jm }]5BC_!'kmg'l6/,Os5Q+>%S ƿT yHḴ`0H  jO3$RA74t44H~M$d5M"d8/iP;\o5T `4IdEz:Kהi"T3z?_<%BH/PM!R?c >Wֺe>4"M+t/' W#-L0{k1G*uYpL)d܋9a#]C+ȵHZBIE@Ȋj]rN<eI%Քzk3Ӟ_D<iQ ʹ :+R΋]"ty4Z'|\]Āq{PPs@|[:X :EaBYc\C|W#)>}|0ȃQDĕ%ӃE;XK`QJwe.q:gjTcGȟT )S.匿qIMs }ߨΞ'ciqiėNB}4. DInz˵s^Ү%vp%ҿth t'?ѭ=h tŖшh#/KBDt\\|EPj#3pmZnrrȆB@K; 1]ljI+>ٮm1pOaZ >S<,Z2v56U䚭Q̲X^& jk盾 rG_.,&AÒCQUt# %ۑɌ& b%~@TI#+V_?Zv (Uy >HXY[7&[Ki@c_?K 16@V|HUB5Nf:U@vW?ݿ1VN endstream endobj 396 0 obj << /Length 378 /Filter /FlateDecode >> stream xڍRMO0WHd2c{+(U*C! P c#<ycrG=)2JG^ g5 k,hSz%r~Q)}ڍ C;5Է]ՋEΈr(!˩r6>lU/}֮32*aOU :_]? l78 >0PHSBCȠQ!EJ;9 n i;ߟTHXSn?IFtm804"' l$Ӣ& C79i~ .%}]?膇_.Ts7Dس(X[ς r8*'pc endstream endobj 457 0 obj << /Length 1213 /Filter /FlateDecode >> stream x͙]o8+r NbQ+ͮV1'1%'!a{QA+9_; h<ϻ lu1] I ہ!ǘƷ([o> =AACn_i,GpqDlC5ʲ \1|zQӍm !wbd );Fr-g}lC"nMJ,?Ou7^T?Z*صR9T*x= M:8fX#]t gۍnFn! VQP.R4Y ᮤؑ2c;:M{kS'a2,s(UscPc+3?Btbݠ%M&Ye띮®aTS3 ~ԅ%I*IWX*VDVo; tU-[7U"j"fGȕ~hϠ@N?nTy&EwEGڅ_i\ەvGșCcLgJluT*xEϛ6}O_Wb&TT噊-e#绿n_/BbA[|Cڡ \YSx% +:x3NsVO\ve7ڃM3XۓH$H-peI! %ϯ}Dz|t/(Kjj|>&4iZ0Fe~l#<= sQ2+2q*Ay_n敧5 %-ҒRz`^f눅,^S`lB&Σpyݦ-R<"U2"c1m(t(>U1:( E?;2 NK3KNOE9Hb(!_"kpwiXSs sJ٩JT*N.-zV WބnlOfyV endstream endobj 481 0 obj << /Length1 1424 /Length2 5998 /Length3 0 /Length 6970 /Filter /FlateDecode >> stream xڍwT6ҋHD= MzU:J !@(IHB/;JM"4 RD#Eҋs=w3g<wv05$+Iuu5 $" sqñ\04DHB `q:E"Z,.#A ɿH@  KA}^x_E7  # 0BB0?B8a() KBx^p=a˒z7؟҄ȹNpoA8+ C`p.{`G:? e 83 E 8wtXa b8' ~) ԇ(,Fwxw̪{e Ő_Gàsi [r#.˰@Mpw NEo# I0orc|B2`pExX,? `=Gǩae\poG?0tkec=o))_F%%7OPD (,A;E?܅$2e;g?$3!C  1?QWwFj<wQ]$n 5]]=Xn8J E@pf:oH y@eMw`pm`p#K桊"/OXLA!>$170_H,9D_6ZLDẃR8ZB.KK?vzѸ~ A?N!auaG5,^2DG‚E֤>q$ܜir`5k.=%~+ >jv SW&YoMQ=6KSb*Ee&w3C7}vVI/ vƫb{r{guK[<ɫzq`hpElgw, (Ik?K=h-8lYId{FW@Er4%bL{2/+?hEkLO-N״x#${^%#!4U~''¼#{âӆisiI0Iӎ-L+M/!;jDް"m{V8r*Igr^kP v_Xv lٚUt/{^6Ԃϑ#9]QsnsM)ktʆUtcwafSOKL5 5K>V0zyKu]RwVRp&i xlf :!2G4Y4Aܐ{ +cՃY1@SM@VĊln/?;Wl}ͦ i{'TŤOd+nz WĒy${6uCݶk˵Hڴж[wvܱa'ݴkc)5F>7her0 ΩKm\W䶅/M **!VA\Q37?91ƐX{|W_%؄Y/*t5ʓEY낕Z`{W nUjC7l~i-cky5|S63dRT+f |_D1ePjTC cֽu  +ۊ!Klљ=}f^hhp/ڋYwPD7S,@XFM-qH{5ؽڡo65 HfF݁Ѡsor^I24z{v rfʶb`h\қBt Z9A,zP?{ȗm8iP^[GSYz8ƀ҄#LeZAGOfKgqq(c</kF{^U8 ͸>[2cab 0ZlwȂkt/"jg1qfSt i׭tx $ {zb:?_Ą+ E8F8V+k,szUܩ)L B@I|1+o|S8K:L> \;{/yԆhhNfR]ޫAzmr]XgԑA`ȋ!ߖg~L1 /`qȨ M7g$K 2iu{yU>QqLy[Z=hF6ƌv:@Q1/^O0"^ ]ƁzUkF(R9ZCm\MXΝ j1 C#1-:6 Ҵ49z |`dp3t_;,Բ`L t&H{&^ p" @|)<|()d߂+OȲΕ7& ߾u3=sSc8M0LQm/6wNzGUZc fEj[t8>lJ צ꜍i.n’9+oV~6 l_l<'b{YpBCMꚚg}']ب}#1/\H nt흳}n߆0fÛ{?swFzKYlZyI!6'F=ୣK1#Y^ [CRN~5aDAT |68 eO'By]Ug_v>BWQm.s+Sc>K(1s䍏=AV`TdZRJug4.[\NkW))~D7-!mRł2;8{4l♄9zҷV2ǒ:Q [K%ͯyػ/ &&Nݭp89`k,wQŹI ߉8&Dջq(ʠ l8?l^UU>saR7~-9< K&1{&\ei|]IP!󸚥s͙K!thMaaO)e oY[X?o9GqPCJ8U˓4xnU` Wٮ .ogʙRAmF)|ZrX]ӇM^V8DƑPb)aDojƳo)8!ۡ̆35'¢nAP0ia HX*3s- BtLːWN aH[Ϥ6 7U9G>j5#:@EL? T,h`6:r~jܛ>{e־bqL!ЯaԣNh ExG-suUIuB*e؛HKdq! oW_|/M#UǘWÓύ>uT7wN{E]x 2{#{(PjBu[ж"X*MC>}wd~Ranf9?uG}1g=zdL;?=oY-+J?ItoNvW EY͜<;&"tY ˻D]xvŶ;g+M4 a:X5;]+xwnH g6D;3SX 2{.~/\4ѨW[ͺ?&ROg/9FA[,b7˓@1o5MܖN.-zFQĆ9$6V@?Ah 'E;[3_HQ+JrbkO?tBS %UH_ 7*;]Z̙};Ptr o*BѝQޓIEN^ENQVIVhqRwe7͐ӯsLU)# 37,j%A=|ZM ] p_$C,^wEߝ,0txأSɬaNƺL fnq6og2]=Z|@Q?*ʡg52qK(CCXm'rSCu`#%gKEF޹wd0I©bczk=h϶hZ;Z++,ŮΡlvs\+y2`,)z/(p kil]pj]ȫidgsF-98-P"x[h~&RcPR$TjoDj ~bk=@M&6&4TvMEi3#hArDvp;!C\ù̽?{w5/M]g%ۊv +\{,H s]e=Qm˦5y? ㇩6\n%)kQ^iX{ȫ m[e}K}=DxYƜ뚺K>xY @]6DDXJQ !vubԜ+QҲل3JP1B#8]W^+,6dBt^ݠ=T?سĞIq)1V J3٩λvZ-K_(]WG;MfO"?z\_r5B1`%Œ5M܋g&Du/<'tV^B</តJ.7Iv4/^ME8t in **p(t|e4$&NCaǘ))RwG4mk92c{bZCϸK7ǜi< w1CYu1`_">^7_h^A^87ө e3اWѣZ.nqՏv F\ܺ->R쎗[JkvX+s UW\Б2ĢGC6VQexV;/+ZJy"_CM`LH7p?E9dq:|څMR>`;$D&_rM})qI봹E U>Ylt<Drmޮix1m«>x.X3SL):X<޾ZAw}Ң:B9wFWBÌJe)P(l]x L6u7wg[ *%moO!|KB åwӵۻ~Nz}~q4t GOo$sK݋mL,;5EGkdS*f'%/GRyޕIC;id\sPƺ\8r@ o~^b]2x`L@yg-/XAN1 ޝ+zYȷ'Kx4RHNn[PaYrTYk ng3!Cż|a $[tE3lCzn.vޠۼ:;*B ?Q3gv´h<29JKKuk/p]?J,Ixvuϗ'f<>P7-9_ endstream endobj 483 0 obj << /Length1 1384 /Length2 6013 /Length3 0 /Length 6959 /Filter /FlateDecode >> stream xڍtTT64(ARrfnf`f|AEBPJFZIAR=5kusum.vCAeg# BbB"1Xqq±eCc(8aP,Sb~z($bXR,%+"BjPo3'h0 Kᇆa :`)_ဲ; w"=( 掿 LPNp)xݰXYaa!;FvU|X7aφ};wgB . \>P4  Gx!ah9` xu;fJ'g"8W0 E  BX_E:t"0(|< G@*e#oO{'4?[?eu*b@?SaN ]$G:lC iqCc0, !"""%#<~_FOAPp7  `^4gp‘g0gp_Z=0 7[rSpJR߭A%'|F+eܛE+?n:λ4vV[y).ŨG}R=hcޚv2fASS@ĵﴹ=>9i}ݎY2Z.!?}7or+1s+Bzzۗrhos6$~PzX~9GŦ&&Nی,{=* Scl(O ^ZM/![˽{߂<;hS iteq4r0շ.* .w3O|z} QX4~!xBsKvEfWMu7ةItq^& U G'_版ܖJü)APIն۹!QmyyLnbQ9$Uqs%Bj~lc:9ŵ4ZFKcm94/1O5b_\] R lw^/*R2?.Q~T*"篷ơϚ0iqD/[olxW'PZ:^mzq#Rk"8n;*TPъFC^Wpe,O߰o6vvM庉sz? ,p Jl^rӈI Owgoޏ=s1Q`.Oͮw\PqQLVo]+ɘ=Iɺ3t̖PscS1C'Yt˦ɊsVM1+Yg|5rEן2-˸FftE ʭR}_ciyi*`A~"!1z{l9Ym2m}XwkId9Fyk8W > >Lb8PF}+}gE I뿸oUVetmdG̖| %z*]AqW*uܾ'Ҿa[؏ri5Ah/OT .ŸWjbK*YG΂Xlf=Bm Ľ٭ꞿz]vBױwMdhGOHHqOw,V̳)ӭ⇙ttv5 0h ƨVjM^j54\*eɉ常F0aκqmwyIg[cvS*XX+9-;zH/([(e**[J{:*]Z ^ RTx]$*ĹqVngQ[u(?Ur@鵚 !a_!Ku&-<41@( "u&;>܅kʲ4 d2I^9m:q? X4<z; ]Wh[ަTm1U˜W>%2ckrRfS]Z3\9|&*8M jrA&B4C91ˋHI2i1T2Us)6YN JܞfdsR#ߢdhQv]Fd^$|c{F̏FڂhFikb:!!$dQGB)˜J sЊ9_)I8@V-cjzH|'10ShQ@}1T ߍ(L ó@g!n)5)^#;#F\$ŮiBz_=]f[쌧.Kt ѯˍ4 ^.52Ț 4HKFE>eskN2w94q$y/µ9sSI4{*n8u#UO0P$3i_'Hxq~Lz$w%OvY7˟6M6NOCJSK~Ɲɋ1Z*H_Y3!Oh:۷v~ V*e^P(d-k2& mî11TLs/Ky2Q[k%K{VS訙OզjT|˪|QM3 v\8Uf}D`Qt1Q[!7VgIU~{UT7idJJk/BIR-QaqJ7 G"m:󒐏ߍ}A(79arՓٛ /r-D1M/d4(T"Ϳӑ2K/Ѽh ~oTNQuMܔ[>leeZNG*8md~eNa j(cw0fmx!4S{v{P'iR>OEm#>J9,WyjFuTۓl>dr/VkО[b.f^š-Ӌ;[럨W&O8^2'RTq|uP\^wG롗^&+2:LTm:PKE7Dq=;s.h7ܹ*Tę6Oc%ѧ*lJǼ *D8z'סѵ lt#S1O;&$o g pnP袈.닽mzVnϵPs;;_t+ȍ] j\޲xsR2敀+eۅqS)ԬHoypw qP* ZRoN?wٜu3n}GHɆ3Y(fd _]{*!i4~5~ D]⊖-O{ONRXMD&f(Kq| P2Şw~?,qWF{Kna4/,_^ԕ +2RՋ[w&)X?+j_/ZyW[OJ=A}k/U?gSһ䚩_7&Ku\QL'ȳ~zap6_k zV^'tNY|tt?BtYF4٪ޘ>y 7EasjÁ,)^c:LV]O&?4 1ؠ?x/4 fP 15br4ƀM= M!s'ZAgνe:[ou$8_8&ypVS?F"ZN(F @ H`'u R8NUŭ+Z_|[$-I<oZ=5N L, wX#߭iH%}z?5}~x88mo*$uL*?"E䛬sZo-U/߳~Jy7-O!qL`1n Kӧ'V4`T^,V[dEvCRf֌wU)$ۅ=.YMЬJ37 BcNmlzЄ_Xl\rE"U7[ AADΘ7McVKo։.:^oWT%/Hc_*J&RR sШ\~h? endstream endobj 485 0 obj << /Length1 1385 /Length2 5981 /Length3 0 /Length 6931 /Filter /FlateDecode >> stream xڍxTTk6 ]H HKt00 )%]! J H   qk}ߚ羯&N(G ez&V HM/;)9 G!e c650 C!8$) b@_@,@ wnP4)*dd~ݡp c\؊0`xȊ"(Og~!0P'ϑ`wDH.po {BX"/0x@B?ODp`0r#Hg  4tE0!FQx7;bZ4`CC<94mVG:ݡH gjpO(~ ANc8yy!wj0X6g( wP_~__f A( ;4bH`o( o?W  p$ٱf({p_ K?;[,ÜPH_G,lb&g8UTPa1$$RR1_H ]>ղ?QXB|P^@g gH `w8\/ Vz(Z@KWrWƪAe0o;:1߬m77 5D?0( _> nاK_.(VC~MLBbt"3@T`C0'σbP> #G~'Vl-P_(tap}y^#~pe;&j ZQ.Q]чSs,}< ]*9~ ewB1;OH=YlF`oÛj1wq_W|fe7zZf(=`+w>ZŌXݡJ26}O8Scn5GE:}5Lt9GSsoqxT$NU+ғ8J#y v${59뫆^5٫%1'߻|jcE5%E! wHZqDA>;{ Jw9^$C|v2H6]!=!cfxq+@Mk5zCHxTvΑިG6$ˮmW꒘zר{ę`||ÎnM9k%IDsqBSצ[8$VCf(h>V=Y|H>U>]:xoiчDF_=Dňt ]yocn&.UC TӖ߻SySrC5"&g:xK.gxӷ|:hqF %Uǘ u;OZ={_šOlnnzm7VyWE @C;_F|F/G&,Vo,*\6! XXcl\i[A ^Si0<}5o[cf,z^fy)ݨ,j(7 pg {r^z/~5 Q4&EBfMc|y;j]9w{ކrio"˪pV}iNϾ6eOm>_kBD1d/?0KFCl)kV6d,dӖ:ikA}%~013nW},$6Oɳr% =2nd~ MZ)~rjïLI9aз%>c%Ɔ\-m?^w%ߘ.q{"LB Ge}7Z "] g' nulVɫv7' ^Xu\!{w @1'd=ɝ<S:)ǧ odl_cֶJPCƎ[Rъ>석<7W{DN8"=5CM&5~yi> K*.`OSo$z7Z攍a3B `ڸqSS2G|&Pgqi[u|m泇+0g7MʛzRƾOLou#bԮ The6z<UMbiUy#y]?uYhc+bo# H,v-F1k}¸lC=441[҃=% N?\LC݇62-{:”|iY{Ѫ{e(62q Qf:"$Bc炎d}95OFxg͆HIQIB9E\ThčNQŨ[Jx$Q83ՠt|{ h)Db{tcqqNNr},uHꨰbg fxv:>BDN Oc{ZdZSz)(rz6 Vmݘ=p mEm?`c167n K*\`i)ZL= e`){Ka3[V`lY ;O'Nqd FO.*8Z.7/XTf['A~<0kڙFݗ;Bq{юҦ@}+MX/!ݲY_$#`Sfw C.ecJne6ާ :{( =tV8lyfQ,{TqGC+c9ɓNGe6o{;#l'LGKDHPa՗i-LtkeA곓k8].0U)B(Cc,Χ ۟ڥԧϣ0cKqisUL҃ܣ5zE]'!_lO>aѺ \C^C^˻!WG[,qnGĊbLյs|܋,TeF칢@o lKJz'O6Egx\_1 {$᧲dΠ؝e bc)ɗSuzI0Ts,РfꉆGa5yTd{~ϵM]_?5骞^;iSCAoڑ3Օ8ͺSCdtgDݹaAἚB5>rvGF VuN[uChU|p'lF9g7"4|VIq'?9om*Ok6>yjJmZ h 2f"}ĥQ*CKmȜYoa2|GXРJiμK=FV|USiɭ+7꠹ۼoI)ÈP鋹(RyTGޫ=':Kz3⊯+lZ0Q{_OOI`&Gr=$̒6QpU[Nô8 rvIxe)bC t0 zWbK-275"'_ZFrcˑ["#H6,Q̓9l3TD:hkl*bM !b6% B,UtZ?VʐKI{ˬk%i]58UY Ì) eT!qStQ{[hC %NLp# 2N_AyОdqdIi('] )e֎j8s;ō,~L8S3J4H#rU! فղ=HހLg+aA2F%!χw뚮S}p-u1(O[Yg3[t{R1^v9iޛ0qDϪǒ|9s!.H h])זs'SNGTfoS'Eɭ >$Kk.POU ls }~}f2Gh) ˩Ќ5~0/;+degOԉ3sHyD;^IuI˧T=j:DLϣ`9|J>R^{{q /;v$Ck9ӵbWH7m]: \xKx4MD,>T6+X}$y? ɵ[~J?VzЧ%7 8(UMl? Pz)XةkcN&gfǑ@z%ok}f1f $}2.m}G|=hGy2y#?u%"_>Sok磻1nzd-JJPg3}#1~n}mQgbM^s:t/31]}[w[FOOL4$&f"o&吵{":w c#.w֡bzPt¡!CeĦZAѯ_rRY? 7<|S[Vesf~~6îMcV]!e FlhجUr[0ZQ_`i{`J&X)4;m{GGNo}1|.Bjy9tޤc~; (|''<8/ܨO~>9L:%zKg_M!hg~%;7!`8@fnΈWwLXuS2H \\_1V) c #A4$ƦD!͘XѦB:ǁeYWӄ V  >LČ{mCĚϞ/zؑ>[Mۊ[9~CgeH{k@eTDIBmY/AY?om endstream endobj 381 0 obj << /Type /ObjStm /N 100 /First 904 /Length 3250 /Filter /FlateDecode >> stream x\[o7~ׯcE(^o@mmQE##F++H}"c+j]à8̹_8Q>{e) %Qy1*b,n%aŪ8=leKP%:\wʚuKRVlT|B3p W$!*3Qbrz(1\x@X'x1xLȵD;bV} P XcPqBD@XR-&Ψ`;qVP$0pb0:c J#=1EED<VE'{b aƜT2bMV8&AxcJ+ @>Q)f`(l'ȬTL*2'ّ M`U@ "/gN9r%XU,(`Y9J E jDQ]BhYDG ZQ5(5G<(XpPbQ kJX ,OLH|jk! \mdjz"T#ǓR=~608 8 d. xɻŝLX\͗XM88T-ի n|2}kpdb~}nq2>^nl7uG@iKsyA+S1N履_B4Yhx|.lHv=`>T>dR&M\\\qD֓/zů>~3}>}vl q:1pSZurHMRAL_ή_/CXl叫ņ"l3oQOU?P"eEq>I(kNO_aMFg8.4 6}q}bz4l_.WN߿Ζz~yh6;9__O~~䇃˓ot<*(YA|C%CW ا cmI2"D%8M =ް X'괄t[eqWNFUZ[/Oϭoo`<6x ml<5xs k\<7x ob&<OCQPF& M߄g␜&8mhT9hf2G$#Bΰy{ c4 -H="0 {E Ƥ:G$ J"6FbBG #'1 $W&+#欑^AKwȊ e$l. )bC!*PY%Tf0-WBq$$wոѽ;VhӇYv#g#oT\!T ejʎDWK&^7U{M!6J;*nejGyΠ^s>0Y*;FBb:]FCCXCaJ{:4¥#$ȉn$9d$heM\W}B2.-d Ԓ﶐K#Imp+R Y lcÄ"iX8?255`]7ZDLoojOߥ2Rj'&U:+ɏ[|"b:8n 5󸉾u|E DLKHAy LG %3ḩ]u.U.|Ku$BrG(a$B}-أ8 zdN(8x*s'߳yĴ&xb"P\ i "x!52:p3EVtu{W]Gй=־bl:3<`kAU:vwKaW$)] l er}T1mܷ8.lrC`>cG'jro WYyߵ` `~+T@#P֐^=_SETN~?*UVd1T3`KHg׽3pP𫱸^qy{;l^'޸o?(@_a;ā$9y^NUүFk.zξSKp7^/Tjk睓' sñ:;uƉNԚxi[s]Om}oYJbB'WYc4niMkKnǩax)H՚S*!U⇖'Oqlh\@Q;RkؘVYc-FEn潮c}:Zs#|!z½n<_kf5ʓ Յ!sfeʇՄ:KnFsd8s)yS'ÿLfᝫrZ~w^}oϾ5q>{sd5i>w%ld._X0ٛ%d#˛ϗ'o縂 GOmx W^gٌ 3@l(߾{qyb:y|y˽nv>:wI#$=9zH:>\QJ.@৉L̽Tw*t @ endstream endobj 487 0 obj << /Length1 1306 /Length2 1243 /Length3 0 /Length 2081 /Filter /FlateDecode >> stream xڍS TSga,LuZŐ KDv"*S y$y/KB rTePEA, "*(XAD ([E¼\p朙s^]kMh#G\  Ƥh M8KvXD0p z ЙF_F)܀7F 0Vl0Vĉp7꺌lV |.ċ|H0>)!"QILaOjX%H OF!ـppaB\)`@$FE ` ^aA` F'A2lSM@|L*P-!"*nOBz $QbRC%!Qd}JJkmA^T Q|Zp(AuoBeT2jU$0>`hL r'ETZlpfD !Qa⏤SBj 1FӁ CPN܉+Fȏh߇S40JS9^ȥ%pzzb @bG'SĩqB!d2O&%>e&LʅGoh|Cn7OW%vCRD@$s@$<QI?4N}$P&dbÄr}P>&Я ҒhttbpAJA1 OBLAҏĕ&Ҕ|BAlarěUOj㻧ƗV ı8>g84~:ŋny{sop2;7&K`f /,"~E/>\xX;EyRlJ:4e-`lo5,>GJᓱƴ׬Ib-;*O_rVb[nݝT]>=2_ސ)Hv<\򘼖ty1WZ6qfgz# N8ݕdivyD38Cpᆨ +/;KW[XPF-ι^'&i2`_>aDeP870|~CEKq/"+c[eȓuR A4͹֝[ h[O<8=ܖ%:[y3.imZF5ٕvK6h}=苏Ƹx~6iwI(VY(Kf' Pi .MYw۵#:v!/&B\yfne{ƔݕGVX'+.mx̫ VT^\]z}uMe!9W%֏}aWdY{]^:vXl,]j^oelu]!IloI=Oo昭_oi9eXW$aG=d_*U8~|;}BTAQl% endstream endobj 490 0 obj << /Length1 736 /Length2 20962 /Length3 0 /Length 21520 /Filter /FlateDecode >> stream xlc0M.o۶m۶m۶m۶m۶mofΞYw՟`fēQY+HDl=Mhh9D%9Xi IHM -l M8LL I=-̝ɍ(-W60pWs02vuuwurutI_HN^CBV \LV___Ʉ? ſbrw&fhg/#, *'/"D,o`k/-?&Fʎ)R:d`70r741nvꟀ )MLv51'wq6qė36qnH8xXX{ ؚ" 3-=N&`bI?c?+llgk'OJ'"(+&L߂Z _l +Z?ՄOg_^__B(sac§abg`begg5rqt4u7?r}Έ+2oH\%Yklcb7TZ Hؖl%4c "8A8x,jث`kuZ!zg jnBe`o6s9`yXn~}.|q*0q|UZ&ƀ tgeʅN}`Lw;ӋSJ(ؖ~vPETI-FˢB'мM^vQO $9yIJ>tv-{i;cM6 qᜑǤ̡EOpaJK).9Rc*JX\bql)RfJѮj8T- 0}zS ^]!VCHZ'ɥc'PO#+BFJLwvS`k[=,ñfi\0NߌHyy`ipeȖBf{&Fx&*qDm} By;{`\U f]$FVq 4m#1"=A|1ɯW Gf3AuZY1w胷Xy{={ W-~k"[\>t &W߬%nh1Gڿ"܏6X _SPLN,4EQ?]*-E }Hb ՞%B gU%UצeB ' iv\܇mQyb 2;h=3E?{ރGAy{~P/-o 4do5N]|HFs4M."qe3'QCyհ}Lz˨:睓6:&[['O`HG7"f=ƪE}p)B'$b9G%ci/Y+|S<8%UɏD} /~4l!yN"8 /)U㽚z$DXԩ`45_f~Ȯ̶]Nyݯ 6\DPq׺*S*{38)#$j 7 ˪BD?דj+k3ڒ [95K VWIwqğr-sJ6ט9oť:dZ<u |~"5-a/FJ`wCϚFM/B8Z^g?msR9GHq2~{_ |.#ç{Md9_ RP&kMu2}ŶO !Q:3).rm"K\j<$Mmb H&-QmT[8ݼܬmz1\Ęyd>-]# ?Ϳؒ#4ṕ=-4JYfN&qYr=~ V2.iJ ~%BF7{~wf|wwkT'iӈS çL M`ݮ!'֎K71{_ B׸Z6`tl{Mrz3}L4QUIwL?| 5?(pU04ԉc#C"i9 B#o$*SH/B Kwb.\M0 P}SmD:D!J(^@VN,} 4'lЀ*P_I?%0[K ޔ*H,TbdcPҟ\>eTEfa7MI[iiʉh'7} N᪉q'[3)"0*GJ>X3ءI]O>~]kC(T:A4i&҆m@{Sjq%Ϻ"W#%ͫL.ABbUDޭ:5 B4huLճш&7YZbGnP{ {ZTWJ %ޮj6$vѷ_ןn=0eTYXZ:e&!Xx`3&1Y좿fRlm87O*0ՂWDsP7p#N?R^Dwy~Eo#?F&`bdYY`͡p*%..r)CʳەV6LT6|3Vs7dgtJhh zJ籢9\**eaq^zm#?vt@r6)6޹?2Ѩ@bͿY`a֢F²q&y0%e" +u1y0B@2]Z#keʴɗTb ' nU_6i~/xk>̨K:@$4"GmQ~g /`!xYg7[]D5k$ƽb̑jsʯ4oS^<`b6ߣ׉2[q:T ެaIGlbь/oc᢫j+D栟2nP9gTI8Nh|4jUoxx_L\uoE$Ȓ@ #< rytAqf`xֲU?Uqy4SR̋2Xw@zU#&{ȌutQ">WX%Óa7MS)1YWV7К!:CnT =*+ ]rjY!D?-]mv@EWh1%E2m*4i , 5oI=yScldUu-"H5MN~=hD;BƝGDHm`' ߍrvX#gj͏-V~ai~ݞ4lj܋E~ݷݘpԓj!$@x)?XWBKq4 ,~P%C]՞јΊskָJkʝbĞvW:4U$ KS-ź]?mJ`NPJqEGYy\#;ijfmm}z5ЛG7[_a_H㳽Au*(4#CZyL>:z/z3/dV>wOYZ`V=S= X GKLi .R 3e_.O?G2s3z#, UJ^=`8GL3893a͸RNa\jyY!\l=FVZ+𩤯_Vi: I-ЍYT8\%_yao(.g욾.LlCA4x맙IA2X_)|yfQhOʪ n*h`gcr72)aiC"5Q +<4P.O fM:V~?ߓ M!;؎wFS3*m/\rڤC)bg-1G v`tBρkHA[CGthyoB<'S[LĶc_jF gGG3+nB| ,jDpF[U<ө59!$oӼNkR&;UO }C$:Xw1܂:.¯ݫ0{tzNk;]!xK:v QvJ W10?F*"Kffzt{~^ 啛)LL.z~$M_ذ$N:Ѷ9D,m5!qاz)~5ړ[/怰Mr)DruF᜼2GȧdhhFo9`N2KvMN\b`z{SQe't~pv}(SNxqDJ 1΃eLfp*i %Sa/~'Q a7 J4TGM"gZmG|)}+"֬25i+ٔrH$s%gXNE<\ *ϴ}b: qʓJ0̧d_"PFAhk{)δV V񐂙N]u4nHůi3?2j*f~3ݘvk|76N±9J}ODҘV 9 QA=__8K{wvq\?EۆӗK.<q\;Tq@÷K9ԨALھm'B(gt veMs-QBy, 4mu^=~+c/E3kznZB[%=ђ(#fj.$檱doUPMKֿ._LE:| \ ";N dSP\/+h4s}2bgT!F/P΁XzX"-B~|Z Ro'% !!\O0tMEqbc`9BMx`LkGU UBNb׏ٛ/Dԡ'xh g~24ۚ[0/urEB7٨/Km8~F%ѥJ.,+5Qe1 'KEdP-ŰԳlG0TK V7N<HFO:-C#ES_H4TljQ*E^68ϯ;3?X0ۿ*aN;J=h:_n?* R"J' f_9Sg43pl^~+ !#v0"}%E8!% -f}MM/$[LEDug)dcA´{aʷ kFLk(2(~e/NvK#/\z\cdcGBH=StU^(@4T-^pԡk4uĝ Xa4g@teS;AW0Um/U,8 6Zb35%b8\0`t@7HЈsi.#}~Zr\. JXO@D%i/P45 +f¸eF3 ;˻;YEKMY 9l%G8E.`RDg6l+p,4ª$4{M^sh?mV5)>ZYwm'xݜj/dd"ژڀ8Z4z5c11v/ (yYV#:^Ԭee6>1 !h'8F3'P kQbാ2h`װ,AVfg'{U"xA~_)9/&RWv~:ߐLWM^ ۝uSs%{%q~,eփN4!żY#_)y^G=gA[/sUQi pRCVxQ" h ]@B6?'I\Dr b>0W3c՚ך`;x4y>m55 Gayx^0g5Z_f M8M4 hGUyhcA7lR-Wi} +ypLRgt5J;S r` +޲y{C="s˗(XY!lw%Ld o8}[atmR0ŶtʳoaRo 6'%ڸ jaYr&$!U`#:a 'o( us!hao<~8 %d1֩*]06 ar//։7{H2IowTV'Oqݩc$R:,J3묀(rw_Q&$pzf̼1mKXt܋SX\MHJ5kϼ+|= w#R`F$fl2y_: ц y*N`iu*kqylQ,q^gvo \xr<_sPܴ9Q?y9 4ZVA{_r ĝ[촟]m+Du<"YP/Yi;r^~B㣔 $[.Rcty5nلp qLoȇ.&AEl!YZ2CiBX? :ҧt&˰mũɻ #sy䫯=_)r%[FzSӚE9YulXV*?O=yWJ*d0{<NU ;k#;'Krhca(.H-CbVHCvaMo:$˷OܮnntҢB H }a4_{kaQ9݇{Q\ 8[ I*&C=ar4%9΂tQspEmN9k8+m䈅Zl0s@'˸LuCdhV!NG6Cf0g |sZG%~zuwYw' 'msblr zO-}R즞_͘åpɱ?z,09r%\ _m8c4'˷˓LifcVo?!7!*,S"˯yI S^ ·YrEJ1mϠ)90ӳτ1VE_;Ns =0x|@Cײc㶯QD&<"}o3k~Z6op\֤&o^CfW$MfGPE0Wknlao kH"# hPx $2N,NWgu0#DtDJ+7^wCO)PϮun֗ĕ+`R.rf =W3JyͮV8VYE9`M+9NgWKqU.'GI ^Se`#y~4P^8SlI|E68?cnڽ"~y n/O_c,5ew?;h=6/QEk(ѕa]cm S'Wނ; Р"~UaNW/[<9#ɻZ~{kxjuj؞S3oLJTsr{ P]]UG룦 `$*Ӳϱ?Yۡ]=M>F.u҈8f[MAi (Uc.Ԙ8riH ϫd1E P@@S#x'/%~ ȊT#F$ ޣpvG5Pކ&6ǧ6[Ө.|2- tʽܫ O Hlڗ+Uq8FIOr#686]ˎu%yx;SnoV3¦w0o C ~d?dS Q؁J6ڕ426剘vbe3h&hu1- cs%m?9{nz)%S'w.Ym=WJurAJφՙxL__h?_a۬&sjpMsJ<}ARF?rQ{PY"]eSE6Pߋ: - f A`9<DN7~3V~f΁CE4>z^֣jd>a b1 нxssX7lh 4jqpڸw`ņ 6׸xf(jwjv{%q]eRh;#[ IM+qIyK {.Me;,xq'4~IEXp+C8;{KLIkw/xuuMB͍ZI2OW*(zCBmk=snP#q%bsOqb?b4T<#IETr 0KZ k!ų֚nȆ|WdL.m)þr%9??%>B'rm>[F ûȈ´qwyz%ᶵ0267a[do4 @$|G<(>o.o>zԁD9KY PgvMDh$hkuj⇟jk?gSlc$"Z\;-?[ȜX]x 5Ja3@\e$ϾxMGT < \&F#H%+ sUwU=FϽp 󅎍DDш~eKO ʆBU.%ĩC6aU ݸ h^yGv+%`D)nPҬ*h \*lKι\n, _`cc g]Zg74 <,-9rb` .hm3OcYR-{,5 8UIQj'kʩGM x,ݳN2s~Xkh5TD+ڋyԗM5kBנĐEYҬKg2d1D 駋`3 *pS.b=!piJQ4"-|Uȯs5 >/e{F!aA_rq(wQ iT)=nrW2e?.3 Gd9WyPn8dt51>&`Rpx #r _ߞgSnn<x'R=J'SeK{dʒF -s\\D ?޾Ĉ&xp;C~:77$57Qr*KpH/)S^MmH-:Y.gބ;ɞ{6ɺ $AF:vM}JQʘ DlBXs{Baʠ;ؙovefԮh2fAPߖk9[ܵ t ^Ij+ZiJlʭfV8s;~ĜOM8hlnWטBX(E^^ 8g8'? NFcA/iMJ868 z6@^InqBUm"<[wR 9(<aLKC*;LĈh_:6:Ji}(/\FqacjOM4W&4 VϘ)D(o$lrfBz *;חNb؄g2b4 Ӆ0)fŐDC)(֙LIb1 C38ޟO-ì+I"g2ɞV[ +Uy, G5E\.l %?$JxNu22xУLƒ]pJv'P!gCOp&iE,難ى ^2$ % ţ 4isHjRPx XF{@wv44x5d2#紾a27.DBt7D VasPMwgf$H] 7(OkR}q4F?ŗ-{jdHhwlu[XȪL^R^聂M&A~)Kׇ[yG])'xaJ笭""+EiJ5zyF]Ql$Ky=*k?0aRVJKauDn9Ô!xnT,"LAE#g1P}o5 D7DP/%|.zk¾~=B^CGUa_C;DDڒնE~L;EHmIv>?(Ar!!Bݲ6gӴM1RJKKZ<΂Jd] Ki09S/:kE&Wqh0Ćt'La}m 18/t,,[#¾Z?@uF]ՠq NS M j͗z h%"#aKfu@}JX  wDF]Kqh!`F CC1H**=7N^i p *3TE^j9?#NMYx]/Uo26zӰ>^bev5~=ۯ!P]&ɰzE`7Վ]g!,E^y)dqn!{D2}V~ߍBH#JQY!PHLl "]|HZ +8|#<1ֲ)íYWw̸$;Ϯ&'9 iv;5sͲb p D;{$*T{H={S ы̗ !֦H4q6TB830qOlbB됦) XҢNY pJL_-oIM<[{Kԝу[+S^g_h rQ/ EN5"[ tf-DQ:E1єn,JdrIC Mf@5+T`z7@+c˞%!gLD>u8 ^n&3WD'~䯩qug`,KնoPї[x- /-;X=q@IrN0&ZSu}4-ٲor~S"LE:XQ^rS\x~GC%%C+6‡i5?r)@!#[ Ĺ,ݻDqҮ=vۯrULl:$ ^3;TD\cn1܈=ΓFLa/1 }DM<)b *>ʈT ܺ{8յ#}V%Q7 k lgI-߱&gP0g%`ب'pC~%yJAL+:(@ jτl8b9)KamlS npYTir*6i.!luq=kD,Wvsv˿ݘ!9-=ey{ܝON<]C"?'M(1<ݠ5iT@]jO&qk^H>]?y֢}z+>Y&P ;X\4A碢-f=r-kn?qGI,m8O-.C~q SIXD",hzWK`Ͳ¬=O44ׇ\!AX(g61oj,H@.ËV^VW4p*dY$U>qPM g=*X[rߔǨ~ 1yzFў_Jjq| AӊC Cv#Ѐe:I wʪm28LJW7{D qA-x=_YnfOZHx{Qb?'K*Xq!b4z-FjD<1 z5;0?.ZѻYσJY:׬ 2AsE `嗒VF. O{/P'C^h{ϊEiz[hN:,KlxW–X-3@Kko鴶5 C(ofR8L2= kR(ُ9`%O".~mGq@IC};NJdsdhNFKP<:{vl_WM:v ہz85z]dT.|vYՌtdB16Ĺ0V=Xij|m3~w"+udfطdSYG߁y sGsjTP hz Gɪݷ X,RTDXW>ŽO) ],D+ OQ *:hpl8[lYaw 7UċRggAnܑfH|h;G8xŊƬLn>ּ r+ &z~>^{0.i@j|-wh؆%׀Z rʨQ4 HPJ= kct"7/5/t|vwR2߯(% Q͸$w坐y ʤK^+] Dn%`RV;ɄDccQ9K9\x=j;m+oڸR(d h_M7FdtCynv |) |?8e۟iM}#]Fr5d=qH9 z,#x ^VaXqMSW^uq"HRE$Ch#6BZђ 2{p3!@>^aofh5 5R3K;%&0s͎ \V I^/aJ*́}s\(l$;aVCQMWzT5;SHPKv[zޞFA:G)۰5ssd,Hدpß+σX}5]Tnkpĭm:褯g k /ez Ƈ4x%?*4[V zDڗtدvh!!T#Sk Wf2Ԏ3.3AEWe9r VEΆڲx]l:Ml}hG[mrqթj$jUϦAvþxYY~}E>c:@_,5AvXGg0l (T^*|*Cnpva]`Ng59GE¬xOeGV5k Vӳbrr,H8Þbis׈̆fhUPtū9#b/t9ױ,V'oEܶ!hO0i8&ށ,ʘ xUy2۲Cݤ{tdӣ<OM_=4fMn+WǞdZq˜o3e_n&1jqy*#W]9L/v6SMw2뼇CdkEZhԜb'Aħ$0 $ZRa2)ΚCC[?i'lTM?PE"1#HB3: 6iE٥PU,1RZKou>/uwmMHm@*pulOK3yc>mM<{3}o$ƐmLn\;=Yv>rOY@TEKAUBvda6je# =kH^dwDX)sF8ݘjیnCu8;O]; Ih=$:[ILkTgtEa!.7)HNB(F]U#@G!v zϗ3-0 o/frMjbY&<}8}'aI-Z[ud:G-޸n FjF,LQϾY VvDA|yPÑr˻jJY]P!6K)'r @FE<{Bꗌ]1q4n,ޚ GW3'tP`=YXyNhin;=Rӌ1[m&$yѿknb/w s-{4zrRS筱-_yY2׈z$Nn$cOק}OmT~•K7ְj6!p| 2ȨkUR֦^e<|f+< s6zO$!=<ጱg endstream endobj 492 0 obj << /Length1 737 /Length2 24663 /Length3 0 /Length 25242 /Filter /FlateDecode >> stream xlsp.ۙXOl?RLLv35P::dML_eC*C[Kߤ!b)BvH?ܻ8Ǭnu55t xY)s2UDivM,.pkd_ÿ &:e ],=L j}#(aa{ozfv=+:9ڹ{71ڲ1oUzKXhTؼ5Ao>x5ԦYN++5ʎdyK$igk i=X\\ 4kE͸TI"^ 86+稂+=L~J_`x:je{Hh{;Wj :򾨓XjJ9f \͕PZuhtyY8H Qdo~/͈xSws;^5)!BovO~* Oⶄǁ  Y ue@5O'UHahmJ _VNbypeD+ޓ,v;)Ŏ|;^>ɢN/dCY֧?Ʊ:Y :)GC

Qu Q AJ>2dp!7ISGe˙qeFd8*R]_di݃kQ$z*kns*W$HcZD~Bԉ.gdհR߉cI4r*,S2]|.,mqkߺ!I١OsFlT"XK  }`? `v4/|Ҫ샻׺8oG.Zl*e):?CǹyT7G3oÈ!nN̖CA0¤ R7;|Ƭ{Kc'r߾̓LԬy'~0-yp ,*G{Z VDÄ$OE,YlM1`XHग?(:mz#ZGzz*r]D-L(P;vStUXplK𢹙^UXk3>zؤ(?i#zo)'W5$\(an SυȪ""yw|kvnA7oZ-dӑtܺ'e2A g$9m={֮)_E:&zrM<, JI.E%H0,cniMPI-Eŕ~4F' lo*8sד  Y%J5߽lj{)IpG EKlmg]}\'y)  ;a+-%)̡}pq\ARZ;E|ܤ@Hw`d-]tO=L)RH"`+On>d㫖RZl^qC 6|DT`3p|is/j(L#kE s(!]EwN9tpLwO`SKQaxidq9TMm@O i[ֆ!xN<:ìMEFgvT\o, :I%Mvb5ɩ"ޭ.@j&l-wnn}ͥڋn k!@\31/@%W:*/O3Zh5iݵ *ԽAZ;.4@d><7>,pCi)> Jv3xc)iё;-j,1 [ { +7L4?V$j'vXlLAyƘ+-2t*2_T0@yGtΝdsTJ'k.HKtqSk4UQƒ(/gVk8U }e&cH%jz= jCIZ+b.VtCiju? j[ϾRgpc꡽ >^OVCLF1_zF(*_r h<~8Ln;et7¿Yy]4Uh?6T'R^bmȁ R1lPDlW,w >A%ǿBMZ5Uʚnt.]Hu53o򓅘bL9:YpZJLh-<<ďju[֙iP܂z<]zAe`Dw?ozY0LٻWͶ޽IwipPr) .@lKx}2esΎs3%{N }d!48e"pt/kΔ,yF2~>aUɢR u-|ݕO{(y6n`Px盠idbk$[ōvHEA{Gtobr=IET^]u4V,j=nP|E3%||]ʁBzvϮpAkuލd-ԞGܒ8-̘p9w-o;W2Qh%MaD*8y&5Z'(U|(ePDi3FDF#dRxSK =Ԁ( ]*r>$ugiv EW0)1SFf<5/gciG9Z 6zQ}l-c&,*M_A&_.=򽝋{!bآa#.~jty+R P9ʒp'X?PLƘe5t˸H:lf``wKжt%;ѼGX32TܴC2$(#dлsq6{o5SL}»UQmemcI?(uhI L 7̜9t3ÞÜqvxӘrm mP4="~1[/W80h^^R75eb;)2p^r7kCcOe|1, Gb }t>9 QzFyI#e||&Է8sBkbx sjdJMI@ )vs&˼O'қU@r;)\~L"-VVJHFvT`y,D'ھ>%Q-6nE\=7g 8S# 0I3ۗz|pҵMWqYX,2w?t2u)@}}he owGɦh0L{omj_#J*4h@2I4^۝ aw%KwGbzON|I O:?pk޻BɁx&?ZA֘X~&e#s䵣'"9VH8 nzcMſ/TuhiCR #l{c">M^V[~aoͬFfj>|֥5:x{$IpVweA*6@+ȳG{)l&ż!ui3>]:f7%\dX(U[GBvirfnG*IiQ!zWAy6CoNTԀMfʎ+-<؆P:D֙1%[0Sqsc}V/-c%#siـzD>¥&L-v3bO܋7Wo f†[Auv8 N,}ݧguJN Q9p״Bg(4I_6z[vɏPę51ssjA(/M:}c</OZZ'JF LJ'Y?Ik!YϮ+a$϶@Oo{rMfqpu2HN'?3tXݴ}ҙ: Cj)DeTrRMF3g !5sSHM*zyIY>Gdtt! RE_p +_'ڮr.G R}ɼOݩ| _Ha͂AZ&:Jz0 OJ3X6ƳmziVV  O`x뱸sVwŀtqa/Pfti;/,|M^HRGc2)p8^ܴ&7[=(*(AD7~B-]>iѸk(Y`z0EL@fc17VČjm bC/L~m6m]x-~ZawVQ"I yqw*nC3({H1jG?* P&|uϯk;A'r>(b΃$@&B$:ga: 6kXuXw|JZy y%ͭZr@>1y YUo/̏ѭ~eB)3L&sSb{-_ MEX8c? 2zϹ~ުM͔i kS:GF 3O4så"M %g5#$Ŷ}nNthp rhBs(Ә6-5|m y?0tփ!uGG`sC 9BRu#kPf띰$L*6 d)nq-HXעeuRp, Pr~[3(eVO`G,~c1)N9d]]9c넚kۿ W73޳7Eq@4 C'^+-~Vߎ@tTչJ\1s;E2uY [OcWlW%jT);[qZ#s/F,{L‹kiߌ JLK -H91]gqpz+sFvB4[Xaiϊ+0X4U&h!؊:JM\jAsTݽ>ofJh9{v2AQ$je٬omV~6VTZOaB"@0툴Y B{hT#Il!`a5$lxmCT쐼l?g5Ǘ-f{/|g!-Dm9ן\ s@P^ ޽ 򁷛+H-8>1͸bM?~fVp!)WN r1Ư~eԟcH~>D! >9HQRu h|k۱f 1뷈FlWstG#sT3B4f ͹\6W"`zbu~폽1 @0%r:B.ʁwnYmTkE'M_p]i&xZ=*ze(gF A='.BἶLW6 Ȏ _nt7t,ml[{K6 `oi{f2/.^Ȁ^Mq"SR 0jb"휤HHVe,0+^X[+9ӎ{԰o($=#+cTq%@Og@T'r BUx TLh3 y sѠ5AHj9fE߻|QCDY &:1Rm ٮE:<((5Ob{6%8s1̜#%7SRD0/9,^ptCLSE^&F)sъ ~̹\D;xx.j_F51Bf:kzI uw;%)GzL<`*dW˶ {%"4O}`Cnx",{ɗK=!o*2/dH ߁c59UܨY=g ێd !0̥cdgNF+ O,#MR[! 1v`s]dz$6.0j^ՙ: )%3D@pq,Мg'y7p=u5syDPm^LRTBJـG} ):_ =5P2 Y~v=&kOݓ9P^2فN(Ut(whO Vp_4~e%wFVKA-c̏0iV_!QSP7o²l|Tb;?x&oz ݦ /L%94f5/K4#9[Ɯrg,~s9Rg{}+aK6}uMg#T}9i Qm/ǿjDjaK)>:%ei&q;Ȳ b%6|s"G=#thg\ZܕX7Q~Cii']]m]/+Q#2Wȓ),AU${W T\( M9[k+gfBmz'CW-ώUۡYS_n!wL (rs?T H|^: K&k8bqj㰕LC:(!?lm.Bؓ&Q!!<*w_u^ݜR[ӄ)"|2 BaN8Wn%n2W3gm]VCsG[Q; .Mo4% 7ѓvv3ƞ_&$Ѡ[SE}Zdd\oUԒp+ h0a9]Xԛza`eE54ם(?\9FF3$Ρ@̵ `' Ю<3z*ם Q߁5/]M0n$µD+?Ɇ#`ŵ f>yIr3p:>yM@BI!20B֢@ToXu[-!ڈuQ`;2F9C1b.ra8=M<`i#D%CuD}'# wlbUwkK.\ 9/dTؘѺmRF`0"oy {knBxn`$mR.>2)mxT 1.vPMVbf[C4$%+R.Bh w̎J&D+dX<<cMkKT߻@eZyIA9!x*5RawNt+vb74Lh)Jas@lƷeJ[82<ן;ImNRsk=浡ՆD؞*vJMWPaGHm /!|ݳn$?Bf"Cx75nBcmDWsRk|3hZ>KrP͟k[Bj# ƁJz ɕq Գi.,Ë/vz7wJ!&iT?ǘL9Za)(IMb@Gm"0~6/PhflH駚Jmÿt":tL{Rmk7Y別[Ohz(fO> CGqnObr(5ʚ9nHŵqlRBɸª$:": L;RÃ;SpF;&5l-Ex`iZrdL-ei9Zm*|jNK)%_YnR{hz h3DᯪK-"B髄pr۷A ɒ'HQ ns,p4Pg޺iK4c퍂;\*ǫ_akjps LJXUIjmK~ 2BW/ -: YB4ࡀ1gd/%'#Y@d+~a>~$`RS91 1P>֢xAbq20ր1s P-tNODՐͥ4JH^tY%VlUwνМ+],om/y,anUͻD"/tS7 J>[ǷNab-f0BbA8SZֈϠpg3'(aG ^"leF+)}ܣS$ߥ(&R1v\hͬT73C{+i[Ӿ|ėPP/>nBTޫgLT^ˢ}`j/j>N hE)<aKSs5HW9۠ɂ ͇ʤkK0X+mgCzN{hP[?(L{jҩyhg).bc@.4o@gdGٶ#\w\zuI:bՂ/n0 tk2h0VMЈt[itB&>y`1k͖\EuMҭs71k_.af_z^r΀Ҡɦ^9֙帐s~Ma}gC.~|1gD%pi®|8 ׫ЛAu Fc?D d` ^h;FcTK$Ox[^v f!~Jj<[;q`6H_܂w_fC<$ٽ.а0 Щ\b˒pЪ OUkAΔ&`\#sdQǗI!f62HC'08r&ύFLӘY:/?nV+Y} lԮ+H%])^IjaPxfFiNη> X)`iWbcLYM5c7ҕ4.g>1,ua-W:oS?."ń_}ńw|?⒋L#Jw=(uRvtIiFo_ Z5+w㯩UR gKjՇ,ڊ[P/%RAjZ;4zȑ<E `qԭ둖VAz/w]".F_H-UKd'z=YY$)jYeL޷Z5ɶM#A-NJV8=Ԝ.̮ ]kT21چ E-|'pvJ?̾R;iU(1':~`6H|T fWV%ScR0a3;&L>BFo1ɤkTuh߱\1/%*\WJqm$zjjl(W'a\y7%#@𒆣Ncc[EyU%U ww(3.qdB#?r9UlNIԔOc4 }ZOC uő9R^TW`u$t?m>1M?P@S#8P^v2V_JnBЯ0r7ٝI4e118!eI2"I// p3\,nGŸ̞A<3'*䠓(9: [#UA \DfEb[TU?V ؠs ;A sPyGEi+}=n[;UYLNg {t#{A "2i/D s^$=&ĉaZvuF%z"YWV]&=4$$N- $gB(£6ܐ1 E++D*nl|ٝޱ ETvu;x֘OA,v,@$eG5E J-Qx^2\\ %ڢ ?$J~Q(0dD:Q,qHO5ɠס% gY_n}ALQ!PP8 e4~dy۠ e٧6Y J߯8y_.6qK0>ĩeWtH/Zp /wсWൄѹ:K4!@t03NAK "a}' [(߯Y(RڢekVaG1 $^OÍ*s%P%1 `)(@1q:x/d+޿ns4sNM\!rN>#oC|%Me]I-2lx 3e .!K!Q7=|&k rFXGqW_"b!Y S~:k.JSN[ qX\ ,zuJVtĊ`oO1(8ҾL\SqbjZ/o,4KNY,CDB6˅LSWdFn c"߆V,"5[7%Sg,@QHw4LLe>#Pd7U*sHnzx4!2PU{$ZSUYmYq\ؖR?TWRYjAΦ%Gq鄜P-"_y?U7 bc0Hso慱ێ򮘑VY O/#y0i|.d " n*X7/ 3c9?ܷУI?f b55ocnj:rٝq~  }!^egk7fuM} >%홫':cbB8$doSnA. U{?;eٺDs/W2'$_l(M)7~)t"P؂= M/X"%&t([8(̚4esB\ ?ztkKym߭J]IɳoSQ1Ҝ,0 yMBla$XDK1)7舼J[!bWHQ/Dcϰ\,$٨q*KL@!1dj50MQB|{9S&-J\_y~У)N+WC|ts"e1#ɌO{_O>Dt3,bF*^xMB w(< ,VαSxդluхȜB<0&[13}ˊ:)qP B [%z RЗC^J|0&&v!tR\xgJǚ ܚާSune!ShQRC[;Rԉ$#4"N)t=mJηj,"dv!\I?IT t 1FӃvcLD؇|B( ,]+H"UR?!f0)"J: ER xV]&SA:#󒰠\Ġfz€x|}hy; "x2*G(sVR-G*K!l~XzSV\{# a+wiH5X.tobn oer X-Y~r!Jxd,6ڹX[OT{;1؀q>przB0C ( 0 @ DWȨV\9(BjkM[ātM ~ GurVWv2雅J>^Fi0H!{+/ox+03}m'[І[̔A m >8>tl6 0}N* w)\܍)]Yrl]&-؛Z`wyssM `k@>x L-jq[ߦvz!Ƌiϰ[y:Jy~x w[`,hӢzfTYb8s^EM\0BIA͍{~t\DUn8Q s>Bius#PĽC\ Q'i0 C4s/=yM`-krp*)fRZRQârtwߴuȄ׊ wx8o:*(7*(cS[aɣ/ lF.&ى\JJ2xB]L\8(̧g}6l4iuMM/aW:?ЙT͉^8nhg>Ί)Q;w ;ofk K::zPk&*QU`C9Eo0E4|˵7J7Cd`)sP-#zע[@[╷= sÔg ;~T\=MM`8NxqK9[ &#nɷn VcH?3QyXK^"xe`TlIXy}:!a <մLwu#~r9`H_wh m@;KpXjKaUE GՅ˩ɳ="|]7v;/`׻o@W婞Gh`E2J a7s5|D/eScKj Ef#s}aŲ16TS\wdv<9]WJi J5{Z߭G&i0{_F5n0eU uMUREE Y"4qUAqO@+8ߪMs߬h|ъ=5 gJ*h6G.B[ce<{h<z(lta,Q߳ZiLQ4.1Ï#_IBQp[b^ oazZ=Yi/ -%&h7/Y")uEڦk%_EDՋo8;a+bY\'%Vn6_FyX!.mk fh[{YΨ$|ىT;.r.E3럿TA~,:6-kJDkehT{Bs^5ހ|p:L"&8.b}ݞT⾖`) "_8ﷶT$`RNHgBaZ9͸K2}k7]_S Co]Tf=3}Pcn %*A`Ag r Ӊ>p {P_֞ꆹ'ƐzQ C yX&8;{*l3}z5a.w@k_5:R\rz= MB۩KDpbeɗ_#;zqKR~_l2f;ic.NuYg -LJӚwyxӲj!9b'@3"#M{il5e^w9vz<%@dp]O;>@6Ǘ ya*q%R:xmTI/lw߾ZVMaI@]m1vi'ڊYkqnޒo-Ä{s%m\[)[" 5g\=dH_TԪCp[Π6I&ڒl6A.J!Ų- j1P2W_ݥŧF?]}=Ԁ˺GF7gkE `hӭ ]g1.z©<]Y[(IZX)7nlµUqu$NKV>PlY'8_.NMйp~YUB-?AbGS\x`4혓}ڤ|ou!?TV>``PqUt^vGx/E]@\(0#ObO#lBbgX D6Ɛ?؄sPV[[m75Yuch[!N ʣUȩ[Rc]y~slV?Wg.Sg1 倜-%RS 3~i-`G(eNCKHաֶ:wVբ9QnXU WofLjDI' Gl1֤B sڌx+ggv_LMGb+%F#3yxMI/m!)Ͱۻ zLJ\ nTR/(b T8"D|~k^⊄`i'pssI:P7rݢlQs3UgѰdZ=$Fl J&ׄu+l9iـ_Hs@Kwe"jVxUgcܪB("145x@Qq@dՖ!A#XXDAݨ#U;VSl[sQ똛-DT@!]떗-rGϦRw:4f ʛm bʣgG` rk]9lJ." lui\[Z+H"vHI{=-NL[3Y~E5Pgx ;F(;u$GE!Z`:"/$ ATX\uS2?5Tw&0#Nť}hR IYLm6R|D4KJx ̘\HۡYArnCn]F78dz(\ll, ^;趦Ⱥަ4_\m+^8\3c|Յ"9N '#70&";ZkfakNe5hTa'kp%DK T41 >esW1E:Yb l[ @tB?Aq֌r O]R@˵kXNoƼt5P7?|Oٚt98Mk-ݨi(wqs rq\BUMX'^Slea >űGc~CIíɾ+Muyvwj.ENc*YW@SlAm7۠>9KT0Ź۔2TL>[QbJVv¾0imaL-ib1l3$ڦآDBDsUmʁ"N%-B+Jl0@࿛Eqs9 DsNu?(X]ٻ.WBzG̦܍b؝)׈I;bPPn^.(lyrۖڧxGk\ny]l!OΖs&{,0m,i/N'Rj ~O j/aU>3ti]Pů^ tNy&jخ+-5:!$pS0q-aMIftGY`NtbwP(O Dʠ# JZ|Ε0&lx*TtrºoOX+!Yy%yt2QwOR|`aZ6oBraXcP^h4!)& CvY0`%U'/ό؄~Zt%.8'GSZ˱#EOvi񠅈`<+ɚž'*\de60oC3a:v,X%VVi?j~ dQ-ҿ[}.@)kD5IL> 5U|C35Kߋ#_*;)&zj8Ƴg\[mԲO!+&hz{h dH2N{A:]789ʐq-b<6L.|vIM@8)X B*D>e"1IP4ź /vz${jL\g@|~;^^\lKvg%%U$>_qH` dv*1kv cdpgU wQ!˦lTjqS3vov@Kc~[[3U|@ I\A~PP{Xu0c* x#%FRI:Aúecͣ` \z.A#Qis_@9%9Ɇq&F2ѫ?s&1=1/k8945;]Ag T5>^zO5N30Byb4\ZGzOB9\pQ&BT`Mjjp |ȀFu6~n+DDa3LA!0'NX##>1ouč t>}_B9_8@ D)L*~՘S;?kS$hYPx,ӐrvFZVD?=1VǻH3M݈k ܸ&G<7Dr}́c9.fUQveu2Z.w6z2S=s-~ylCP^_X[ӎ*5ܲeY:C"xF 7lj n*KD "<^oWurZǵO(0sس.`LV0bnIcN 5M͐;&n#Y\uz;3z 3عk: 79 1N')AذsL>N)DžCދ)iDZ.ߪ Ƚ|eL75`湄{盔n 8t7yu⚞ӳ6w)T 5dnERk}iR IS}̚PHu&+n{K>ɱ r x#b=Km±;wTi=jT3P-m@F2"c{b9ƣEu(x*gc:s2ukXY1lub'aܟzmus d%pNtFZkK-NE, IT3y9dfeU_9?7Dcꙑ5\JVY7΄ 6KGe^vlfW K`+XW޽%Xz"DaҹlWbZ>ZApR^aP"|;3eHzw8 iR WxG]@3P.`Sk'?p:n*0r[,Y3eytS⸩RWY_T_+*m]H=ִ endstream endobj 494 0 obj << /Length1 737 /Length2 21029 /Length3 0 /Length 21623 /Filter /FlateDecode >> stream xlcnͲ5ڶ~ڶmsj۶m۶ڶm۶V{s/92j1+HYބ[23##LVلfb mb`bCp03wPQZ[X8T\-N..618L-M" RJ y5@ kadbdB0sX[ غ8:C ',$ aPd%)uv'_kY2ߨ,z&&3_IٚoBNP!lkky#@/-6-1- )gD5GF:.zVN&ƊhbX?$gblb%L6]i{2K @;,fkdglakV44oL8;Z5.,aa;w/:&6V ;# 5rqt4u,w#;#`˴ _Jpj`axƾnؠ`fm[̔H[=m9eqi >3 5xU]7RY?G8iλ lѤ ;D'9{</^CB~?o^nkjܿD!Sc0Zk RKE!EjCL4%P!3{zG A#~ĨjTQuwp9-s^J>>"n,C֐orZ]Wc{睊zPf&vUM> xa}+蓠_*8=̳aQ/i#-`Zi1( iibTFdF.҂l OW4B=ϺHiɅanz1IJգ躑~4; \B` 9Zj;BM>ҟ _nA;&Y\T%ʼCYp}[;$⎃dH.vyۏs(;?ǤRǷ@We kf&o)mf~i%A9`&sۦ &j'>LSGf/,2a'FUL~O_u*q}3#kgZҐخj]S2ܞ Ȉ0{A1K<.ׇW55k@@[Ol1%$6{/S۔fBt_kMM|W{gu-$ee8-V{Oda&Y)GicHvHMǕrH}?=D|:*:c}6gw@ S%~>ͯ^',*XQYH= VW5ڭIMxY{%́W~Զ]hfkFv;>Cvy 3XR# 5!lJ>ߖa-|'A)փj˖ 1x}Nq>rvG^be 00#($2VGJ^xӘN%;s&a)%rM^vjG(}D܋[CV8Y!(\vVYRͱ1#OT )W`)!mIhF`FR:B-qe2ߑ]Ę6&fE5?;bX!ϲns]vJ2`S%Ui:# G]Y0%朊G+2A:o`cyib1ױlȈ:/iG%[nǙ])":xXGndP%S{*}2ыc`X-dO v'!0Aa#I9 t՘g@p j= BO9^2!9ffcOtn<^vUocl  hox=.+dC"O tdž,˓Ew% 석e6mεuW4Yp}yfSOugVK+nuxXJHdpB-0AM%:ș"?qB Q՞27ˊ O=br,@+!0gS3wY> (H[xh)^j"poȵ)?^_lxX'(+az{֞. YIBrBFt͝H VAsG0%myS*DT|*GJZ:EՍ~JAU"kC( Mݑ2?pӈCE6A y((㴙]T a.X˱U8wS3&zAԫ8//c]:%2 W AO4UQ0яQ8gM)U4*ΐ-^aGcE:+멹G~GO1:!҅^W,$uPZ Eli߀gh?L;NnX5kVP˻Srɧ"KG{:91`.:%KE"2%tt!ZtjkxO`󐛄Z~ūLT.RsZrUS Bۦ})9It%+GD"ﯓk"wl3$Pty P~>F &S6bixZILk3D:ğcKE瞟mXlr~kWHs鍘)#&/&mW] `R7XilA*;P io S.1!tuh!oAz9*PÚD>{b(?J~Qzuj}G'Z;۴;iRA9yl]6RKC9EJ~oq~8YozG 87NfbcmGHy(;7W'n8k\_9mx{7 5W"e wC47.)___Pu6kgJ9;bWFUke!P~+|tTbH1r >ϧ qx-os8Lβw OyQBRU=R- )Z4*üj[idyKw5-rwG0-,R3yտv*F,8)KH[O'5'VUꯏ(-9!%H;ņL{qyh=X4oS]BN %f>o:zP/A+.IuJ7c!nc1)Iu)Oxu+meBҚ$U!َ8GL:& O\H@XnZvi_dZ|er:=c3ӫOk)kU e_]WQk2c[X:G=l80AB!sPގneCP}&(fYiH[ְ.-fڻUѳ3Gu*hX9/4˱w:K#FFKx)#N#F[͚g"xj650UBp:\R579 L 4-tfVQzRrOKV"8 \*O()gMksl_ކ]Rµ̚W})plNO5䋓\ "''婶#ZN~_ܘ3= d`-x.dsҨ`PqjTAkmZ~mA8+aJzeĦ4E dglYc0?p4̘';yPnyO[h+gTLt,6xL'yxР=nMWA2_e/?Qi&DP"5r2l&Tt&##Ik3,[^2 >I* !k)(e%#W`Cd@^ϧd7;s>b0ׄw=kc#q=ȹ/mf T>xkaq>mϻ$fq|^fE8{pH՜)Gny5'P*I8 ͹2sxUa'JGXĩ-*(̴Py1f>|G dx *_=wSbi%ԫ2.xk,wc~ãl!k+"}} GBNϠD`Ri#/$bo[ϵmqv(~]rp!SڏPǘk~ŗ(y hS[X'|.; ωcֿ%()I7Ʒ_9SY[CY;61=QF؂fsGʦ-=عU-oMAh˥-b@[jtRGF0ˬr{HjNuCorLFnr(ևޗwB܀JXoX> 3Z%rΘ$Ȯ9݁OѮ8YX(ϡܤEhvBkXl0&9h OB1lHN֕ɺ6+OLQo1uŪB"MrҴl]'M(ݮ3>\Gp%2(J2u׵b kn& /h Fmڝ{mKr$7'IυI?8,%f`M1 Jz{K s&G22|fgK8?A/+G\Y ‡9vpL~&U]ÒNro>%XuK&` R&"GŭڔkLBڡ1FKyi^3 a/f*t"Plc2=|izBVvNUڒVW#r{ _-ݶڿ <@>8^ڱэZdgC:((Ct^.07{4? Q (ߤ'4"/<0ogSܕm`(O Z?T*wcDǬ`ZM'QesͰL!bwܸP킷Ax]\zjgBߙ9 | K; PKL`xzڼ!_煈-J"DK.iW ڰpv:olAX1`)pUf~+Uj\ SQC2 E!tw.+G˩ dG#LE' u,[|!ۤNҶLSj."̗FOS,y /(>r %xGe4 )/P}QgtllS924ۺZ|Gz~gvj9X锷Wٰ,cr8m?ݖlmuϭAP}dAԅ$RBwXrB^~|'Ӄ1+"CTf8iLVu6mI YuwR0Yʁn#]"0,7NL4#FM)9 TՐ'EE}k( yPT8fO,T*iIM+8%,˸kԛ&fS]܆.tn'&^@wX5I'Ym$0 D N7:﹋wj/`{|PR߰2ڽLH^DˇS:ŻNq /ā |+9;2!VCB6rg@uVX7?AE#b_opbJ&/n!a(qSc'xn)nHw% }b(!ς+8J"z)IvSk _|WBD=m#OK 8݌5o O湘UlGoR6ih(d+n+$u1sc'| %peu/VX?8$8 'E/j,'P@^b$  N'ݏN~:u* \,WE.[op:@l>Rah8R僔։ۮíᴖG@Zٗ 7ȒaI/d"7~E4O6Wدc3)Vti )$g[_vMiPY|=Qkt &N1LEQ/ hNiW߰j'G,`vzqb*@SX[U:H:I: {?[ZsQ;}d(JkG '&"UqVy&jð0}ׅX\yZZc1D4o z8Nj892pk W ϥxG*az?e8z˳z?gV!|Qa3?`)|`@"(/Ȟ.! =8|v߸IǓGC~ak.Ez!#EP&9>d3 3ϣulJYӤ3k#u$Ξ? \=;Y;xQù^{>H{PR}܄OǥIiueJS_S)5iw`$tlS4ڞѝֻ&s[@U/r53,n`Kj<Ģ#4xPZkjtde*C+HlK[#oO0D  ֑>B>X@FUvf;QnSl0@zS鳟3K/)RU:8GGl ՝axJq=h%"%ϥLo+VQv/|kC0HNWFgֆ:YU8%2 wueQQrt;%!Mwp*(*ˉa?SA<~ټԩ]j阖? #2񤒰;)=Ed/wm ohzn&mMydS(*0}/VGқ%RI3,JkC4{~B4Z>y'_|'Sc*nT%^{AūЩh[Y7u 8\UeZzX4LC= gM#A XBѱ?E@TK\W%g7l N{{~kfLm@Ev['8f tshq,s*gnm8,k]ӿ^HNYwãv%E#8깧KuSH''SJUTc #:cGL{N3޲3QVߏ_LAcF5lH#H cZR5vr}@tN*\ߪ(5#L-72!f6ݥz$:id'FE{54C\Mr3Pb٤*&7p[6% ʞp>[~ͦSWr3-xMo=dB0<$vt4낊&C:bګV#"1b?A%V2da6g(Tk8pľ*CɄAGN[JO2_]xd% gF붰17GcnR{{>ܞILܪf?϶:- !Ig<@Ct+*UQEL H% s .}YV#9^֬ziWDfa)Ky -1lGtֶDrĐg폟dJ5* @( 9#FLM'1_$Vf~@blC5f2N{ -uȯ8+KH^LʑR3r"7ǛFHi5,9Y ݭQv ^4xN)_qA:`r~tj[cHT\8B7h? QZu`uʧDžpVyf!"S5R8/T*S[#Z xKe % Y|{euqOGbD}ْv!px`/ 窟c1UfO럲9NxSF%40}| 0f2,NN1:T8P۾ ٘h'(o%m9a6X2p&g!L5(-޻9ӡN~@Kt'!@$smD[{xI#/I" p«t8 gʞfZv4v-\Bhkvo Ao昑q9_& 1AJ_bj 5  u'g/Hsm"ц%dbHEh`t䠯FFDll`x]? 88Xhs3 ]~6].M(>$ooPH?qprWKno%;htrCݎE{ q0T+s?1D)[D5嗃kĢR3p0 KkJhm4.T#ɑc&diGp >SB -s1;JBo'TYp!h8]gQž z@o*/mׂn "nz/d$I6t׍[W;Lsn8 )U 6el][=XK(^e?hZQ{_(v·(VkWˍ}6}'Ӌs$7D+Xg'UfjqLX ` r~Ұө |WD}om2{4"+L% KY$%#5#\`wq䐓 O5'v[ͅAl@bv S O%f6[7K55 n"߾$P~F=UfbD݇kyoΞ?`۪AߝBI{G6uU!VI|\#㕮\1U5_zMr{}Ʃ *bζurwR e%Q| h䴀7"0( 68Njx ^8k8E< 6AOh$tzXP3lP7Q`$C^CUȵD4LLe&"S,(l4Z"g,L]&,-AIniQK1o`yMl[-VJ%^h?Gu1-!HxKQ # (I'aMb#J$tHoJ cw7AYˑq#we[)+8m`RBWoÎϝH^LH̕}cVxBLw66i84Wxte҈۾GkĵU_/sZc:Azͪm@gLʶ'~l=Iufݶ:U:%?ǂ+ع 0q޿t֐]T _HO)U] m,p_{$ԏCY.٨9*]HQC"u PɅ:Ъۼ!ybmS/;TSF ̢2 S㲠+ɰy{C, T ^iOw3Cv&a_Eqx@&A Xzs&w8UV-_hـ7cKwWIGM 5ڜBA^[AUBE K]jr hmgR$ۏ7cHHv O B1uBT)oDoa^+ۨ~}z!bDa,pHf 7U 'د 3O^'ztΘ3Ab 嶝FpJw׮ǜC?#+s4d\\Q]M`tԃfOP>K_`B-_E"t6xtp%?5،œivt4H)4TDCci|U5s'E qv trǕWd2*2ܖEqaO>PX+X*Pq6Wݦ dU2RԐXRufQK7X)F4ͱW->4z/݃ڷԬUo!ȃ6~e1u |&\8rkM{ *a$dX蜶J1Hj5,SABsUr4GBȴ)L(i$]88N,5SԱ `6 o% ֵG>Zy3 X]nִ}h`6oxǤ)v6]/&p)A]F\{] elUY#|{,O f?c~-VY~%|al-!Yl0Qq[BhWG~n]5\mEat6-bj⭾Ny4j|_Hg*MUIHP sk+?Ɵ2Y6ym 6F!M"}:!'|`O _y7:s&٧EV'pq%BDz'uFġgxEW[ ^jM̋Z 2CM <+X޲\f iDSKsVD j,k5#&6&)Cʱʼn. _пLMi QM jM]GɀC9ʑ0otVQsuu3,^";D& R9/ HW`冎>{YpLզN}1ŘBI[GL7Ej}px:8Q䟼QB(Gs) *ӌVY6SYP~*16CViO{>#@@w#a%H_qg1JowU@V@{Dk̥l̀R+ i|=txMX#]LbPEt(h[=&:GqT-!xVW~acL-)e9yg鶼aЯiB헮 xq3<iXW 5.?GVqZ>m@-Ъ܆b\,omE~Qh5D˛.54)^iOgJ!LI&/}$f o* 񘛾@J(RaisAQL"t`mxhfutu4UUZ\V}0DBŅ*e94 )̋IH̽3qM""\:v?t36#TitxQa'>]-GTƬX dn:%JdJ!BX?jq0Z-Dw œ9Sbآ5-i^s jiJzNi:D(lqk'Te`CpW0i3d.fUi/*3~CVR10еSp/#c4ᦞ7*NW+ =7M¦3o)$Ҏ뗀OE!=& pygv \8%MSGhZDŽ{ٴx^vڟՙrތsac7?>J_ԳQr)>:ڲRzCa߯=2oHT|&^p ,HՄG1{,98D6 ~&?xWH4%?3fJlY]WZ55h;֦UR5: 噜?+[Ǝ(?3S`PHU&Yiv6rES"Hi sJvJf^v֬. BUGr+4?yr7=B6S cČ*;Ė4NsUkXJǻ7~A;9)%Sl$>>1SGOmu'˩wz]trMS",PU*aÞ*z2)2$& <"@8$.>yjPOpNr#S\)M4=ۺ_\xSZr+$7\ք'+vg%\mqDXze(3֫~L27Mi ّ0gz; ^ZcIY8 .#B'g7{sN3 /h/,k Ӈ2ohN9];:\o1rB,]5[b= ״Z. |K~bB1n3dc[۩HECƔUHbOu;݇>oԋ8Za>|!ZC0Ex.%dFTP%ڼ JׯKU٫$KO-Gra4"\딌]'Jo-jleuR :!GA] DDk1utɑpe&'Rd?\5[5 L:-8i|Tf0S 2O7CL"1}$%+~8uY{ uZNy0eD]O~(HgL? |%׀2gM ,=F"$=='YBzB8h:E1ftM=D79v^M~l8,(WMhC"jpD9r[Uu3tWܻIDa)qN'2DķNkzRF`8 6I}H L+M]0/w6g#&dr/!Qýu׵ڥάň ]Hz*1g.s)h*E.QL)](鏴( %'C^Uo$ HW;cpiBFCb9`PO+\ =QȢ"Э ͸J/(m&pPNBwhP4nKqk7`86*g͸g*xI *_&= ˔{HRmk CKol4`2:ʃUQ'#sx9Y4~?^/@^NPꮍ++} ڔrVB?ǰ{HvCVqW?)T^`D&mj:=xe`7BYL =3Q4}5j-rQV =tO";SIzqV SQۺkx#@Tl34xг x@SaΙTL_( 5Tbx덶8V?vC&/j' }RXf5#{!:?+wJS'3]\;ICwGFz>G#9Pt&ˊN1' sd0Rζ#FS(yF-bF&,NS.L2+m.H,UK%;\O^XolxVݤ.B_-i ]GD[X%_j:୥TVtUwxU[ts}ydAaxDRuA}pH*vʙzQ\k:D ^3E7=Kfۋ;"&TzkQˁ44N yV:h'>mcA$8>5+V+9Bh *' 7@,*]?իiRBS7]`nEܪV9/~U) F'ȉiZGԾL<՝YC֟"k?- F巤%Op􈫶l4I%adgr2] WӢ=NGGB@M\`^Dosh}MK9*[enfw\ HU{DKYݾ_'FJ_y ^B 1 p\"436 323aDԱB]N{UODi!b\ܟ&OM$W9`u$s{OI}ω endstream endobj 496 0 obj << /Length1 725 /Length2 39427 /Length3 0 /Length 39956 /Filter /FlateDecode >> stream xlcpn]5vضm;'mNNl۶qb?RLLv75P::MLK m-m<O?dٙCB&.jF?pϭx1hHjȉONۛXڙT\ -bL/gdfD=9t,&V' ˿Ig11OUZkXX\%85y[|SblZ"MiDWfJ⶜I28´{xAiqd4IYmfqg3[ ´݅"djWРۇ;gZ ʁ?xJrF+|͕pjh"dyY6P a&x_^hSOK4W`ZR *}~ #B UA=Ћm u硒,!2Y &ue@5O_QO`ۂc$QʴɰW0'9/]y6< %2|DCV2?xZy oZ{A'ٹQ5u ($S`M3AJY/ ۖZxXnd.l2|%=evB27i?Lmj*mc> Y L!!Rk@sGTwɣ8D0-fx!ʳTF[Ur# n㯱/bFr0ܗeL<+?Uuh1ɚ23a!!Hb\a\=\@Zy2k<~b @],:OΈ0<+{Na*lK1DG7k5 k'mf^4ê< hhHE@,0[?vNL? ;NX!:XP!&O>"lB+&vzq3x{8j 33X; rd2\F?޽2#m!Ǚ"ҤVmw-/'xJF9-Wj]iL2څ58|Ąl0ܠ7Ke+`xzO>3*yd3.=驤'ǁNwfHwyYzWrIlD3/rH;_)9}LT1YIRNim+ gخ +A3Av̂8pLEGfw?n6^ 0 4NjF.2'hC V +@ ^(N0:CGf.7hy;I4ъ_ų667AϘdՓ ٤-*#F2PX P}.TėZ7-= 29VgVQTWڍ. %+3z%,^ |+ U{ԖrBt'cNw=auՕF 05/B8y)cmm&m ɬ}ϥG yzNCgĠ6)ggIwlR3Q5s [vмɸc-H RIƉxSZ Yr h'w-5pxF'V)視>Ve2 SyX|Pi/[ JeJ \a954&xgA7'|ϕ{|~,M%&}H*Go׈*eAe>9Db+)2\/$bpBu=pnU0?(b<A1}6%SpP\Z㫎+.ܻy.Kj|&Ic ?cF{FGo;M2ͻe0_"D%v< #=AnƟ*xn sT$Cxn/7߳Iip\zKn?i"7TvMs*42is/Ii(ɥݣ]taVÂsl}"|y>XzծuJHNPyh|ƺ.9`Q|%9~ 61A*$4mt6kPȹFq$5L{_&]jzEzZ,-(n||)yBZFҖ}`W;uϡV%3OxWsf6cEUӑF\w\04;D$GUGjtV)U}HWPqϋ h61Dsbi x1\(]Xa0I'.:;جXSw5qAl"LPu՘ZD[*ɼn|Qi|x!;'߯ }^HX1Yx7_'x)ΚO_rUCщ=\)j(E(6D,6{cON I˫4-"0$Z^ muv @ LF8{1UKv?a'zOx9(VBpz1e^fr{hCs,."NSVAu\6Ԭ>rc.+%giGף3iT>2!lAz?%^+IW'b$|ò) OfYfڞ~+TyU\9LX4orsNC<1 }< Y;t"1Q`[6je ;#Zw|zl}7Ր^ |IZ>d] th2ӣ9.~? q#C'>tzb2X?4NּB~no;ͭ0SAl[.~5/`"提/!URzC@# y^RE_v2M99:!  p(s)3ͯW E /޿cc8Ε)o'Z -1p|ur\fvλ:fk02ĹVul6%O d8Ͽ{yX82g,O ^:RF. Eyީbv b{گ7-A$qn^;CKO8ZD{Vm=L*j] q]xθ;3q!D 'ռ-I)P{pU~RTU4 mοRH1s&ܶ0V)Ol~0!rOH|v*aKpӒDM[D:=Ie6j!Ma|ĵ%xe~C(|$vq7KF`ڠsj8XoĆh=JnR)@ё-0$|Yk.MZt'Kl~yjr]YoBB3.Fg$5|a'q=jY)Pe}fb4bKVڻdB [!{*!Z!WBcWu@H5|͍K-O]E`Jɻe$#4` UQ#_6GbN=8(id(50/,N^xxfY?I">TW1/ ^?hU,B &{ E^+O蝤a 4SmYiJUġH> ~ƜCH3ڿP6gDTСGbfdž~5U:E{MPz6ح:)%;47EIquS)LM u.`ܫTAymyŏ1'Dkvqqh[;}c=H1@w *ш5r&Nf2X4Tvo:ev>xg k Ք:Yf RެP|lUѭtJ &8/0%tӥB\tGdmp\#ռ#rs9+u2i5sV̈߅cy!B-ߙdkJ|r#6Ũs3q7s R~$ Gsտxn)PhC8PPbX-lNW"?枊}1Tt$] x Up޳@O}c{'4Ƥ\cX3"i`;jm$~pY^<%Se(_~nGWB,(ŀdtP0 lMt |8o;7G8'L~2lOknj9>Ѹ 't9ȹ+M$^Mxw 6ZBU.t|G[l A cGb$=Co!fiC_]KJk(!3{䂂s0o`+Āx ůdv7S\ޅ s֊Qx;S$iUb&IP?e5/$+P+Af-a)ceaolne-G&i 99˛=gly+;Xc5'mE=z6g.ha ٭3}bf;s7 b=EK.>cg3P4ѩ(/2Pjnd0Ҵ2 jIHAg޷aL$-ǡ#Fso-,-\mqKa9N"&7szDNN|nCoN#'vM֓AiTʉ%ssj!1DEJF96#"(%< 7F.bpQ.$ 9|=8?*epR-`kn,&B,^e -fpxFGlKItA"~/Q+Z/F,Ϭϴ"e|AY2@r$%LF ))D? BV1ffC`L\z՚zү&D2ג|I:z-,dAW6%Pgq3~p^M'(3!|I/t 퍓8o|P񋀓at-ZA:rmk?a?s-n*چ͒ :&9]l>931qʲi9}wm (AAx"yֆW6cLy}]HO Wdj8I9-tL;$dэW!@hQ2 BUR!jFڸТ R"mjBaX>3O[eiO$XĞWЩ6?gcgWڏob"?Ss*Fąo@Z]+ɽ}`hh b闉hOe`Z"Zë7mNYC8J7ښn%w@9}1z5^\TnODy,MAl].YZ?vL0%Q632&ՋD3~ehHB ,Y;[cuL:3JaTbWVΝ͖M %a+xJ"H¾јFEG$T~`h:\@yPS ,EM\uXIuWbEy5n$bx?_WE0"2[C)W(_iR ]/[a$=qewϲǴ-e畦) 0"}Np(Q;V;=i 4/yK-K9~fJ (+!D v0lJ7F`0'>zwKuPȌ},녫C >+UO?4HS)V5AHGWL$*}5$aptd ɼEhIݏw'I]@y/fצmdda9PCJ)NDNOl_^2=l¹{$gjR]:u8LE-,y$ev-wĒBNEb&+y ?U$-Vm`G"=P[YC( I8SC^Pbʜka(q?:ճES5=E3cV 1FǕރ-y~n"d&/j͹yY|쉯d9 8229%,ڪ~q;W;bJ%5UVYXȏ,#YJ~%Bjo >E#U*5x]/A!7PLMq@\p2Ϊq%fοG}L8!Q2RF)5a(k ܾ8{8ÜD{䬚i ُȂZM="٧Y/y|RMe{㵝>2~&3%Q%v2^Pͷ`{=+<=5+ǫ,8'/ 4##:UNRºZ?"ܵ kKlaƬ9o”UA?@}nѢ U>ȑ*`N@ur]tEL7Dm 2z+bWYa (6X4FMNheH a꽣94Q(Ÿf4>ϐx\ϜR*jdYl+}(N0Fp dvk@w|Q]8P*ܮG υ=wR1{N֯io! W^BMd2G_ EG׃E`o / u7e̹Thɦ[ַ]*f| Rk}nIc,WŬq[s ykS3~5Ъ˗ P5>L%-oS럞Gג\|q=؆x].+yU>p.LX rX+h.H=|Thf֌?GCҽ^trU)SÚ˨ßh/|d< ~8UF*6kBR䙒VS%3#,|lg8$}EB*nbUP-Q2//`%'p[l0֊ڇբWӦNXB)?kzNI1rn$)#`cj(&ŽewWsI>jg%v;/T ^ٖ;B':* ;с' /Y~ɛDbć:Y7K(=q$Tn;1́ڂ^Q/ m.@c|6>FDIݛnwG6(򔰞=hH7+TD7I?Z3bʢ D  >lіѽax#FSDf* [5&' MK=7'B-7$+82waw3|,`"y$#HTO܊]jD-\%± (]r0%2dVs뻸Ǯpj=UauQl=`lb(3LJn-CC/ oVHe[DartLz| łUŧ>ܛmiF~ B$a0ogʇI]NT&lmO~V>6Jn|4 0F+0R W9o|y YFM{b}w<mH.^OBtj%~} یUEu;5Ҁ_mW7g2a\W 2'.dIȽP~vWG__3K#H%vN1QҪJرçy,=VY**/<7CFce-kЎ'jwCt0sߎzuHufXq_a${o~SfL=. [|d8̞/ͭǣ^~Na6n\gُ,q޹޼ue JU.];u+G%{Ǖh4 ~* H8on}3#=}-t W@"x)J0SDEX٠J3wR.[S8uu&,pIoq`Y'/NJQI[8V\Tm ߜۚ[j5˳8P$6WA#6K:^Ӵ^WZ[FI7^Ru>GcYX;ḰXh8̏zR:0hH Y3\2^dʡW1GɆ/8u~lΦz]98c|h3 S))|6^څ^aZZ#-QGZΎٱT2W=_w,ywn`&|nD7;҇YkwX}AZeORN*:Ds65:},]g;q\=D7nշ --J sJ;PR eSa8#hBJHϳm(Pў*hOv)e :ёIO@97qzb6fC/RѡȢƁfpx!4xym0_(b MdG'2f 8++K>UU3:%D<5r_J95}Fc+A.@:b]K1'"i7{ sJWARMEK_5߇5fzSWweF#X DŽݎ*?{D|K-w]" ѯuyt{ ](7>f AʸOY{ 'd ~*..kmߐgNGٮWFooEmAݠa2EO]^տ3 XѻHfM}qU/D;PgZݣB9ӈA=-{0>a%Q#=m.M,DMՖ`Fȇ5/͘]}24D+C*.~i*1~qRe<? C!@\C|vX* 4^Gsv ]) kU}}gx{,.5sLcu!W$ynb5.<՜NL!SCmy쳁Xc%5{uQ7px|I}J$z][+ ?>1E)-8]LF~:wz  tHI:@n7z 3_#v zx+%Q& Bu'+ 9ŃsN/p?k,]cp@ l='j46h\gWd Q@YRC{ٶKX.4tit@db[2DZmJ Iv{S)leJ6#J+3'\W x$ ?{L&;>N=)͸ԝ cv;A\l4M7ejERX&HxBcs80/A֜=OfcIY\Ƿ9(.cI%J+ΏRIHRaw&3P5UM⸵ӒCcCC+,uM$}Ub8V nh#c<&}`$y O2eWaվdyMж)Z"]S'[_ۗ4?qqo,6 [0&(BpNԺ> G&V7U*}tWM`cgaW(8uiidW7..>R~}"͈xFs>,D`2.M f~Oވq?v?|bS;Ȝ=<8Ԝ=M-x a QeY@5 i EW2b_ JcBb">,3eI;i@Vy5X?=Cy!0b _s'V*04jYw䲡ę@turTcƟF#\V3*{oy sktڎ<6\d&# OxLxEʩ=;cpM3/+k=S(y6'e"l4M2V6 @RQŐꅲ@c,0Xpvѹ/3ʼnV]gl}ST$`ɭi䝘`%-_jXR3޲yۗt"r>DaȔz_X_حcU ٜcfIL1{JvaCe,;;;*i\# V gb䁳,y!| ǜҸj:`ܐURT4!L,tǧ|%8~ŵ`.(84%w*X_TQ݉`sc LC S&G[> $*|1{F+3'gjgA t `ufQa)鵽gPnoXCbؒP8[P8RcZ[Fך}K%_L1}K*?#L~:3htg%O+Ag>)Q{;枇[3*BFGCe EUT tKڷ,:㚨sJOt&w7 HXţ}Ca岜᪰A Ik(1bBWi 2+*G*Vc [=b#d}8oGTV><zR301tatnx&,""EU;GkP7F^^5KZ4=$BJ+oiցkͦs/chU}fcS 0>B:SʧXw6*]9~iɟfFzo+k<@  -gɣsR:Pm?1 JD6ѥRu+(:Wtï[Ѩ dq! W-eRiȸrƅaYBDZ~ug`$}\ $Sdj$O=(8 +ھD#x?f{ p̃P"%`_"r}l8m9;*v ]!ºi~Z4sQ0 Bo\ku2%?<_J8a%_&>T|o[j2QՆRpC\a,E_-2e<2"$ſx(_"=x>V.%orUq x,YcjKiȣY ^ʚ;ۼg:sLQoՈ1׎ ny ,qkelb7 Ll&F!Ǯ| "A_J; Wڭv.bԷٶ0z?2&gP_2D|\S(Lo"i|jӉK]O"_)-8=t`4j!o( t`,w|<0C_$8XALљ,0%Rm}>49Ko@3Y9Mi޻"CIv3X̥Z`R,ԝ* jo=Cگy 7 ׭!n{yPx~-5f#29.ʧ (+ GmzI4+}v1dm&gX{._Ȏip'RxV$bF^M$w0֊h ^==is%7 9O ? }Q5}|kc8'xoNdǯ0hlpFfޤ(?22\{cҪZ09ɵ@(6E%\kSNJK,qFR=}i_"W7A(|R7R$}|R(/M=#"L @{/22]{{ѭ#ᒸu0ť׭P|*7Xx;(C@ڠ|Ғ3֐C4($HWX*d!Kcv~hL:ŒpWi i[ <1"zHe0Mp>scy3al5 *O]Ԝ߰Krɜ'5e.$LR;N>yNNf.Cx'",Dz\\b K-]q8nҧUph.,e*NLz~07!WW@ֱ YOOJY *3@p`$~w/r(=Q)z*~56,'"-R]1Y6vi<+VrT)'+3WK-e*3#7P{=]S#,k> ~/U>O /"ǒ(ғ0)yc!To G@99 yL5smT.kHg.,&˫tv.MO#]ڦ aD` m{3$kI MVNϨufz<5b7#En OXv@qvu+g͑$p6[}Ak-ôɑSq#Ob\*ق*x-LDZ|0ztW(GYSq 邹2Fcj/rs*^߰.O^.⹥DϧRU0vx^ΫܛX L ]/DZɘ51Bz wjbyE Mi P Q9@jYzmlC|a=j*SK•3%>$+rJ !oyYK_x1!È \v7Hi"ۺ-{(~a%e?FNH.ӳi݈qߤ!>@CiI]<`I%уt zH[3G7&IFTb-]g&D".$ZoRJ@,&UV.V#,OQ$K. At`x2i/#^PZ4PjB=#~>D߃K?OH;Hg$z \u t}2_n8p -oKr?ZJ Ғ:\kJC\nd$E ]e*SnލW6˜€SGh//I VLROYq G{OFD.bZg#!2x@UQ׏whG./Z0-!+ %?yx`-`FFb'e#kh})oitۇ0':۴hX>?R(u`=Az/jUqΉkcae%؃Pab9 G{0ZdDfhލn.~{x<1D V8`{q<3tlBEY[R;{dØ 5ȎOp[ra_ob~fq׮42>dBZƚSIJE僽pH xLO-@sCmcPl?wڷ :o7!ϩZ37^[8(ä6$0G\zlX o٦4U*=mP'fq hZx{n;.|/r [n -6S 9'b'G{6Pmoˀ$}Pۘ)F_wk] st@R4]'óEZj/(EoMwRy߸A]nF; 4LvkEWˮ\9ojV4&}=-;E_SɇLM$g7_`uG=7 0+j1` tK+|\o~dO 'FW2[ ^'+dU.)}!ݮl~Ws'F炠 W3Mݭ}Xtt3;)XLw5P6^8ɳ>8@캺a(:`~+,D 1颵:6u='W{L[[φFfp #B 8Ѐ٫g{ "SG >ȀUԏ ;-?_! }Y7 :LZPuF#{wwZknu_D%0xDŴa?u.M;SH?I ~r >c^H}ՓLj^V|JL![Y_Q5P>E%N@^B.('fCˁڶK]v1hu\LJd/_Tm6%U@qX;۰wDCD9# &3Y^{\c“)&rwis |Ruvҥ,~Hh[&P EㄕksEKq1q]Ð=Q\ɾ8iqnQao1Hҝu\N"iX;r%>? 6rJnBw3I\@ȇ "(L`Xn;U)!RV}|J/19[4LՁasCX4Ed&Nb"oe pU䰹"_kEB+\JPH%VUtЫg O ZBqgGJj}T){] Ksgg`>>Ai΀#x4S4Ɠ=)1 p>c':H1Y!zK5F.ު4UAVPN7ݔRƥ:Hi tFd8 }dd0Bƞ"k&r_ƒD!J([FvsJܜysBz"ȥCBsdž{҇F>.cF/ tpۤQ"'N[2_߲x17v5ڤ'LTcrN eYk/{urNw?.\D}epJR]E1>boO_o7LmM ᖗ)56`{kF*wV"0deZ(PHp:Bٜa0Ks-$-5ůFm'oHG_Wˆ7w26j=Z yta80gBᬸYIFXnꗝV Xmԯ=A.z-zQ& (xy$y 1C^_)T3Sv7#&֝E&}rj7m_j;a㞬 _R'_IZ~cF+Nn&Bm7K"nN}CI7 ܖ9nӈ ʂ%K[y2EzhCqQ!f',+jH$X(x&D6ʿ|">ϕ^QŨO|t;(@1_df`W7c~Ɓ!҂vqCx PVEɇM] ԘCAԿ ;沰&3fn&/u:i"2=h|>5TL;yv䵱'R"zZΆ̒4궂Lrb]^qɴU-N()hN/ꡐWNSnԹ:p?3\˳ bZ=Es Jjnə9[[BXJ}cpz^ZKZ'NZaҹgjj I8`q5QZKYlN"΂cm@)EF5HhvHTV {bP=5-6q0p0dM]J\9iAS\7h0j4) ֏yy% ,o[If+?CvV)o\2^#U yDi*d'У"ȖDsς*1g2IyF5;=<@V'ˉ#lI ''l}U3cu4Cs('-<*!!:ڏIYx_}xlw`edoy*AtBPjNmzzsk%Oxt/cDa`X|m !:xϪ Tbo/IQʃxWG %mVj9r O3] [w-QRzlUq iG*8 I෿oh/%#Au7kIk8k:Vaʬ‰ArgmюUbЊYJN v(cITqټ˰|T's$4 ]̾iU>NF{15ݍxPV?d݃Y5'*_g҉|x{ga&΋4J'65mYJZI'Y>)h<8z*aL8Nm{]N"q*ӐKV6A)"Ƕh㚄sк>vjN<-@Xei6`H{ޅb(͕==(Q1J-sG)qöyox4 'X5`UK(ԝhvWwJ2<:A>ǩ\shnfnXsQd8&́a\-=/.yд0)dܶҗ '.qsL-g6JO#!$J!зRwn~vW'Q0:;Aƿ DIA̸V(k9"b["2`B0 )S?$R"X\t7Uxc &hxj,3@xם7.Ȯ h ^1ȧgMPSwA('ԣ  q9-'@/!J*Xa_!\x?ۿ9=}:=?~1pd>2TizW87D,qjm֥ NڀRHZ<2Kh*%'ԮڤD‚usuT2t)Zٜ Ȼqfd ̇رq/PNmzxq> Fc+8u4tyT>Ɨ<>ϹsYCFCo玂P54X$ IƲt#Qo6^wswX`hXp7tM,hc$4%K6yX<*R}aGzasAW gK^).őUxٵ9p"!5d#㒜z}^I` MJ_,e&/?hV^ KmV[H5DK!bB/gfNQ>ƞܴMo2 NY4#Ks@P(O:&ݧ}[_ڪ۳;- ;I|C$(m0f0lۖR\ `Kb$b!:ڷBL^E81 _MەlEx?'t\dp_GX}^a^ mkh(BzDwyٰ3PBҶy[n!7 F ? Ag{_1]/W]lMN+H?DhbV)5;RNAtu|1erbxYVġhS!*_G#t2$HxUG(Õ=xt 9m]'ClٱK;90Tf|N(J'Lx@mNUƒq!#z_8<]-BQ dG7W " Hw86ufzC6 F'2Vޫ7yx<:w`V-Y4ִω+8+LR^I$4*Z7|NvT!tp"NZ H+t~bBӳ ; XLL ? $Oa\HTs :WaZW_xEq1[A#)GP aN}aζe+{ByG/ ͬ ᥘAj2}:F@v7̔u4GȩluA-ƱjS~JLv1c^ر|~YDy}si #[k AVzV% *'Eg Z=Dj6m8 5!Q&'g (<;r 3^ndn)0rY~3nFa{}KxB+Kl[J]?4s؍ ڨ)K8a| 2{N݉O<]E`TH+a: SelSg!+ Xp> ڍ1F*[}+7 5>?vUh;t)M{rEs"qB)pyKquF I>^\д[f5>ސJdqi1/)y}A%xS6P;1q) Ҥy5W*A/ 2{# GΒs W{%F]mtP%2elwŭ{TEڦ!b7 EjG܌c!6(=qh_z8Mt\hGϓZ Ȥϋ<׾UkLGy] XCF8q7-ӹ߳q>*'<-bg8O%'ƆAF둒\I;FrJ\P -rkM$5t"~Iqbj.?5ؖ ְLg`Y*,.#(Α7A=ߩ1xzبb ɳಥ>wO5a` |[nlkQ"E_HDI!s B}ČNq{I}0;򟾘Ko֭/vApYGOBFygTd] C B9IntB=Hdg[Ghm1h?s{ PG4$ӫG5}H^YeGz]S\ /Am +3|7Ӑ<ކjuLҢxnv(筠zs`,xP{ȋ%FgJDs I\|lAVL]=4uj YDZDi?zWq.CZ4΀޵z~+J`3ͿJTcڵԩ?zm4O:+f&5x;Cn㓾;`eּJK9𵽺?E7YOZ_/ݢdQ;d!O$VDXם5~[@. Y&*G4؅EVV[BHfRʈn yXG, %i Sư6K:k7226I Qd ,r~!`3ClX "lVnяwp,6<OQ491GBkcxǐ$˅ =;U _Rze&Τ6f& wߛOUs4KFh{,d9Z͙[S˼9CY^F[,fhP]~1AIDMĝ IZ C~*"E\cBP 73ZId jpTU Է5%+=𶙑%1kR.om\y|O/ yE!sPf wR{'lpk8oqRK8~DJ%R#()MڌarB nAWo q;D>qN)1|5nYV&.ʿ3p)k?͚kcϗA#| p9$e,g_YkӫjVt6X m*Nwu Qk]"sE7Z_c&:JV &A`rg =<)?:R 'iU|Y"`CҵL.ʵdn6Rg C@L`6\)^ҿ"\lOF<kJCp Չ=?k,`1W  K]pB%L 1K6=./%Ke\ڄhJXy73FM]ûL=U4UDi hbw28 JJpr/9r۴?d~ۋa"pyfҌ[QiIP97uyt5c$%snvvJQ|&^nkϪJьLl\Z{ў^}+iZ*:ߤVP1J 4E\QWLT6vA0KSZ7,+.Rȃz5M^*Yڠ?X{0D>ܷM"ѭq%.7!{ ?t\IN^BZQ[Y0').i? {Ұh*P䀘Hsk;KǂJ9+_Vjayx7*Y%uDsN}]: ).$t esJWʂт5cyfb8ۦ `_B|޷l9j|n~:ԓӗp ;j4=QL[ll^GH+)hi̥I iZ@ȾNA8:=b)!u>)Gߔ;0m%@l#ul 3~U刔jJQe'lYy= 3+N9m&ڞq\ \reLCn4@ooDÍEÆ.{^B];ASAָ^v :v8fTT>GN~q㲿!iVX9׎נq*$@(N/'M)? WE@-JZEI+Fο#A!ݤ3"n}q%Ĭ2U[JEw[_Cz7uPjl!AC'lHpeX+\A 5^t[Yh3Ygo-Fk)ݿš,ll+-OfW/A&MDZ5N9^1 6AP .;Yg{'Pʝ-~VJkߛ%Ǵt[pQsk 71?o21Mhkni~)zcFXjșՋ*8-ps&/X+)- k@>|~C H M\ ԰*}\VDߔ|n χB=m;0lݚbrEGf%Ν=Qd?Gp`sX=rTj ]V+nAq'&.: V8oiJܬHOotnR2Pv(RaKt}գՂYN2I4~f z5<;_qca]}׃W9u(Du.[%aiő捰}<eL>ƞctUlX㛬o#BXv8r&PJo? {M<%̍ܧ\rUA,kټ>d9Ȣ/ |~g᛿BCd9yOKtZ{ lDj?q^XYkQj6>V gU>EmI?HP HG^C# X@j"ȉLr I5][3@lN:A6;Ha艼$X rR@Űg/Zu?- l2% |$ƃȉDnM0݉3sĀ-ZKNNVTc>c"1 "^]Vז=6#J9veAoeBঘd 4|8^|1aAz6ms-`:őEKR-Pi* gdT[4mE}SXczĆlnMLƈ<@26!TuG/(P6D|O@*9mo]pW/y5//5LNy;+j% \*qq˫IO/;f2Lѿ%:#pp) /9ǷI(6o#$jkM<-5|2{c;GÆsvwk{o~}%0&Ȭzq'@G`G7P Z=x5fTmf:.wv@㗮 >eqR?i1c1W@55.w M۱5]D^%z-6SڄOýX2-dEcsShXQeg@R;{1KiYU "[2upU6u\#.34|lZGc<;џ.[:lA:+`rz60~J֞`zntL#͢7Yg$=X18Հ7dԓAʗWڕ 'jlZpp[N1*׆u}-KW?5\[x<0;&ۇ SsA|m/l"ӡfRuuN[Tωu=|sQ@&rnU}3~r ;]v"cGC:?Dō0ǺI&eetFYUQ(38'Y3c"; M$+Fv+xdR3 ޥWyvĉsޖs:d]1yX+e95'qR*)v{uui ?_\I:REnNxXŸ ̞@^i>Rp3;[G0$w2{z$H:+ .<5МSU1v^k֋<+(m CF [fd\S2kVDzNSJ(i Ьs( D1p̘}23KL g` 8W9ÒQ VnW6̖{ I)S%{06)f͜KOks2Ѿp:yT Cj ˜^-~`9_^J A؏~ynQpau)~_aZ<ͭ1"{h6)B'ٴJeoPPܳ5ʶwkfٻ=G5nم(:ћw Dj(۸ ~\k%I(g=^5wi7d; rz #hlj(>xTB1r0Jx=A2o)q'dIC! L3䲚FfFL31*f|e>.SV bdbc`B OU;ծbɓRQEjtz0hFhvZԅ=pD4Df +{"HقvU~H}HlF zq|2{qk៳&4'p;x^d}LUkv)kPfu֤lodxa֛cxvFќ qKBh#x n̪dFs\I > Dd[FZ'l\#(P  e[ga 'dr~n!Tk|UQ UR-!TӦ ,S b= q4VUntJ*i=*O WfF'#k$2%0g-e[yDf4xi|%96 FK9rvm* g tב;|~yv тA}b(/5AXmwokn:,}=JC:.R33SBal`卨VZ(<:1 ,?X>} djohZa,1EW6ǣJpu6 [EGYAdjpz1$Ӳ%`n&{zn |Rl|R:̚PgL{QHwzn6ngkZ4gԳu:Msl@iI&~}V| Lܻlsi3.%Q Ip+Ɏq)dC?,64@}G:  ›+k I ܸTe k>lhNso! BԪ;Ujbq{yk/ȝf0>KG8~qҪq]fWּ0qQJ-xIv]|x" cuAWX&0r2 H,%6zKlD7%GEI2>uj`M., @0C8JBn U2XZy?CN(kΫD˰헼gaOi%)rͷ+>zT62)= YiQX3+itlr(ӡ.XNw||(WdkgUsgGk1G )r~~x;vRMOCQR|:"j(>nZ?!9 䋊/FwE5$v0dq>&0xK^aǻxS=OЅVs!(k'm,zĨZ{JtOzj i=`1&=j̭ǛR1 -|һ@W{GggX3FXOْ= M{f8̚%u14Qy,wY2P/x69sw釤@<7-z+]7`M[HCS˥[aw4N\X Q2[U=Fb-8Y= 'ѓ@5O!^Hp]Dl15?sUϪZ$x,;B VQ`AyQs-\D _L-eJ gQ+?&zH@|uchJDW;ﶌ*:sF[oS'WcE&Yu ۮV1h3:aMxω^rtJ{e?Ցd~HQe6Ocɿ9ة- 0@t(=bg gky":4?hUL#?hv )SKE),ihbJ Y7=5pܾ7u@T1{\g$"(8E 10ڄL/fswlg}"!6q\q7u͒ sܕ\w!a}? u:6l=ta2Dy+i]#?( 5ɤhYĺ'I0Ηd?qa6>RLTg/)k }_vbT8 > stream xlcnͲ-jO۽ڶmXmvm۶m۶{7柬̬FT"%qRv3ae(*+3s`HIL ,lm L8j&%;# dk`af0je`lamPu02p8:983Idn02kHȊ(dUb&6&VygC+ # %`_ `eQ9Yeoe!1@Z6Nd99:XVc?QXt0 c #' &acj `Cr)&d;[YX(l휝L2&6q`S -!d6fG?|;98ǭf򟽑11pt8gWmmkJzdE%G[ؘXGA`?c' 7=ݿ$B-%(hIH ebe000ؙ\#gO-=LLL`֖m4̖S 6.t*nҶHO!Eؒ1_r 5S9^ѥy3*ua>?M<*cO|f"&d;^FQ9(^EƩ/ 9}E &[ue8\d'&lVul)qOޓC5l5&B_cB; WO߄'R?[@Aa_{ ̴lm2ү+D؝w8?86o;=z}WY`yD+ f闾>12Ŏ\ ^.v \.<ɟ@\ޜrojZX U54 D`me  3'X-KvMLOF yڛEQ2Γ۶_D?&H7QH]SwR,hl8+|dQ"Jd޳ AmdYӬ6צUXaVZI'$f[᱘I1ZsA$`94F#blfXo'L!rPMd`<#AwXӲ\7e)0&i`ژ¸^\Hi3]Dca%F?/ʠc-&$(͑6f-(-$SEH~<݆f++2Hy̠kˤkPڧu^mŶ7sG Y[BҸ K\&"FѺaGtɞll3jΎ(6t ̅Y~Ԣ?Z\B;r)ǟl(hD<6ׂB<j@7r$@Ӭb/́ƄJz(rUŔJ%K\;o"׆"eGb!m<"U)ֲ ρofgar^s8%QkY/ 3%Q»KAͨ⋼Z?OI^[PWk? a$(4ĥpԼd5Kx#E UUy?K>ȀCg0 ^08!#4!7vuߞXt!0eGw}I}W&bciOLs/}9Kޏ|{Mno>٠UηŐgKF%* jl?X&gY>jL> < W]βXioUl5Jfi3]ii_9Ec m 'l}hKˠʫ T[ya^'\Feg2"vwJ#\ ,v) :Sw/RG&׳W-14ч6rN%~NٹNtn/yMݰ8j6&*LȉD%vlT1Щ۸L'ZE!׹ nY`BL>9ˆ7Dˏ]~}iqTN.;uBA04cb .b] `\[C܍ǪDK A5. @\=zlkłǯawt*>N ӫ-"@zm.3\ؘU?x!!uG8)3a -x{@j8WDvZ/bov&u:aꎹ* X AѦJnȂsVc5RtAV6,To qˊڅ&S7KMUkJ3[qJ~MU y! ?ZFA rSE?^q`MTCjuqæV`c2EE4sVU^8#(|p8 o^堇qJbW' Wx/6^=nC1j.@Pa|hOu璨~I ʃsSH]H >BzΞ"tcX@G\1 ,MI~(!j'MTFceyjvlGo$L]ǿʥ8L({YenbrڼS@-Pz1~A`7}b8q^7(L`R0-i :i%`0gG#BjQ5Rn&k;#;IxW1wqٗOzR)MoMPn \{35Mr\yg@$'C ȉؘ1qAA$&[oxB0T A7i"4?zcPgZxbI0oLbP"u^ltCnddžh!ǝ'(NAQ}2L9b1x+wĖ4dqj,#͓|$^pmdvR8_Egs#(zT  $P4aա?h-_?S P~F\V2z wA_ ~d|YW/u7i~ +/FS`ӆj;҄PevzCWhCD#3Nn< mjHc>\"/46&৾ę*6[1`'|-<ȊעG0 zLt<18gL @Eȩv僺"@NIT}:"]S)IzJl]RV e?51 RPljkN^ A ׻`KWz'BFڍlC˹|m>YL,/EQ_?0 ]hΣiepsgtgX eGhDl>I'f=Un' 1R&ֲ덤K|oL΍FF#2ucMbw}{*u߀ "fݾDGzC"i_k :oqj\{1JIDhۊy8g`~]e<9dOMˋb]75e9(# KhڡM9C.,twn|G`q/o!>tF,)HJXS;tAaCcgt^~Յ^[eO-QP €sZ %CI1FPCTt26; #ߡc !+?mvdg{lRʴsbpqPgAnkVݟTpC}YM |,}ekxϳ jA# M * u{&kS&DF}Be%^tf\YT7w5Ya*Vߘui>!O'fZ+I0iH)2)j( )_]I_RMƀL1(BWMz%>bȎ~-间5e{ msAD &hJeKRi↺{S 7F qIU%ݻmƷfj~Ps9rBxME4E@6NLʍ̒Υ1rTK eXK4 W޾D,z=2Р3:%E1tgaQe+Х#g2fPƢ:Q6VS+t,B*@ͫ&֝uUvcRܢ^ E  5ǀKݣ?Zz/1j KBqOqd8ulmA`i lUzNCW%$haіW_.=XZ*yb#)=,+OOPo!?/ ^5J\8!gxC$!E99D2dj[חWEl^̯аWAodvmpsok[t$ 'Ҧt=:z/\q\M6_u"%- Dܸ1w%i11H#z[)ZaR]k R"ϯ?~::IS"ͯX5 '}>M,jw=WrlcA[K`ԾV@2yska?G2 H0kubO@|C8Aؽ*ýܻ&r{ՍuU4pa}&+9tkZ4_5 i 4 ѾJ>+AJ'H78ZݯE3C\"mCNC5Vж2_Z7]K9lM~jiiptj4P@7pitHr({Cj#sշx7ۘ)Íe0gMU/|9{&Esu|AܺNQm=גtSXD!S{/h6T/0>iQE,u[IL-Dn!U ms!%(&&jwij,} ,b"X-tq|eS=vM{!g:˾I,9>78OIƺ̤<2׽G،g̾[)v-Ku'Rv]kxKhl;XUC9XGV'4iX Y*gZN{LC`1BX&C(E襽eFw@[ '6]q,P,x24cYd>NhXv$1L04GVgcUPS_;͜3x 0 xwe\#Z,A=y7Z9QA_:k)xRF)l -1my$r TAJ{b [).[ ^=tt9H5XaMn'B:9_A a}EnW^桱t+5& 0#e _8LE;.`h]Ӏ|ϰO<"/kSrM\ !D%X>v퀥Z IJTR_D1FF`zTP# |V&#/$$ > n}V]5ʆ; 12]c8$-̏3ޢ_GqcomDžc23- -Pﮙz-͹e<zlB7:{i/۶/,<$#lOlVCAPkCn}-[hrVI̻j.|%?sNll3u'j˵`83 V PIn#PkGMTl<> &%˙d=:N-K6ҌGxAn ;?h̭ j6HX #Yt&S}NmxM {3(`@|RQB- 6K8ON8@%&]8NN;qቚXcLl59!@}Zktt~JʚDEJ9wb*̸iJ$.&tkX %^3Gk':i ƎU,x;;6DW=볟I^d-a v\{H}P;6{6^ap2Ba;lPGU^"mt6}|/ 4T]2?%2si:y)b_ ^yw 0m!Iڽ2,#R9Ocۭh_#g]T ;`Cs؏|a\jщ2/M-mbA#JQL[V5NGE-tVu@c||^-n'DNÌc%H5k#trus/GQ)Z@0ch&m*/.l(3ܵ^RفdV3 ӍؓSOd9.&pUqgV])}+k0ڰ ME@2$j|C邠-W|jk9JJ La} w/lE/Ζ<+ U` 3ƅ - W.Ʈ"h [g̶=CR5~I`Ӏ JMJ?80P[͈I}.= _Շ>Է.4)YKտoF// {K)l/RҞ|MFf77j<:Rga. VTku/Zd`YRx}Oגg͕m.J5Gia5 LLC,zgJ17%>4,ڏ_PrSZq a[ݦXR:_2CԸ?JpQbMY\A=ӯj[a?]aWżuSCUXP8|y /Oh'yah1tN=MFlo_{IS'sRMiQ:KarZGN5u~")zXqjnPYPHo)"e y;G = aGܩItѩ<ȱUuZC3yZ*7"{??e ,j@XҝE%lA*-՟\1xSα-'{G&ѕF^lqVN{p ,#%FLESwU -OҫrҨv~*Mis @=ʽ,"o+e62=y" @HR^wЧιw28]QD^Iv`m_ ˩'vOt=9tw6W-'WxZTRs) IAeD olJ#Ɖ:2/.vWuaHpz UЅ+>Kύ^cޕ)Y( N+&qVR$p̄R#K\7?$'(Q4Ġ%-XVvmS)Mzܔ+CʮVR2[vTȉJϻCu:{75.m+47AHֱj!bjyzz4cK],_lFh"@<226I1-|PVkʵ4|IU{KM|;&lCQH}d`$i3= `v/= U}}Ji&+0pAxQN.kN(sAFqִaٟ;wP=38gr:`wSƐIGv'k 5 ̍<FeM!S}N@ކ 7LdG2ʀyT 7l4s( qnS`..tQҗ!NsMۖ5|{/hEOF\nl3)uY:Gmyh3iM2?|5¯y5T&K`shLS0\%LhVݗ0xVP.[">"%Asj9jK 2;pTT1 **{9ܝ\Uo.AKd7!efSe}zUsRn"DM3 5&6U^5k| q٭Yخ:F5f˧+s ;AZ%IK,ŏCF=s6-J|~`в79~?vdc."2-wQS NGGqshs s =O$< ;*Bg!"&T9 S%}BԟlQ8^ҿ־YݤefK[E-GA$4X?Frq 9g,rXcz`+iW0Kco/H ӣ <],.AF*}}K]@I~ >Z6}i5P*hWbtsBC-:,h4Vh:AN:A󰉈-$u|fvkEiBa\Y"? Z8(hz##7B5u3Hu%MfK%t 0m%8ŒfܗP B_m.Q%^0`u,@̕{)p5zk/iƭ`oN*KC[jдgBɈFɪ.INdGNmE"?K\~CM|x2 s1.ciz5dK! :;t[]'T f4yC.3)E/TȔttK/GEO밁p4q貅叝bov_RGɯ.tBK2 mg&Md82߮ * xR䙐:$^Л{Ź\쀳Ș.ϊ}!mbU:{uSf= _wzlE& R>!BĜ!zӭ.ybbt tt|&rnh8eǷeU K]8p' {y=sCfA;xLHܿ5RE<(Xp"VrX ԧ*c[\K9 oBv.Q*lg[ߊ K>OTص\ cDԹ&Ewvvp{POdzYT)µ`5gt?m<#sbj/j˙F/˃05):;$<<8Pq+Ԯ 0 [e ;2xtx)~ 5#;^N _yRTxf*Ì>@v4Xc3*]#D'b:M |6ilw'5巪)/ ?#Vu4*Ń} I `](P*s>"|?&ۍ 5 ;p _H d x+.4QY{P""Oz΄!(_O즀m6/m-8Kژ3W94BZ\ !dqڞ!Ƞ:ٺoN/{}3F<YsŽL]x5.LJhoh3Rg{$itd2{#4J{+bHev_U ,0 eM{=f_| QylֵC巩00_U8BwPTĉUzp9+JKF?8Yh">SGSt[>[ҺVcg^SmF!Ǩg Or>lF:8h1C0[4c`"lQǧ<j·.$?>0dg5ѷ)]Ј΄ޛj{PcOW͋Ⱥ }KlEFpߧSDU#"$:?Nػ R4?Lou*Vy\6c dG%QNڲ644XHK>׆y bI?8q%952|P%d ~Z0gX~y ́S{d~^?qŁyń<(PP5ĺ_A>DGoΛRq A:9ۻaRiQLU<j:-Qm۶mi۶m۶m۶m۶g;_Qɮ9)t~P(*RҼ"S%';A !#$_2\13A} "Cb2@몡_q­zbO-aKa|h_`:Ǫ]gO UET>@de1;}e1kzj0ŤƷcnMh$ފ5 X#I&p?h R}Fm[}eR8{/rz U8C wto$LtJY~$JxmEybt.%SW.gf{,7:7!` S;?| ͳo|vH&(/Anq3yqDZeÚpۗrV<\E/y_`.5waxfgN x v)}G v*^[Z!9WZqO?A}kJ`$]To+tՅ٢oFu#IOw[ZsP@1U† sIM\qL*ՖT~$kOcNx3Y%l[iUus}Tk3>`-4z˥m&KHiϻuWB(ۯP8zS0ZSbvᒛbnɍ9ǃGiM?`tHNQW w4QG^{&jŬ VsIaÅwcD[9,דrřc*:ij??hT8N.V1c#=͉CwWJHG}z):NSI|D\kp.9#%@FЋ&M eX ^0@H^P;Ojjfw,(GzkZT g^O pJQ>>µ-N-,}{P;8̊u7y$>7/슀pr]2ͫ#2S-y 7{8*K(8pȦGH  fYklLOs9 h`;1$q$!dDba4'@"ŋS͌]Ti 7moΏ0줡1(Hq }RW, `5lGu! vޝusrz8{΋}} X4\-YGf4I1qtBNx뮉Hl߶hZYaZIyp.Qܙ DFiWRը9U ->܂P=Y"sZ"94ZIT•ʳZшK&7(S͕UZQ[E_s@ (+QQѿX,gB+8ѡ3.%$Dt}gt=LoRhGĞ)kI'o趜ȗ Bl8vt^X6 7 X9u4iokp1oiO{MSF۟a YuEv% TʉOy *3 E[/Qo~W)҅?镟a{YttZiZlUR$.T/+fGřQH^b<1ʇHHa&6ϭ]"_q0Z[غZ߭';-AP*i1ĥV55q\d!hn}#h,H1&liD)앋7'[3rǩҞ Y,@ram)^D|iJVfEa K5^.Yw{߯|9W\$ۓ%)-}4?^{0׳iVjT^b DJ֘=^<rDW}XBr~ 1L ~]P)6hϜg>o? f xeS)OꁤSu& V-̩ Pဗ*\&9pO?=Y![.x_.CB=Dӷȭ5VRs~Yel:`{, (k֕\+/Ƅ)\)~u5/1RMKz;ۑ԰tiAKMmBPʟpoN)oT֝|8O7t4j$,^2ۻc$]hp C_Q/ߌ++SD{k>Ǝ'a6M[>/ KcgGu4$x.͎1& WNe?sذ~ c 0Cτ?#A]iW N|3O=OuKߓ H[کCqǤv4 ŕ&TSŁ a#'H <<ח ϊJ uէȃ"44i*Pmrr7&H58" Q&he+KO #7f)!M +r~,ȡ.s@4^(?,Dl P%RQfRCًS;pq{$.i8qiN%Gv&fY6_ffayQy(\@~mGe\|B sT}SPu~^p݊v葪kpPRx}5^+%}"\J OqkƢ2~%ZsGwsW=^9hwC&QKػNQ@n~ *HFps+b,k92$X ;gȶz --%>.NV2Ob9L]! (Mi*zXKzk"QU䫵U:SU j\P!NĮ0qy:UƨQENpo ]xتIXr~ !b;`}@K@zH:an%-T]'7)D0{X)ۛ/]iMNkb 8 9 jtiy9J'BҔEmÑW>DV r(e h+t?]ۅԉ~X$,`p,LOڔm&*lF.қhW?cvUbx| `Db?8>o$Ãj shAs|~moHW.ZgY^=Ls97sڀ'IR"}?};nPz{ pI:yh?VɌ\ S*i(i(b$ 7N);xck׮ M0Xbe$fh`E1z8j0m:@8Vw{=`i7$"rAo؅${N/jP*{bPf8BWA7`֤ݛ`!?iw>{I^4<@o?m2^Obr<0<<,tV6{*j l:H=d1>p0o;e,\`>ҜC䴹\{/4X&D5-,QVhFaE1D64xU@M#Xx?3KEmV CXGMaOkx+Ot5ZR{H,HMx$8w\mO8{bF\RSĒ``ts3#n ry &FS(JO^ݖI@m 2^HfϨ5>SnK5Amc` -K>?A48qVz*KpnrGW-]\X_S$5ǽ*OH1$$$'?+wvQN)-OYJ].65HD_Je,_XLA2k#_wSԛ>`7&x0ҕ VU%H=}཈CS/EzJ5(Z1t_! !ƮW +/>(/Yֲ8+jvnBEiw0yn%Bzx&I<ES>ƖI3-9683fƙGot9IfQ&q~M JXsjA 6%tl7b(N*ڼF뿗hbfc:˱ V5 "DވZa2zu Ue aϋE$&0ŅhpUT~C-Qo5u QSB:ĀIJE;}6Ea_~gom1ft҄%+,[ol|pe?7Wj@Ip a4i ߜMiIl4\ AS$O ?Z67U7FǠ5Ͱ:rt{+^Ȩ"P2D7bBNR5RF&M?yJ({\~%'ʣƏjZihx,HiZHk^z8xIV.8$8겄Ho4m~0+Y&(()/(/PMrULZDhO#O̹PS)R10ˁ1aK!G.gwƷj$:DT-׀N#PNh*=ʥ&*^^+'"̳C}(V@vcw6BaeStUgw6%\LID(5p GF+x#`;4?:dAbrx+;w"Pu#XBo?o#D A[''jwX̡,hMroK3vȥ@5;59R4cn4 N֑pmA)'ܫ<@(J~uYE˲Vb&?66ߏn pr]ׂolH=}Gn4*m_Y%t16Nw𫽀pѧKEyfjuX^x4y\r璢ShnBxrF5C^W]ځy.-}?a [v?I3Aؗ˞,Nvڑ-颲㏝ WU$8RŐ͟jY49IJ:z'צ X^&8' ܷbNS39/~^nO&,t ʈ]w%6p[#*cz؆օlE[_1|V%bHԈ'y2z1K(Ru 7'}ܡ%%4$H]!t1{$א:_5oLD>6pH~)F~ P+[%|X49 W<+ެsZq!#V8~vj7X[~Ĺcn?XsՔ;rG$"Os$/LO4K-uQ|a1^3j1ƚ9z'QQn#OY#ڻ(G}xK/XLH&e3~󴞈Xͨա|=p >ˈzZF0 Jq}^tL>:ʍzK:udIGij[j!~ 7*\LM`K%0ͭiB饰 Lhx7讕&Ҡcϊ&+SECDŽOS[|%(|uյ :bTʂs[ƀӓw-*xj%ҥ6&YprǻpɲB0 ^. AXFm. sL)&`iR_Bw¤̔,7Tߩ: ߯HHx:-lԌAthrQ)`ZGOSu1u#^Ss,iX'c͇AƬDSJ8%r(TEroIu 5l^p@woB8Z{T N;@YReꟊطhb iCp%P`_E 3Ԣ)nхgsA|G]QG>=9jʎ;>1]idxNL#H3pgi2ҏGת9ËۧVn `̕)㬬G f.Sja^.7z{!l={tfi\a4]f JD㨀HQN1/̸3KفʀYcyD. 00j b%WhH1ޣ*zuQgn#ߚÏ +zZ cWoQoi2Ϫ9yy;WmZ :[s:w?0l:XKOI KVSgRnk(Zl|Y}9V)Gz\?ߒXE()6٬||BCB6AL+|J\Ґ? 89Y8ZkC0WC$t ߎ%(v]x 'Y=ݪ򖧎j]ng\ \h| S~ͱU-sҦdX `<Ɋ>W䡑v, e}ք埯lLVp StJ(E1ot (v8aY%h"V0(5qW<^ FAC"V6 H(X4zXzB@H^*9Vs" P8^]6UfMT<[ g ʵ)5: OqqUYq!]Zn%37# 4{g%IAĦ a`Z/F Uc F0JjO]bgoQ1F[ EuB4WKo[$'cFB$ N&:(sˡ9e@0g{  X<,YCJH<Ͳqh7xhd'a`\}en8[jЋnD`rfbTe-lKPqu80˟[:@UI;j['y]f?>d.y4$-dD~?_7͌{qať(j. 6e셱 KXD OGH2)-|}VpۑV^R>j܀583ޢW^epa*'d >E{:%PH űGt$^v?8rVkPi/dlؿ*i 9O&[z$Sw Ļ+1N!(sOcTCvs{N'oj[ᑬuV$SݙNLV^=4y Ne+]$ְ\~`K0+ aXbe<>goES ?6i cɼ~DNwN-C[˗ @&u+x؉ ߺJuKULq9M9Al _0vYMkހ ˍϤLKR_DZD=o]'U?TuX2ŽM̾x[ڿknCv1]&+%#?OUCT=~1wJR֑ Vη_js #n@fx3|wx?#OmJt6Zn&nQS-̮D-QVN(ǩR,J"CR^VG^s7޿LL?LcǙ?\q^: 4]>3 ^Qu5;w71N:54ߟCX3!fP\Ń( pl7g y R%g`T" OpWT8qO;%䨖p\E9xDZ-S/ƉKvS˞[P2 C'Dp\XTq8  lۛE&1oBd(KMŢ+#$Tj1*N^chSn;&)򏀖 tzZҞi/#M:e1 <_~IbpHd5r[.58lzV#& L+ ;F/h ,? 0Tb1+h/^d ׉6:; sJM{Eg?p%!JIczaaoS8$CÈsRV#y^gS#ᦥ6Sh餸^p VI8C z=h:ɱB4-Ճ1˳Ҕ3?]]4}ot"W݄=8r9f rYm|F)3m&ruyXײeW/uaؖ@N,"&5'#NS2RSJ7,oS6mkB|f^e˛qn~[/sE4>4yݻ Π[AXB=*bU靥MzIE{$9cD+־qvR⤑%T# W/=^$2٨"og?y9VWr;mࠚBqB,fjM (V]r+(`̏ikSBVXjX|rMSڀiƝ,g_dCK#gm24%7wp8ƕ#F8BSg7YX\z`֪%s){1@$M VVgiJNO/ T@x ]!B܈"Aϙ|HjKtEP˹iWj! Q G~6i#If`ۭFTÛY~[ tCwl\Z̳x-py+gY)Y؈8V(CV8Qi"VT| ^Fh3:Yzۡ*Y_JfPG s{V/8I6k*ݹe秕[Q܃#9 /9*Xg v=T=$I`Y_,K.;F4D@76Dq_nc_3&?]MY`BTq%Zr=+_!$/$ڱ7i9YE͂r$85'ia8ZCpxZ G֩8'{9̠_O>[br6k/ 09 :1CgvY6<.t'=y2Jm"?~B;ػj~Hd:"mNaSPrH]ca UVl0Z.J}'UdѸC>tO+0Qz}\U\+C Faj3%)mmE&G {ʜ\bK Y66Y耡og Ĺ["[!øAj.,7-ypKa ZMe?KNs~4)qH ERTOP;IH\l5r_kd!%}vPs1AЪXskAq0%'7]a !nCvfBKtԝ[GAyҨeNFw_Kgc`7H^S]FSnIWpI!hiV:{f(,nܬb̝scx+d M0  A HE.E\1EIY/i*+;ܷd>Ŭӏ{pr> =0Yɂ€ՁvI>Q~kRkI*nWS'Qk[2WV,iCiNx];0ZξɱOrJlo%- s`̓DT)ts%ڍ)6N:Eۙls0Yy9C̩nWe+I!+O$9w-iEl̽Vc0êgv]Qcqt `DL'TS)Mkj[v-V>W.Rӧ_b6brtᨕmVm)BhcU@웖{q%/B#">ҊICO {72:rquv׺,ꊣ0"Z\oH2 3 ?jlMzjoo xtS픫?YxX(j >l2waLqk_{Wd"_d~ŸY','oA?ʳ ǎ .FMCsLഁU.AcvФ%2Km.ٌó7Đ_69J,9 P}v8;1 Aς^lN4krK#l]cZfGG,|\ΗCukڇ>nZcɲ[+ bߗ4ʳОRY)s])Pe e@".dTXb9;\5Xa*l_ǧOR=`!7'ove8|Ղ,=?x˧~s No9>Z~)+>L/%h9DnX7-Eاi&*;F M J7Ajnd^]uO9e1S7WXg6`AҌ %N\ڥGب~8V ߸ ^S>'/`[mzfq7 l$oGEՆvͶx 9u@&zDP*~d(KMCZSsUM&]] :l+ԭC, ԓ%Cm88yy}i TMb`@n  Z*;[s)@G^Bc> ;p% K-,/!oeWf-Wa&;>R⣋|=ܾcgpb$lt$)G):p 7]"EzD€j]]jZV^%@\4i,kxOH ^6C`B iϙVJ}ڞxTS}cUi ߎfh7J*'5u uw.KYvɸe}43| hT:rGqU>=IG<"u8r -|O]D TJ?=3i+:~¬żlWπT`<XPWo aiZc&k8Ui**.jJ>xPsD|ֱKv-Fuw:+}=%dhn認QwQzdWa҇keOLo.oiarP*gׄK,wlu/'ƙPzGV3![P2*`RU>:Ǫ( m˷`NIVwu絼ƪ8DQQ(0:痤2uM1S?br'NJQhMK TuiwA'A7s92*M& C|"u8kh̀x `ioc肿r8BYk vHތThvG'B遮1g'% 'i+5V9+ aO"&j@D؀Ky*-?{>A =>\"7*%;{(|pVr^u{O)[3Q2(wJd~+l$֮` ֞ʇ$R mvBK`^ULr`ǫ+a?pފ!#@ $ 1)Z!_XQ*Aim N|d1uvq'ӑok ]|'M~üq(nܠub\@&`ąl\5A=lÕ^?u~\XqAI`בnb/%6J}jO?Ei_e}{b1T4B`TsS2)~vXR171: qԁ(hŗfTkl@bg)txr/Rd EDll_4ӇtC)m?Lpb_$=.4y֫) h  10mZ}(ȯ`Z%ϲ !G\Qh$?8ԧ`[3oPwQ*9TCTec(oX5sf%*"\ {3%.r% <͎^{NcYsVӢC[ da{GKwp_kYH,Jˣ-_暒VȐx/t;23kH:tV3S~&g#)̡"6cMҁc-J tAϝ{K̓3aX{F7T ͓Zu$uK 5Jo_qD#8zS(V#d' {١GbmT ,`\7Y./9!S^tDu: >&;Ob?6)$r>kH2%6g_|r2YjT׬"' y7t3+]ka7_!p0V,Nrh|!F$vZc@u$unI !ʟ3-v`!o CP٪VP !&Qzp^UrA8bЬ*ӹh-2+: 'xIEZQ*jyTI#=|b)7\a :$P O\D6+}](>l'Rj/;f0y=H4$\iHu) ㍔52rѸa7¹,C'Q H3F99P!5ͷ_eU=Zp }TnacnM+'S΄??&JujњC3G:e?9"Q-7 oep/S*NB̙(LwSJt7dQu>dDľ^]Ƭ;|W$Pu S'׫ΩL1t)?6{j&2Uv-F6}Lbwe)Ͻ6@P{3UӹE/`$S.vl<nIN6ݿCd qEoҜ =h ()^b_.9qn8 I)Uٔ~nxFTqk.J\+c$A$SDCu5. 砨hOX<±~=B۾cx>dX{JOհIƣ;!ʼ4_T(o)O3 o^*r&1;K`_cEج(NP=dڷ^G2B * + (9 ]PHآ,eZڙ0v3VTM]` qӺT2=V:sjCEq˚=Ky .fb ("lUv<\IWeLk7;S>mkǡuj$4y}88g硍-\4>ȀCSR1h̜E QtdFP3F3h2,N 9­! o `it: B:X6&}I6+-wU8ŞƂ>鬒nE[h\*܃pˌc"q߅!B5R DfhG)U1~p\Q[gN}h9t v} O3StUձ0U|[ý6ODJy=bW59Vih~3Ou#ɗPjQtZ+j dL;Ճx(j`&yqTL6suۏ//k)}M_-r+(,hgo-6.s3}1gMJF)yk=y 7 Ì vǿ1 'eNAS(bh^@>lX~N)Bޯ;tR&X* 6]gVU Iѻ)}+ű&oIor7O<6xigy輊cZ*GRau"Di \E^m2x`9*Kg͹\(AXi,ZSPΔu'3 WJ;twU&c 4TN`롔fn%*N 0.[;% 4[i8[}QnG'"=@&kxzkEt:tPDA[L/p`)u# II]{GuH k޾h(L=}MA",OLO$D%o) }{_n=N^c3iheAr;r+Nڧ_zfx]CAztd{XrU;Km%0E [ Ti2Jg ՝# Qb 펉)$yfj[rpYqRRݱaQ9ȇkԊ?E<]@7EѱS/-Ӿbtݓ94ǎhKɟC(h~jg%o.[ f gi4`)0Q)`"Dg|mSAd`rǸ?;19fj\q ,]&]F|St Q5kUݓ'>'V\g_ d+@;q`Y#MF"T1 .2wYGN|)qHfEzu|H=t#4~ u_4 7 L WRF' h#.\vYhbۭŕ\hz$aƞoiF<>)@wIt㣑{}xUb ?2q-p_c.&#wr3lX4r[ bZtYBdД ,_@Mau([   sdQl4L=] O^5ثCCpr{O׽]{Lp+An@2E&HOFUdC^Ϩ3AAݏ|JEýD'KS}noEl .4aCD#/77`)kf"M1^:wxn`Q{@&F͵LX$3MIPm]Ly)xJlQ3q$ҭ3Q=;C.A#1@}"Y4/p>W#-dž1dNltĐ)N>oO?.Aq@=cOD%" @]FSWVEOh#/>1F:zEzC{Y7֒[Ssӑ)$kx<6k'EvXgB>r15ɬ(x3XUg] HlTϻoT}MEqSgR4- a䁃\RAqnvnۯv,"xY| o[$&yQc:$iG=de?*}Dk8YFS6@hSB(zLq{h%LCS\:D{^3FS$ߐQiײ˷xۄ|2JvPv)fװPZˠ}vE4ŽՆm~$'.uzHD7q3NEZֆ9Z.0~bu Au6Nʞ(ro|fSϴNkӉh^L՗S0!2bܲ"ˈס ǣzⲰ1vuq3h\j_֤ux:ŝ3Džm6 !Ih|ώEorpyZ05\m>>=rlU̵9z%DRm˔𓺫72NB8'ϹyZh`$MGYsO/ވ=ہ?eU0BrIû]!Lw\X[=~Pr@Wִ/GKTP2PqWfkըܨJ/ю}qDܞ#E2z1đJӎv2Fh㥽nIݹ! 2(\E]͋ c)QӦa^\_P1%a%8 ੣;1@yYx\#L۝THL뇯)yxrH ۢjh1PKFT|Lc\>Q5ޢ<"T($YZ(@aڢ#J9& 8#J/6W#l b9Ǥs0&-2POnsu }W+ $I:MD>)td1 2@6skA)%ڭZP~Fn~3Vڳ_V 8+r4) bw^qDKn)P%mXĒ>CŊ dxKcDuuoŨ{ENT^~( endstream endobj 500 0 obj << /Length1 725 /Length2 30251 /Length3 0 /Length 30767 /Filter /FlateDecode >> stream xlcfͲ-\zʶ.]mvuٶmm[{s1sF.2"1;[g{&:&zFn 3##엣 7@lb`ba!p03wPQ mm`lacmgmjaduuuturwtg `jam%!)'Sؚ8X\ -2F&N&TS;G#;[cqr7[WG:dEUTT~ l2LuvmbhkYeFc01-&f0 M!??RMLAX[ؘ(ػ88dMm@ l,=!lBf?z;;ǭfȚ[g?SUc;[k?{=YEEu%mEm-lih ,A: ƲΎ-F㿞tJX݋@`baep2s]#GG[O.3w33 Lm --6kk[ ZM.iֶiK%k̽50$g&{KfT"('AspyuTΙM*?-/qwMqmAY5$4YMƭ/9'9 Lp(ت_$h2\Ĭ,DSe (07z41⧹{L+N51>\wzWn2J?G@Qq@gܴ|m*ҿ ;Dăo $67#fc>,"u2I[K_^bG~ k/xI.@tk2&HO/AMSW+-""+'r񶺖%dx q&PqV[ҠuپWri(fx['c1_{+Y,ҟ_vA;&YLDd%ʼ=*"wH-3ѽ} \ijY{G{*( 2(b#>,~ ~Dn0L4vG6a`kM@ou |wmiZJ}K_\z*k8#}Z@7IS h?L  e5 !e> %7q9ehnwp-/ZE`;h-Lm>m<*` ^[\ܹ^@yP 3d [ Lb(ϻ( ~Go_?F8,x rU0$h(!_0!/k#Vviv%Mb<k SuP˰ȵ?؄W[Dܦq*Aҭ#WzRMwτ)~d0/T/P Br?v${\ ^Xfdm^U!BȪIMe5n0Kj$U"Z2Q`oi0_իm s8j>0=:Aǐབ.3e8Q߮9MbF>rQ]/6\m aJHy\Ai5#{JQ#QuY2'7ytaE!FyEF+5}W & MPXNV0aݠe5KX>O[Mƒ|vz<,o?h8}c"S\h+)C?hTIʰ^)Z9;Lnx,UWW`V&cZetLsP&܂*&eϜ42p] 4sK?0dn8u He.BC$O9r4HJQ3Lě@^>B6AKຼu;"dx0fuJZ9jzMlSckAܯjW{l9U[/ýVoxt:G@!L#R[&E~r8KtNa +1t ՇJ)fϤgܧj8e $V0bGRr/3V#@q)s|GAN1aw>VO>$pCغR7ठBej1OOiAnpm-by1HD㽺QojoT+obJ?\DsP%a}q4b9m,\8pkO= ȰǬ[-Tpf=rd 6asJ\[Ap$d5v6~LtB>G.%F<,(kz mՑ_F2 3*qLfM#~rC}^'(5ΟܨW1?cxl7],5 5Qޟ>"KL˦hadal4NC-/f&=E>&~'U8|7a^ 3Nq PbvA(VI|ܾA)W*cy={Њ.Hafx*/PEf 媫Z5H@UaYz#|qyCx<7[k꬟nI%fouQD fkqt<0nLNaXrf.98e'KȐJҰ-xةNm/NRHzgJ6):z,fΔD98p{2;!Y.#95Pۃw$r{%*0,xTE.\0VfI~[fbJdCG!6(p2 ve"c@lz~O X11QaU/Tl̺{ٓEw%QJYd]'hز%YX BΖW:ePr@7!;R0cg&; ~{ބ)ՀQsWw\B~b+tDr_;߷4; !!!87~ HX$ѯ귄0LE] 6A/Yy8XV#ɨ7`|$x;5qpz٦5]\ 7]W̎2[Cox`z~h.zG|HXƲNYY0*FPoZW10,L-1v$鉂b/>h6=5yTx8< % 7s .O | ~E>G/W}KRnk7qsl9ڶFBr5r/}N"sNMG-j۾aBԇ[ۆa3<$ᚚQɑ6|͈T/;13EBu#{qr9pB(vbFEƽn} Wᇉ:KkOZаF@KhvX*CDd:V`z]v!ª\GY;On{ 2G>hs[״qe~sv}Z !9äQ6>XRU){RΕםiѨ@֋sֶ)o$n+ ʟ {*$0Ԃ>]Ҁ:ٷޕfƸQH:s!熐}0_\f7kttՌ9w\K1~_zR08EۺAXH 灙4)C ET:m*}у-Udac95`T:xR޶R2)Ɏƻp왨%NF6Cvۢ6ڋ9O6Ya;,vVKr}J AAPb灂U3LbG@;@@^8u߆h{]ž G/ eV! rx!a!5>>a`Nݩ=()ˮ_…G4]:oěghKnBe6 Z8#+z( gPNta`qSNfiwG⒥L@z7t}3Hγ~"Sn)gRhb,ūמh;23u_\N^ +23-Ks:<#Q*ַ4bYgCc'p&CZ/YVgs4c=C*ig@4{$r 񏋠WK yYǭ{BKёj}9Ѻf3V2R(FoMЂ.B\wdh"~8s0@oee}d=v:'F/#b>vaE=Gp`/,ސZ% \!8|UجB|9(2*,G{C|~d&x7t”ژx⩊Z+fPJm~T~ 2'ԭ7^DfǷn.3zSMa_Ob ε;%:c`q|[ tq-[X񙗲;,KyE[::+9uc\ }i8%wR+'ϡFz*L`%t M)O ޔ 0+i@e!zZzY1[S-liX|F|$k㑒hq ~v%qh8{cB֖YL;840$ޫx%0ry_ VY+A.Wu:X a|Q5zA+^ʤF2q5"OP&rf"^N?t5R#bmy2OZ7IL2_٦J~gӪy!=r%Y?[飽 vI,J[A;3!$ڠ]˨ w J|X֕9L2KeJ'Rآ,\b 'řǖ'"EqW2pm ڢt>59SnL%DHٳX˖+Y; :siDzo#v@ K0Uh| lΜ1UrTGЃ蒓&rۉ;_ֻ8%zY7A|B0R'݉_Sh_֕iz Vva)HxC1Al=`1S#LQ)_LFp,eD,ă IDEmؾ*\"ڝqӦj@6Ǒcpa~fE: D̹V:a?ca]Hy\sԎּDOl9H=a*.b[$x \| T2yhSEcM i ߺ#;#ߍ*%cdy1ӹ-( i @e"9n&<=rjJi Y;T4<|YO=-9c\&N~\ h%ʩ*L朙"5i+*p@Kȟ"R&< 5ø_QG++@Mm1jqCx߲Ja^>[fĦ9Av 8(]EF\:EHNRCnЫI޸Q2yɈRF+"Zka3*]%|W]dV'!+"U~#˯)RA8~e^eIbT'ZP40 l]OepnC.e8mic]"NpbZi5|y9J%9;쳵h~hTWt m{D:,!|?κx Wezê;]X(^yKúc}|d/ĸUÏSl"'/H6Eƌ;,S([Y62ٔPQ&_4("f0AV7s}@6+/Z&yH@f`ZY[Qc C$ź5?ۣ/oR4vwӐ 4Ix%;IX6J|?o):s-bxH%'ByG2q˯^ wfFf+Q[`yYh ˺({kڒԢX7c5y0.גAɿ=#0 DPysW&#[KMKu' YL1<>趾e_[#w`65. zDstj~q]-A\?Ír@0D-4O7竬U;E(ckفiMqCA̛W}؍;^m$V="DbmkZIn$'QvmX }Ňxs] 6[ARR5ӧI~{1vgJ8F]^Z1zjlwFj/TY, Y1`f{!3y:KȿŒz+5,crkSUE5p?9[(ei1b .:D祿bK]Ep_a8Vr -,T>gs)/ij&{J 0)oQBSՓi;̱\D.^؊!bQaEY-`ecAFMr1y3cC>47fvJ7[)|V%J,2# 78 hU·މAҢGd5 }) /! #"]G9J u{b62ɹeTFL4fe X+=in5~l^|೘# ":`dnU\xAXS^zLؿys=΀SgLgT%[[ t=1nVv!3b je5 _x4-"k0WKkIS Ӌ+LtuvV|cW)g>FeuUKɐsW,9,לwmv!氫8(}$h>ma?n!n%[JuڡwgzS{`CQy 9-Tڠ$4 n||%$>Zqۂq2JZ`ĉ[t_ȣbSCJ4|։;I˯W0E^ O5E*9ʑJqsJqFo4-wԷ>0alTEWe'8$`C[CfgDp/}ai'D ;b4۬F@n;St L}A=Ph&9hβnWրug2e[WJE+o&.ԑ{ZO}BJU7Iҷ#T[`5le*@E /lx9WP=oXV10|lש>)?bi8|DmP^hCciZI4iU~n6*st!9rpF4O!9q*==豌MWKb.ZuMM=҆,.1Q~MZa^$@iJh3(xo:W Y|Wh9׼1d.ĄyO``edkE.JҒ`E0wdf>ɘםV3G ^9g3m7tFgG0x0DtG7- $ZXE+(iΨoGk}LM9%à Z{wZ~o"W|Xˆ*Zmm~c =q}^@CJ%C޴gYᬥVpC (*u/i׎"G _ ؂^GY@n6h\_C1$b=+zJ'9c$"JǾ1R.-?*{8Bj}F pƝUplpNTj栬[(cP Up(3$iȽMe"*|6xre{YQ$LrH+X_e獱plo:IpQo2a۳ =a3̋{ȳhޤK| ˤ<Gyp`cxy|_C5@q9T~2nt%7#BRl {Ї-, }yȎwtCRC3Q+1Bq5۱3}*u'fK(<[S,A +_Ɔq2]h^ U+WK%dQRu$p.C]9GdzķM3~Caݮ }f4u{.bĴ 'IϫaTvn{+[ey v0q[{qS"Tx"Mn%bmYQ300+#sߟ:-\IQfW@.u:󊓼dJ> aA:hʦŬmA'?镆5][ro le5YO{`Hdn$RuZKp#O=%$yJFٙc dHRBN^/0P_h CK-6mR:?}qv]'yf^)ؓ{{ӳB1<VmF+)Θk=NOYs^Q}lvujce\/GN]JK4T-}Mg'RJ{:Cɗ.ڙs "$"POpI`noarG\#Ș)I{Pzva,9" bgKdPAgsrv -crM0󨨪6iVlY^9ulW^g lKxs U+╠t0Qke11E:΍CSj9$ĬM!"MwD5n!֛h\BVN%fGwߏ7Ā.MޠK/=WB5\[ ;2k7q b.v=c~>,0m0>+ x?y!|4- [s_$[HptENTM γ?%n?X9`ݯa݋%K [|{kA):@xxWl /+px0PAt"<SwnEQ=$flX~qZY|bhm{ BBD-"L{L(q]D.(U#P& S3?;5{>(xnC~u9Zo'e IEؤB4o?rcf<.pc>}JhNXFRxm|oVxpxn*hnOU9E\-fvZD$R(z|TU$dM r3 WCZ:t\I޸7/w;4Yα6 HV'D=} KǘŎV$ $):H:UB |CZ:$G6Պ]V/*tEPDVT\fZ"/5[~"&xafawb̾aU>ȩ`/_g .PpZ$s(UUiJMvb7ȔehU `b\Y! ;nd]:="|sju+kOkbHgd4Z[ȁ]mj[UxXA{~ ^ v}sk]F抓(D F `]t;T)g VQ y=NO(} t`/.;"'WRNtIs}awŕ>\3#A97 ڭ Q&!BEz^XΓO4@64oE bJY %8=''E/jeϘ[uXhjlf}g'3bFatRgB|H8tUM-RV}3#oE6HvE=>3(*jcxOji'uI $GtshHB`1,ϯƝ\EOOCFE>>Mjn="fG O~"Š93*l>B VIs3gռ X"l'a %s:pdhw^TN &^->_U]sQM]/lZ[T~2nzRaqi9`Ld*3w"˂-1g<ំ g3Bjŏ&8,2FhJP-U%h2P~+#qPz)aeD{giϹ^w sI:Wxl5j#lFl:HS٫.|`nRGZgu5n FMh" eʧWEqX?40m!m-$HQKWdصRxl_+{Y~ k3XL4’mN,bjO$m\{tlmo˲? 1<]_c0,Ԇ}AѳVʛNY},Rɳ|<(/豏)n`8s(um<*XY0+H%mމ\-{AX' >#UvzM\ fW5eK4KPx<[+Ϻ4c\;P|S_fTg |nwpgXH[:'Ay ;U?ɏ;ܖ,B.{[BJ>jz=R(p"spDTLٓm~E<ʽ jfzyyyیzBpKfM[:o4 s@#ވd+AP# j%?\ڑI|܈#^V_V1g׉oCkXBuԺ jRM4FWbqf#22n&Jug1~89Ui5L+dqpqo="VG|cҨWdg_1:|_P3F"?,Ko;Ũ𞣥#L~I1] 4mYy3V+uhn}fBqwVxK?Sǀ(OSϠaF8 X]'7.nuXnvGLURүI\>V=H% ͨ6ž؄n߫Q#"UD7d/fWO'*H=ѓ/W橪!/OxH2v\wp-u]YP>~ML@=p6?˖}9#Ms< RM vw-_. cR 7)J$XŁ\wD^OTMq7`"10ͽyU]ZI@mQĉz_0 P!IY33|'ؠ`=I [Yj$R'N}N$2sF  6hlKН2i~m/ J4Jiaw݈%xA@/oKD?x,m_ӯKU"YM[c]/WLӢ"5_;& V(fA5!rwT};JWK||l>3ܖ14Ӎvel6GIéצws,'/B Z\@FwVιR&w(-鱬$ƉZhi1!.0P_\wO2ywhP_\8;f.Gtb4Fbx|>V8:rei;PR|_͎lAժb3\ ;*\A\d`P!*9sD5ö!j^~y*p&ӱIY(SvC JMWN[hטrQ`m.نK9mXl۶m۶mm۶m۶mU yJfFG H|Dւ_Rhg%B80\k*!Cu$[1|7[|ui޽ s*rw0;UD򁔩C"eͫMTBTzMCZzHj1Zy}}\07|⦙ zerZ=~8/BϮe5B~Gp^,*2çV0 ]2PeeM}Iā:otN^JoqgMZr?f .mOkZmHǙ?vTy6'MPY(pþd"05 ,2^,2 1[B6dHHxAçvG9kFK"5!|(CMq:m'; wB[L^BY /zut`bP?;Ȼ:gUʩ^FZwf@Y,ce,Je1@,+mJS5$ "_DذoF_UwoSQl.Eg\C'Ir`AƟL#z~B%A[2J>8y{?| E%([.&N/e6m)[3Y(TC=ϱVL,K)e3~?N2{W`*KҜBW'^]xM[|ggo.9u[t1%˷c[(-QZǵB?ǀby9 وr ೂfⳋG)S1Of5]cXjywQ[Gn:2qHǴ%$= ѳ*EQ-ai`^P1y⩡=7w$V(1Gn |5f){{j<7>9|*%qi|XEr^׳l#<)AS"DÖX4q4LDH9 ZRϧ t9ˀ[~6%fXC+`;%3]o6yU0sΫ1Ro2 }rRdJJo28x͔%&uӒ WG栜sëNɿ hEN-h΃EW!e,Js&>Bz; 8‘ڼyvJ"94GGެdUskr).QwN' ~x11!&]2;%OXX8 dbެܷs J`bY[{S?*T (G0ZOvd;l/@$'{zZvICqb'$vE0fb~Yf>О$t~Y @|jR,y@",}a =tzyΚ+.tΌߏ.F3D.+pU1,Sovۅ\wrZYx벝} )[f@>EQYCMII~팠l\"g “~WJLY 30:9ب+dYRS)b=PoToꮘ>C1/py p!v4 vMn|5QPnh/6w+xpufTb9agapeB$Gv`jR@W'h_0b\Wg_cb8QU1l '8@Ʋ=\C7 f?%ܑ4ϼ1VgޭIUa kjZX~Ž#?"xMfv(FBu\mTBI _[kIdk<ǣ(d.R(Pe,hfoJ{.FӈH~!S /m }]T-AΦ8.-J^2H g Ԕ2g k$t%#N<~y &V5d"^u iSPz)"rԯBSp~>9hlQ@}=;qq)96D־ے&MCmd]6x_;ԤqUn։j#Rn+pvS{,pGtV85$Mc+zT<foFa:Z5 *I!raԗ(`:ߚ^ÇlpoOM ;h!#jʀ ܍1HAoг0%Euдh꧁لwlNtwú4AoD#|Iߨ~@"=stK "DY$EӮs1]G8x|_=cXrS!:Z ͠ d3+B |t~5/>6 ٺϼ$n0!-bɣi\*@hPc`a[sf:!(u{h`l?0uf֙Pyw=,/RoƊ i'ŕt V"]&̶nr&eSF دn^;9o$Js6ۨP*Vdmt 2#PXV?!8K_qs 9c. B>Tdd8,s9.}V:,KW*Q\X=/)1@CgL$Â>`CEU!B5 v]+ZPX"_c%B5"#hkSa]q')+~l< oqqؗ:e%J%3*M#9EZY^6<dzFډ'cIKV u`,Lmљ %_kb\ ^J5o.1_]+'U"Vb+QDiarMͺ\ڦZjN}{'T`1q&tb( B!ACNOH@#h rmKzDS\Jz+D'J#M3Kֺg!H A%ݼd""qF1dۈ_"LV +&w(2m˰0"4rvjR0x"$}-ZѾVH[EyσhCXt6Fʓ.|RJnC8ٙ@ڻKI:ӎu> 2@_, 2G?-Yyw%=- I\iA;nd9e:)Q*Y QQkOeټO,}nێx(#AmAo̵ȞNaJ%sV27 @er-87{})Z(Yj}r|7mMΛygk1 Q뫢6].pND_HP+x= WX> |BϿBE]sh=u<q. )r}յ}Kh PGy`!DjWnIXJVRMv z!hj2 3nl!Iqp,x))f+"w=|CTCPW&V)fg]?d?3tTzH+.FӫOpe뭱8n2T^[p ̀3\㉗{ge/Y 4m7YahBi"v@U]=80eksF'%Cҋ< [*n=!Ŷ;2E{^my'=1Ѡ78qMOȎ;qxiJP'm3+1#l*^Kny`Y2F])%)~˟oƖ09KaSIF9c$7k\*ړgra3Qb4Q8Ø@Ko&5 - a( ,GzxDlK-\zBvJ=Whtݒ&m dr%Ժ1"QF2N&) _(|Ƥ^(t)g0 =B^N ;%zn* miz,yvտOLӡtύ#6щDQ@V+PP򄿙C'#.:RnXΟE#b 00;"='4̙'c޵~-GX28ߋK/jçY=`ӣ|f^2AJYJ}:Va{\GCLw}`./_]gD bm;2'Eh5֍Ķ|54F|Qh\Φnv{!j-{*-$j式R&aOV "hh>,E{248<տ"yo]IJB~[ tFĆ~@ƎDVS&} YvZvܦ柪,~ ٮ.6 ++RHEQ{s65ƿ\VlFԕ&hx%F/0~ fϸ@c\&r23?eͲ* tp c9h^;6R*^#,QkB?+|nfʥ3Kݪ[Bz 6z?9/eQPLg]nh'k9D/ [2%1-頱p܊tˑYVXEZ%z.}}I3j` H6m^q|M7EKh<ú2 DV3MgMYmDiR-m@-p9'iD\5DՂ92T!FA2BS4ϯm/GjofCqErr|,YFR`c}QE0QʄS+JI$Bb #RR YCԦ䌹}UڕDJ=gϕ)d9cI`\qyn4\=aY[mS{q {\ݜFC"1Zj!MF22z2B$$ܪ&*0DEע;oDNV6x~" WlYD '8Q9!ıEu|yc# Cu+M.g s* Z)vIM$p*ޑ::lj%LYmzr.r D\8-ƃAgfJ^y|NPp9}VPOٓrf]&Jut4;T"vG׮E!ʢɿ: pS@ lʽv])sr0Ȼ@d[3`# :+E y ,D_B`ŞoSL`ۇt27#v0a1 ;Jtp7?$k Kw?rZ܇|soMMRQb;48F]}NoX1-zͬ8Yˇr{:@'ImT몴i^=GK)_>W&tq}ᕩ94 z.N:I`w:Iר@8;Cڒqzu~{Ѱ_Dԙ%ud:kbke$$#P~n2eY4Qjp2! 1%u[-$'.D_S}}"G9]lCG'EѶ+I4V^#Kh?mۡdwҡhᣌCS'}-bW+/!n?;4~djhVK_/&{ ~J-y)hN=E󴴜cudR,<;Z jًpa T!ZGm;jB^B*-Wm۱\?ey}`A靛Ëk{/YHF>ƅ eTniӝ'Վpddjލ4N:[g4pßל2;x4v eT6qLwCWctu6]sݏi/tHjG&=5%TveL#Y{AYnذK^+4Vn's eR>md7qE۸  {Bx#_$JR?:_J#O2M\cb*uz03_Ѱ$*BLfuL8R@QUvBQSHZ<(J*HWˉa<r[SV17F%k;oY51!EwzlL뭘h/W6(]WCVr#3mlћKOF4↑pvnD#ġra?ϷƁuctWfo%yZ ׷]n7ݳސߊvW/:An8 b"wLWjd\kZڰW,wsǺ7c1g踋DȬ6=Șlll5f9K{1W'j&kr@hN]z)RѺ8F!%xo%18[Ġ퀩;ulАUƦh]:>=kPMģ i K,}X @Y֞Uo/.F["5-D1xYx\9tY ̛SM>[z_1}+ܨ5m* 9.!S7F.gva[؃r$E׹V}&q?`o[NW{&ܻH7'Z2pqika\mUu!(b%תSj.N%,#Eyxd'"њ_IN|BMU+dIRx: Y٨x"X)afU-ՙLי6L^ Wp;8W0wq߾TVD0#gb)4$FIѭjDf! K}ɷɲGH2K&^_'%ԗ,on!t//ȹ )uH=‚$rwL{7+} ~D9iO#&8"7fh:MVૻPK%P^$H~*Z*ijO:q|}ҰtObH)ʀAw~K4#o'%֭y֬hy*3͔yă"}J\&*""8$,^KvrܷlE۽W-jiu })>:mL1 J Y5㏶zzfi~fm au+Ԛܳ1)&*:l~'Հ k)5T1Uipd]v'Sma& B8pㅌv4%\&RB+Jf]v`H gN#QzgFS`>&2B5+j1E˄nK}n;yɘ(A樕sg(ctmvT ꣌-l amϿi,jנ*o ܀BD)?B>&ڴ :s}ܱ%E|5ƔR/:_l КɋW׃>ikBmaXUR0$# FqWD@7bxf̖׿OgIZ$a *e&Mʓ4)m<VvIز`GCd-\=ŅO-=A-Sz9%r9N4_$Tlō{h -&Kc 4B-rqJQy t7<M΁f~<9 zS' Z-g8$ iLΓ{VyQF"Ė62sS3laFΈʋ Zʥ@>VdԀ9!S,bZ{/|^lwJ4..hK٦ n.]AynۍK؇?H7Lzxb&3>} n(LIwk땈l:.E=UDfWb}߼hqcNOӡ5]Ȝ˱Ci"7"}Xшy#\_|T%MO]_R}u]WSi'3 Jrg|f $FsTފ <5Dvno!3cZWj;l j ٰ%ϐ*LH9f:ZnoQ䞯\ _@o&xJE$_;=x/,ǜ# -'yflH_q:aΊJ{QR0\TSӣhiO\_"b7En>Fz Qe4CNRʳ :̊]v."~ .y86|m^`#a|Lѯ[mQfħ5t!C?N& "BmP5 w"l!RKyb<%R$Ms"+.ٍ[1PkTGǜ#$ >6F/"(f̓ \K6i€gk?<&>{> e9Bn&]hܩ8[S ?׎!Ϸ Gnr 3 ^W`lVvD=ʪ)sWtB)F|ok%0nvR;D4f+ar:!µ$_qb1$?KGU!O~}jYՕAhL֐S%zLj?oM?JX'JZMݲ.%“<#_H7EׯId8*|çm,t< LV#6IL3 ۨgݚdsTQp)U)|pfE<\K~O"$z5 lǷb,';*Tjqa %RGL=c*.FE=s{;9q^W/kN(?=!K9r{u )n戁0r?2D0,v tLE9lR Y|.nݚ3^-n3ixʇeٗlS'lw-Xh (f>aەu>Xlo^;?XaI M^ȍ%3j80uSᯃ5: ^čIEY&gUH甆ol- mnx Fh:$, Nl^c޺g7xs]2 jqtIhИ?ry(`Aa62-87aV`ͧ'EN 7Alui/-*'.)O:x9]Aݾs+IU7PZ4<Ya/"Z=WMTzeKilpFJiCJ >>+ o$hd7ƌe#)Fy5Yay>w%'a)"SZ F]ݡ#(m:X8ylXډ7kɖӋ,3M/+'U`JX`z)]PnދrSΛ $UkﳆABv Ab2{6׈/ ^+f%1VZ=7 ¯ sBW3K!"m JQkbV$T ꗒuT*gzT +Pf 6ohSuB"*`M!jfP 0fj5 gnγX!'öl3'3Zx@Þ'4[{QLfcS Jʑ&]g!ja (Z&{AN烀n;[2rr!{8>s qn%TwP ?Ԁ6Sb 8Sd+(C\ɧ{7VSԣ؀9թŢrY;kJ\H0y2LHԧjZ&^_aiG3s%I4>R͠@Zjk&2)S*z5[; )p_-8c􍠓HyRP(e XՉ51V<o 0T^W ,ɅSJ4g+W̟Ȗ#i]E+D1n58tPV̆?*\ ;ᜮ9h,ܭ6˩dit lz x# yy\SC2,VӃ7iֿhe^'π=5*NC3Ws/-1If[c)*]*,cMkJ6;s= ^x5ݣ|>kH )YXt |pgJf2w( tl0j˜A)5O`$Z̘J큲(|~envgYql֊F' TF;d1D__uѕKn-90<[n󄱫R) -@%TNw߾jrB9-P3 ùfcU0<2 K-x@0Ù9>T_Jg%|=[{/Md 90QOd^P 0/VWOCO?i]xUcxg1#x7^]9WTntJBh> stream xڭTeXA@šP ifbfP܀ -R(J "]R s>u^׻׽ֽ]PP"XAQ!Y@f1#P$伇p$B0( bb 'pF)/?_I p~u˦2Nۧlv5eOK,߸ j+NWګY%$$Y} yî3gnkRm=W5Uo(e (Ћ9NeH=.~K2o>ڥ4 #z}恂)v璮Z\ }0!Q'Q#,RKL)ldc^;|BF]@ ˢa7Z'EO GJ)X?WDG5OKR աH?дvx "'qSNL ;~,z3}NHnf=uǸ( H{Ǐ8N?7$_jyYϰnee/_-hxZʨaDžUNQeE&ɪ]) [ MRƻas>ks6,m}j7F /< Ovd$?VSEZT[`}fGSDCmOƷђn80w;گT ;#qC^knJuj8{Gܖ?*YMm|pJzޘnhEu难m8v+lf+fM(:J34\ښ/8SeJm43Kg1QL{“YF"4qq0V aܼgX С#$էmdR wƤnY|[ulP[$2q'ϩhIH5ܽ2U&lpMҌ콟Gn ZVݔxdxA3"-oaEC6)(d=vr1 e&Ocפ1"f֕v MWe(Gwן9;:Ɔ{os(euٌCNF^i0Ul5? q.>!7cMېQfi~>Ka^ +u;[tc eLW*w5?m$83-g .S6=dΌsOs -=?iO '"qRsW_K>x>30vX#qgLi1ԝrVݐƼ?Hp3vgӱ#YX:Ud=Ӻm}5E&AL:ÓX!t.:}nQ*kѸ.ypadϕϛ[\4i/kt-u?7&%ZP# H(l/ɪz1FHF`;x:$5s]PZ᾽ox/V&I:w[Hu+i=_9V}|k<6rzNG5G+2rkY qˎ(B|i 'mֵx~4Żح(֙%w RwW&lTD#$G MwI1spݯUҏ5R\]x\w QH1;Ѣf6_OZ|*QwЧ1Q᧿}dx/kFlK}݇%> sT>^a1cUmKҖQZ:5~0mgl:W<Хxn-bk1Z{+RVKvwo唉s-IDC 0f:7 |FΓʋӲUsGėه,Nʮ~f "[{1Ӕ $mjRR$k}Q' VxfGL8Qn+{1ԩw5! %_$ ّXǭ3?+oZc#0#ju6 endstream endobj 504 0 obj << /Length1 1144 /Length2 4578 /Length3 0 /Length 5332 /Filter /FlateDecode >> stream xuUgXSYi"̀7齈HO!$ ұФH HSDzWI}(MQܙwֻ[:VFb1x,Xh$l=0f26p$H""v(</L=(,FO @sU,g 6@hÆxx!SX/%Qp %xq@ga(7(no(!%%7QQQzdp p4G&8@.# aC UA 8$A.1>*En|1 L` ǠnLƐp< @x7GJ;?' {``X p1KP^x'I0 :e`kBP&n:]gEbɒ2%2 TVac  Tp,>#(ӰTQ^p& ɤaXS!gUW1wtϓ鱒jpW6SvNIb!%'iyS̬#QP3?Y/z޶1~fϚ B <8$786E#]nq68., u. Q]֤ 63u*x%YGET}ޝ^F}`cv(UAo4ʷ*EYioEߍL[`HOPs2o ОCȆnXӃnF́eBO ucQ԰o[6l9hA1GXRB+S˷NmKxaW6FNb.(IU8PDW:INeؖLէUm%VsHgŐX]v³C?xE^(v$iB%zk6V6N8{+{$R5ikP5+]:5(x>ӰZfG:ˉ7uNH tЇOH\鮥6Ϛ~"X^hlܒ-bJ1 PeYm{˶r$# ኶z_sylUɡdFݱNGDm)֡Qv:&!.as#WB>TZj e|~}{r&qׅV^g_Ţ܆U(߾/O1J5ϊY/r񈑷Dq؟Լ9gI7/"tL4%^'z$rH:SHy.VxO1÷a짶l3ܜW^P=ly3m2'MBUea{ "I*i[ ۏ.7Tᢜa ׻LilK3zdIzL5ժX$22-tp4:a ;tnmpDyDܿL5}eБya: e =)OuvDP}bKzI{[Ot6E2Req)]w7HS ԋWm t܌0KI)7;P}ydt5"&aIy懻[7/1|mk6kDg4+rZ$s,`l7#xt>BpLEx 0SrYV((suwN) Ջ:%jA͚MW;^I’[,/4=ztGI~ ϿλMx)*Bэ=@evp74ˆդg.C3K7]]WN=Tk,YFz!7ΙYџ.YzlgWf\B]xFc8\6EIg`0r~waŔ9ͥ?=sACCd^ǁʪ ûBR+1g{mܝEd6UTeVZp<(.(/GZh M=K,i|zen_K,jgJi>F"rW _07ߞHQvCh(^{?kIovoGڤǦH?}=l4#y~/2z׆ /kfL v+jcu(0Pt*#I '{s2SU65ZJo&`B 瓽;8pڧ^:kWܭq}U=u.ų:T CjG) ۹s"ϵ(o)q[!9:bSe3+G 3Լ/ɵbB`{i\D P#çK__ {&`}L9=[@BWbP C7&֞eo@*}_DZ#hi *D ޼ ڂ5CH&Wtт[kB KG|K-bk~=F'Or_a- PJz\U(,hkY`MsdZ4h/\2y`ja0]qE|p}F*d(c@SBɌKE8B;9,,8bb;꛾Vs><_s|u~i_쫕ash *9P]<$\rw?uf1SAtS.zEB. v rHM/9^{(lhX(7c#k`}W@N]cC6W9:Q#r.,S7*s&4I;18BD_w fFsR0i6zQ//ěД;PܫL>Μ]\ c73~}d4Qob9uԲj\crG_BuI'Ѯ%YYaRcPu[ΊIc MtNߔZ?ʥzhZagXVN 8د?,<1\\ 8A60`}MMIypEyZaT?Kŗ\:{ /|EY cBm9:furp|M{PIW0RHoۇ8ߝ&r$P67p[iKNx&{x_GŨb2dV @p'P'ʙF׿Gejԇ$/3f?,{_J;J/1zn:ox&qr:)^##J3+6R-8N I}knR'Dsb5ŤtQ (ItQ^XYY;1Dd1;T߂X69~ELBHdy:eBv%dE2zu )(P'6lYi%o^÷Uk\(Mk+[K_J~Cn:T{^[[+=r>lJn|/_,XS.ROh][3E8pS(/ ok K<ԡ^ݾplCgG^~짭( t}rdcĥ-)n~ŭJ )x]N'4"B>JȚ*? O1 9TIZt-7vbj,(R&)͟qWŁ5JojYW Q]w'g\XVRe[B{ež\j2|:-繌5ؕ5_ HQ%5za.(1D[hg`3rw˽tds/^ mt;ۤ-Aj&YɍWf;U:ZUwBc! ;; ixEaΊemNkc%jDc9iu4;yZbjb:(tE7TRl>wR|u=5SU*}cUp){ZC>1m86Q6}[WK5\> l=-"^sm$wNo_w Uꑓ>Qfd&Bi5FKl,HZ[vbV6Sy#=M0:Kv;x>ʘԉ͚5*vJQHJ2IVYgZz5H$^O|&cjjO+LPmEМêv>p{uΗbَ򏠲=KL(ynm;᯺BD+ Og6E%+݋AFVQqp( o>2b6R J<4gQx!ĜJ'9$4.cnMϼ!օg|:ʟwIS6᪢3RLQAYpBo*a`#\lǻ͕7|dR *zYv3aYE|WNOq-"g1 7ak ݑ)0J{ߊ>mi'@47 Zw2ֹN:a13.6u0_ DAwILӥuc{lJXvК-4b5pD|}4{G3!.'K#oLz#I8Fw\j}2!?aQC2 endstream endobj 506 0 obj << /Length1 1177 /Length2 2165 /Length3 0 /Length 2898 /Filter /FlateDecode >> stream xmT{\ ?.Hf8뻃}2(ġI;H@Lxp<"$0#{7C& XP3 E| ˤp@ C d3, 4~g<t<Ah gZMHgfㇰ _8uՖ@#gm@' 42 4ȁ1v̠la!H7ƃ7@3.EԯQpOt $c @! h0J|5/J"Wa2 hd:h `C@ₑK$DT@|·AO氠0a@ ·T&nB8H":?L~X}ohf >(U!;cИzxԾ5|U:_E ; Q@@` PV r]!_WN?˥ӿ@gy=pV y :o פw6 :# @ C XSɠ~} ɆV3( K+2?$1(L*,?*MX9})3 a Eb bs2~רsnf,D|i xf|KXBWe.44m` *'+'䐠p۰i06s&/ԡ/lCդ:Gj&.U?hQQ$dKaѻVRa{7&K{*KnMvPX)}nxhn;*!GmS sr|"L¼Q(:㓽 {/[Ӳ=;Α<[]2"5֎l|H)])1)M`՜ˡɨ~s|+v!qb}уƛA!'⳥ מEݿS'VQvxWU%,]vije&趴,ֳ(A@K f!0–*vXV߸@ BajV$wiSVe'ږ3!/6YĕXk>8Srt YL8PNҶ:JǏ|OH)5ptܵru]*>d4+V;LԷr&t[M]t6)/Se60fmOnפ`K+ OLz}PyqƤ_cРݱ?9yGTo~BO-_T|RVEu'9ӤβЈ}iFQXaC|`+LRYԬcT1QZ@ m}\JwJĠQX~Tc6LiiH_QoML Ibܱ} ^Y;GYŐ,ų-?+J%=z7htafkw4Hk7WE}̉mv\[qG3׭{GNt*6~>vNX=D $vU0mp%uExNlFKߣ[M}--+S>/S 2_I)Bh'd{PO}pARٽ[K_Cɟ3y'2-Y2Fj͸Mی2~m:wU͛\dKn+ YޣT\ /_y|Spf"M T?)'\֑90oö#&*VWLD?Ehuy +TWwE_@KEEbȘ)j"Jխ Qu{xbbzaMsXT5vʅ1S-{rp~ r[j%CjY-3dG kG6;+/|⭋Ć'9,ᨺ 됬BJw6aw/ܠ)}eRұ`fne+ߺX8<}2BcF wu*Fd]_V)$A}dmhcy>RbfW6CQe[|BCvV5;H-o*S㔨u}죌U壥ҝT{vT3EBi&*K/jS3 endstream endobj 508 0 obj << /Length1 1606 /Length2 975 /Length3 0 /Length 1772 /Filter /FlateDecode >> stream xڭTkXWA6K.ZD@  D6v9!DҪmieYiնh/BkW *jx*H"k+= ZZv#仜{=R &2 Kd@-`4qڤO2ɦ|}gpHRu X B f0#3t7w>P3Za)QbH7(A z3!9%qF!"qDa2 34AI ,It qCAy<0Z@8e _@XAzC`*x#Y~yE1F<QJ yL6c9At $y ltcY88~@ <<D" IW 2@.Yl z!`hIUϡʼn$}!9?1 20zi3(*#i = Ń$ez\a0np8APtL"w|,ipb?& G4D:fATgI:B&w4qϊБB: &zlհ(dSeb2Z' }䲜Ŕ$gcG,;2f&3jO a&) [5ft!ǾS"% zyD .E@{f;B#E nO˄=>k<i4VԤn-ϯbyIj-t&w=qRz/ϼC/]XؾR½s~avWsR[O͙hۓac-u9>K4}{:yrs:9q{c7o6*w%mvpX̦ܠ,xHW5"q~KW/7Pn!ND;Gw.тH"rܻ&9kG#^brOVh(2CYFRٞ`/<ݮ!yn\ ǖK [Ǻ O[ּ*[`G,BwIWuLp=ɬ\sGoX6V.s~m.mb[ZX,W{=V4ůQߜ]\k_-_N~d҂YT~{yBg:QWyymSw];Q~dSnOAvvklĽ|~ˏDx-#S)nv&Wrhg/z/,&;"`j VoX>tN=8<xxlŞމܿ'ṃO"K.)mjM%Q_e]b9^E d᪝9䉕9`b>WWJ0IAg>uIBvˊ]>ʳ[ 8|pZF8fݥ4=<̣. .ֻZeGKN m_ʦ] yZIm郵|/mpc͗m܉[,gwU:E-u{h*ݷDGKE _Z1U< j1+:U+\_^mi"w3-^cE-,Xm]0"vnIA |c endstream endobj 510 0 obj << /Length1 1626 /Length2 15729 /Length3 0 /Length 16573 /Filter /FlateDecode >> stream xڭct_%Tl['m۶sbbb'۶m<}o_3o/5ךkqȉTL L<+;7;n9zy௝\hj`/f hb@S  lea RWѤO?!tPp:8]B_'WK UTҖVPI*$@gc[)@h;8l}:؛YӚ _,a1hj7 i tEp:YX,]`eojfvsrtvaL𷪒ĿyZS`7ퟖ jlepzS0rq5[/տhX[':3/?>[Ǝ^vW`5gef[om +{XvEo܁?;C h˨$Ne>$oE7qF%ZV}dblge_5f+`k_}ҮG"loW&\$5K+S` ho__ETUdh._nyuFDCgec{`?]<fbW'#no`ڨۛݴemW]]_;zMaWLyC2]krtzBKԊ "+kB'y>[N?eh{0m)S~Խ(휴A%g>Wr[:L;*! &YH at 7Q<~z34}ѻGCk=8՝D}QGfE!-C޼j?JagN>Y#H?Z񗘲[lxHC|qīz|SL+x#4';c- kem ' Dॲl#,SEu&L2'<"aׁH&Z|7D1Kni9%D,ALoʎc4k].hԟN͐MX9;VR.RNz1$i\QԂ3;#]Jg7 "m:xZ|9+-:~]0kLc& ͪXI\lħNKy5[=J0ThH:'?@>1p@gw m='4flsJmW0 gDY҄~w3:VeoxPnٸdW}mpxc3ś !^54i@ÚhDJY56"H(eHu~Z%jQ]e% ;[Z!va4w1{\M#P9 JIwt$*e. $Ȕcu"2 Tn* 0RxNvS5;I^,KF 2YG=veC`$Xo'-9 JTkbT;9Y5sŖg˛Mo )T\22?m#hx4*g~^UgbM$գsm9}h;BCA|^N~UB"B5A䅤$S=Da8R,M7g'JLJ0 IL!&ċC\~>7Б:r; Wԭ k"Eɰrn0Z3v'n.ǍF!fw2&|`1:U uxʀ/^whwXCW&~ۄio-<'5=+_bR:gG֞n] bc*sRTc4pՏoa%9+ٝE('/`+K"W.kH7|/tLfvlnKcC( :e|:^\QGؚZZ 37ms ގk1Vs9Big55} k$o$m}`}oJ?+9 fU)y4v~ ե5Ogy1E.)A/5^; Y+ ؓlhˆ=s.n64u#^ 2lM˺Kj &-\91tw/*ʽ$wSC{&K%a|BI"SD\YdᇂC]U~{Ǻwx' Dt`-·#+tVHxiu~@h0rT$ /m[樧vΎ"QFaYP?Y͚63% @vlNs-hovY (EN'Dޮse6™b:T֗Z7>3NuG $AO ,B9]-Bj,*+{A;9>j,3߆UV[=Ҋsgb`L_WR /-1r4F.7mQ8>*(\r41c|(K4 $F5( =2SQp,^ '.)AAqӻ-CjA2h_6W,C34Xm@c m;~wS>= DNX_11`dr҉u#4 wJ-;߯VHR ˏ2G.eZ+O4D.R~(OxNLD̝2;ՂN]4^3ELl=y xֿ9 I.X(0'Wyt[-jb!n zW6H8^* ϾJ>);#L*@6[,ws?(!m\ed&xN2;@%Pa']Ӛ7<'X)q+Tr4Vsne*1$V~$;f&(zSDo$+PL4[gk<p_0M`Mnˬ#9/*i =~:%_aȍ[55l,}s9a}cR7NR΋-i=Gv]kka[ߗ<\hucc~w`TpJ{omu>jkFZ]w$2 ([|CZ4W(]V鰈`PPjeF+i~[PԆ`Jq8q[JC8T}*V 4[#NyTJLM\u@TxD0.hej!d4MJr9eId7dK KOsA#1ٖ VPӒT`m{jM8j?o̞׽#/Q])yg죏:H2^PS>3]i^*kSyO$C 8w˜;LxCqpK +Jg@X ؈tzY箦]f6LQksaAs}x w aP4#uG'dSڪ ')Z-ψ ; uCddW!ɃaȞ %+)8fcg爺" ^E`"ȸT@b+b-l@C˖MnRʅ[j¡;5[ H VgyXYL<^\Ϙ P11 ~\ϧ5_׾x0wmZ礫+e "In*9B̆5ؕg rTE.[ZBmdozHtp?>< ygS?ߙ"nFX70 L4"yq(jXd05pzیԫA,4,Wu_( lcS d [#>?nx/̈JF\u9Cj\Gt3CHxyw\'R Tu(I -1QˆpNRos-+#^xё&S73 W$!f6Xw>s#e@4(\ħ{O4pϾi3ːj.N\`r%ۜD~j|=Hhgqc8D)BC,@ m?uPS˥EH-*/=Qu{gBFHKm:Q zgP_o]3!6Q ~: _UK&IK[lAl(9 tdէ~ қmOhťrRwWO@.rM*# ,HhdoBVu+Ag`3PmtjyC$~͋SbI{k+Y$6 BBnovGD&WJ0#**hl^@j7rݙ+X1]Hӷ8}$g;nMl4t:yZ mL63{lyHY[wI|_,'Ŏ5Ȓ{?m\2[Ef~߫l}mA1gv  D'[bTA{a 6oXy5[ٔY' N*=*eLV߆~ĝgLpL%d"Ơ^6+`~42g ㎷YA7"猇7bA z𷥚nH-\bL㠰Ŋ4jE1!)D[IO%[{ tB:|YjAFT quGo@j{8ZRS8t ᧝V؃+j,[4HV%d$HzШgîPub%4e]!Twma.Zп޾ʫLvm8T-d2;^\LW 0Ú48p1.k"^ԚQDO-y`Skn9@T𾈲W8QȲǩC!$2'j2wLaӍ;LnB^- YRbucVmD&d|3 ?Sh*aѷ[؞o7Atϒ+\Xj3OwjHE7^QûN'jk7"n`7=ļ ).ʵ'H\hm_8 OLKwmAc[edAܽ.3Ҡދ$oֱ1:SQ` ! םaooj:z^s`ԕ:NI3PZ̆~we?v̘y,NMq ŹI?4t.rnMLHeMi2iCY _h hdx8h10tWDuvv _>"MIALی-Fl[*~10~3yimdDS4lçܴPD=ʙhF*DҌ%|n YC@$.D6;CH0~)0֫"sU?`5ivxEQ=2(n**EĜseX$oyӑ)jN 0uN]/\z&h[q_%2"RBŞJ$ dSFf:Y^Rr/xҷ2bn3T6x7` -֬8ssF"|HaFo|>x9[|]5JlmB!WŤuJO`\J6ǭz ,6fp.i8iAwIk@]\H`sN$a(?0J\T*#aadK 7D<s M9^'XÇU8pJЖ^w7 0O.;@Jw!t>U?w,%iz%ICЯ@ќIB:;p0$/kl"^57cZi= ꈠϣ-~?QjJ ]dS1Sj,5jkN Oʜ_p;}ia*#1UyйȲc0, s*ӻLij킔Dcڹ.u|F8/Z[ѡ(/'+r\\x! fgV=g 8#-b$s19o*ksT[)HeH0P ӱ(vI>B)?\TX'7/k5{Es}繋&^\qQ[9 ޹-e@6^WxR6`/5QN՜Ƌ>|jCdMJԻ~WרũWȗqT*H>!YLZeeDkC HPZg7IP."mDc_D쇃f"ON"n,4CB5hhN5/^: kLjMBM}|0N =s;J̫m|c-ԼZ4v@0LJ#KȦ(k8 ewN)ΡW&ll|jb g\l_,7l0`~Lqv(Ff[v]o!ͱeПMO{" 2&K{Af}>x/w_ojҋ멼?`:p]w#Cg6%_EE 㮕x- ` [!ݭ&ߵ$3E/OsxC;=xm+\J_Cie@ؗ\'AgGzCOt;l5:xVߜ ԆY+' ~Vc捻^p>Bq3@1mV%kF~)M44[!]]˚I}F7TqJa/"A%rӦ=q@Q@ؿ} XM5Š-"z||;_`31k챓z$&XjK:M~IVZL,V7q3 ix)KS h.DsټI,Mx7hnʗ$s2`lХ&N"(e1jQ \%rxZCZې&:Ј~7+R]lxV;|]KPPn Emr'Eh6?v}A̞\iLeͽWcTR¸4ƣwi,ta"uX Ķd}~g.q?O6P'DqƯP ҐRxwӛ,x}S)ըHMkkH}F.AqMqenwyl?~/J.kTAu$ϱE/\^k a7-[Ž\K"24\B0mGM" ,~)8Y^ccA+&G!?YEQ7nft@)FL! v uiܠZN̪&wAfy Jڻ>cy·L4i=eX&1}H0q#mBw&;m*a(D*Ǻe5jD7g=okF=W/)8#nXlÙAUpng2Cho|4?0AN̍!NyD51 #@obT66h yݠ(] [sK[Hr^w%¬I)@B&w6w*⺫wNnmx8z9}Tg%W]O워~ 2Y<;NMȷNڲW9ժO-ɫYAPTIl*qߪv)8^o*bC,s+)Df@Φ;y]t师s!sRmbcQzdQtvׁa79^+]jE)$ZSG\ }[;KSV/6Q>嵥H7j{ЏfZC^h[?4"/bntvz[u"z >/Y }OcnChFE;Lnrz6{g~0zٶ'rng?Z/ K@_NlCv,Rtd-.#L-*:Z휭:M|[r*";ܱJ:3D7O"lb@eqBV:ˌOTp^KGeHYCz{(jb*m3e1P&%K@=ՖuZDͮhZM>c59CC/!OɾkX?_Vܜٲ"FW20^o:f({i*^Ab\qؔ" p U@ qJiRYQü|T@p>%+{Tzq;"5TH>c@I08%y BNQ\zZPҾ9pUؾex}j~~(HYqX3-ך}QLOCKP'-!e1x0Yi6ܧh3W3,+O4bCO}@j~FlvFWv,Xԫe@W %֯aq;~m\ τL`kig$O!7ܤM(8c^tܨ*7 m,%w$Ym*:MFOquHE:&NGoK8a[U6|#:}s1.z0CP[qOTS$/PУd0)?9`'L~`Ir>ʬ㔛d|竡+}F0DIEJFWg26m5< 1 Mb޶%BxZ(KQʝUn"'gԟ/B˘\5gB%br2 g!Ve%mTٹy'=G 2R7}rT'K#W]n֘X\%j§ΉMK%LD Eϟ +tL' )Zhn6*:b tM.TQK ۳odסH_9pwO5-Z{¾px𾲨 bmDCaOp_)itQ` {io-E+p:cKu?eyY!PbS'ɮ5MhgO3(U2, ң`rRؒ%w_p v=`ٱX'2hBTgkm:Km&x !l} ۖV)AIakIoEb&ju fp*{L?)yWRWo>*8t6v,C#bc\,g:X/FkcFG0SߧPe1^l ڕsd+>հUDf:L"g:LvZ+ #dK+at|WhSo+C!! =mH=-ST)z|qCx*SͭCN`87NNi $Eiy}3]mfKQf_0 \sẊrWwlekҢ 3$eP¨CD}1,Yh2@+>1r@$UG>ZYi?\QYoCq؃iFSg%Z8HMr.EC+$Hıv%am.hJFE ,}HT{1DDoo~%^.6Z:Jű= cO}"_Ry"uvA #}+] !/+f.ohu cr4ݔ˥P.7 J=~ $t<6 O[HK(ϒ\z}=\A6aw{%4OYTrr=[$q>2pw-m%oyLXWI MGs#6N;b QN"g"#_wC~:\($LqvhQ*'HS5;G+Mf{ Cn1N =5 tQDKB}CrXN+yN!ZgLU&l}|[!ZD@|ևh}fDy0>Ds8NQ|u*mQOk1HT>,%֧v]ΏJ>qS,/BxիӱLO,tV2i7R|Rڎ ` X+jb+jա/J0 q1ưv i7:fYSpN2>{ k5WX~*vbYڤVvMdV(GOJRq-pڬa1~ =$_F,|_v^tVPس5lwջ_nce?yDe"0+pfU9,1ݱ EnuBa"G*Jw %TٟMK01%C ό !]m2X#c__4 Up`*DDB,^ښ9KK "4̀f;҈5VgM &bfȿlA,J}QWC7v#$1aRgh0cx|ڗA+$\gwŽH@`Iv߂ZJoN'xl5p}G/1%r*[onNlM۳iԘKniJvFb' j޷O0vA5wO^x Ui>wo=c"2q~Z! DAh0 [0prjx߽MZh٠̓xm5w,3|4g)AX) f=Ex,4EĢQf[cUp?|'@4XE5c<܁(\g)]Ʌִ^k(KSGǐM[fE/62;ݸ7S$QL=Ѱ endstream endobj 512 0 obj << /Length1 1630 /Length2 19479 /Length3 0 /Length 20309 /Filter /FlateDecode >> stream xڬctem&b;pǶm۶m۶mfvŶzt}~1=qM\{EB D#`lgh"jgL@K 1tqR㐦Q41s@98[ 8pL&FFF4 @@FAEELC@/ `jamאɪLlM .Fi #[' #?9pM,؛8X89}X8 l`akdbOvJ__0y;'g'#G {gߨ¢N;ӿvF./_Zg ['? MNcwW.Nf5/_u =m/)-4ߘFcYB3+vˍ]_ "gf(&a`lgk061s@2 B -bm-k`wc-HY4? kV3w0 gm5K =-N&FS=\/j+-l!*[Z_?fP 8+{?3`^4 FvoB>bϳ;@o ?~y/0"FviF.I[8kMLMז팸-ӳ21F&~ؗ5)rTԅ6Os~ux,JRG&K5*!(D"b: -8W^dW=ڛTP-ǝbr~'r-G%~5JkCFlB/:;'MD646:2w 6pMEerFdTݦVOqɄg-|@Ͽl'v XK?.4,н,qʺ~˙nks,NT̲J/>`,Jώ3܀G" _?V_ T!\fM ñ[7=?e(yěbs,>7HV3`e_zKlR 0$-f|h<{ݶ>t@>f=H Kr)(X|_OEúfj?ڻUٝY}\Ykf}RW>qPH+zd1G=:3zSZuFWfiKA Hꞟ&;Hrf~})kR|~^ AgKW 0\}S+xFjyoZ\TP`)I v,SUI5* l\7oqonbY-SNLh g>ҙ?@",qgbF1ֳPX'fGXap]7pNc}f^/-)U;56jH8ATwN\vm)%*˅'ťAi(#^}iB=ܮK0^}#)9pkl' 9V\- l@Du&`o­_ߋwlWGN^a!Փ;,qx$q߳nt`s'F[5.G+x5}xdoCN;ٺ&`͝g;YH .ÁǕp<³x[mNw;=D5WV r̐VP24l u%X~yq:xNQ)_v R޿U DZr,eՔL)m]{Q6k@FaRvFGS}!@],Fp}QbQآښK"JY 3*Ʒ]&ˇunVB*cYV|3L}ɝ4kƻQ-,mH}1¾CzVJVjj9M-9n RKeCtYlGZo^q\FnA8ɏ?79K_yǫT-:yA0%x&u`Q$^NK V> q8a[-:X0֩}77*a0{'l.ē(^Az엖KF0f 2{xvqFNDq:"ƬP M][nO(VFDB֟H@\7 Wnd ^RmJX o[8y/GjȮ[*ٲ= ӯ}fnA(-7YVd^s_ >D7hQӒ 4h7='1R3\RF!hI04~ љ$9ͱƄ?VӘj4~[< Jq瑊P ꗫ k;7h,S5ng,+bs8 q\zG%oAd˫~\,N,c4=}&9!NC<)G~Ul' 㥙TiuŪ^StZ7(yWե 1p>h}CE43k)2uo[K\E{ppШP#n z1]̋倅?9$Ѹw4)WȀiC If%Í 88vZHra$!AL0:PSmtBU3WS65D~E郣A͏ Lmx|Er`Z&R+U +2uw(*t~r,~> 3޽hG I{:3眂}$Dߣ. ETTաe?E 3Wㅉ~/ sarYw%sRsqZvL:6: Ҩ%1:,7 \v?n}طbMm-mW |mMչ%5c^Ξ,Ykq9*V=(I?K%^WC@JR~Yχ\y{;+Ry} s-)n/HE!`-:Mi׵՞ b JC8`z-᠂g|{Zmd%kFUMkkOtB eQ񦬢^ ĆW PD'TWQncѨ6d q@pRb"m4!(xN&Nt%||?RI~#\BB6&(!}˚LJƌdwy͈7C OoE:A0/۫2yEUCdv~jeo.E{6aN[1+w٬JېUֽ/'?LW?UQ PI} J#(TXELׂ4_PS Ǔ j ěz][1|ܗn[9 3BnGwC69Լ$IQJU`W>nNG"`AqNSu K l=rǚR1:7{̆d{ʳX(JMDҧKQc^5j1H$}vix@'`MvQ].h%| U=kO^U@tX0f%%9s M3XKKᤋ$i~~Bcهa|:i)([Qj -G~&gFnE'^Y0_!2 A =q#ͿJkP!,iQ iH٨F@DIOzGl],/nԟVO_?QTLQl#RdD μߚՇ2A3VukxE{XLlO]@0?Z/j8vi&'ǀ6&龡$2VaP*mjC_?4P`"0ܠo3?aj:nVu:額 ۸&[U0!nޏ&t,~oxވZvcZ*&o Ґ9‹IsFhœ"lNl(u-(HtEZ9u֑# 6+2WfS,!yg19>W۴.|;:i{,{'Fe2r(5 v:<(fkFS /pĭ.^ D4!1x͚r9Mcr>ڕwnX3\Y{PkX'Sc'EyK;uiDjP%r$ivƑ?%1@q`OL/u֠pևB!6+ie_n'ߍA R}ȍ)@:aGWlneC;p@ po?Z[ H^: 2B {z`& !>/Z͖EЧZnP; dwδi":Jg& 1K1^28"$]l_ T.uc[|@3p\z 4 FXjI2Y˫۬'}g,λ|ː>Px`HA :fM͔Xqh鶑*43IM K'UHC9pш|FKƫqd5l}v{D$(l0>ga^9=pN7-3r6>/)pV\!%:%%ˢݞ qĖwYbb:v&q(y)ť*$vļv+ /=$V{ x PHӀ1Lʋ^'7Ls:{y;:yV<xe0Eu |h6u-(ąaVnze<#vDZ?L-`1\KЪY/6Cߋl7oMq8;;\uvNyI&]6Cq4 ̋_bF s7(DO[pk ʶIKBtѰ2XELDقȁgWQ)FF; KA}.E"9d^Wwg:mU\KIZ8a_Wݚ#ܹ(1!DU zİ  +Dٰs <>oݤIЄl+ftc sfl:d'Y:u /-G^uђbޡDt_Xk5~/:rxȴmhYS-Q Y\mU|K$u6㝣ˆ<6M!u(z \s 75SIrR.;ײD08 .<(aȫ`Xda޳7h\|?2_äMSHOxf0tB9lPbL剹g[59{_UkJ%rdfK>M1&XW$.RCR+ 4 mE1U v0s; &Gm2>{g aQp%\6v+;D Y{ooKabNp{rL4A0J!vG,.؁n-gd _ ΌqM3?kWN7V_z;klnd%J?dZʫa<ȈPiTG73ߪ:xeeBĝ?P#3`Ӌ;v=M=t_d&=t UuB\d|i}c1xݟ2ܒ:wwCջ:G.42PB;]~k# :&Γьz)-VBE ~[r 'ƞ_ A ByҖ./ {p%`}Hs}_;W^%`6$/i7Hզ{jdEj*e5D%, 5\*Kr#ږ4IGÅ7utf(<W^a /-z%ht1q7ax:cBSЩ2KaCz'E߻<_l}#s ϣЍn9xmsʃ=^eWUl?%zt.]J$(+GC2k|TeGO Li>ppHW3r񐛺]e@+ !@U rtUͱg831A^1%y-)7l֨ ݒ&/]}lֹ%e=Z+ŋf֩qvcmŗªg298G]}~5|Jym/{&ߋhLQ, HoJA~#|Gw3KL8 ‚^!bc P;X;< WE>)9 4kGJvxăID3*` ?H8ZWXEt8MUxOY37L0C7tVJME%Ui|nݻ0QɥeO{h4}0T)? 'vi0Id58-q)C`oY#wn]Uco//p#y ВbLtU;Nܡ*XUs6czqq$pgKYakqZsͮfT!2p Do7nPC s0&{OS!~̰t,.%?X >rق2чiZLVaΫ$._t$hcF`<4>4ބ%5v1ZXV6;̰눨zUL1/@A†M]7wiZ9J+hWtl=(1d=yb:B(M9jޙVxACow~wQ6nRT!C7eEi(b4ud= 9TN]K >:E ~9A4L̞}HlHt Ҁr:\NT ad֩-;نz5qZn0p`~c>+,ˌruGH#l}4Aݳ!QƖ W'|*1E&g mAr(Z Yk`F[tsV8'L%L؍*D*9ʓ%7j '\C9Ov4JϖTO glDO6X0(Rp!wu"Lo7AgW2B4h!0L)8wq5D%O2/a 1b3By 4G?۱ hP<Q udLsiؑA&Pysk5 3R sםWBcq]MaףnMF@AV'9f2̃MmW$k_=f,Fk37TPjw)VAl(#,  zp93N6v"٪3|F hy$faO0Ũ܂';5ĆMZLoFzϽ`H9 m;=6[ lP ˍrc|os༒so`#[5T(WSvycP,{Foxύ)h},$ʋj;b?Hb9' XOtIgf"u4sD+kET[4QA(_!/HC8ߩUhzb7zm\8Y8 Of,Å7'6guo%چ2cEQkj~H4śkŽϑKT5asqdz; Ԭ[g4g3\6-G_hJʡ9viOQe턺aFf94ym#-W wEMd6g4;^FY_r/oyPiH]BBpWXkY12N1d_X{Ra K8g*p]xpN3 \ud –UxHWR[[GiK1^D@cĒ2>(f2.dLmr'!?P{x RW,>(1\ .? pر)lC?oЮ%ۦpbSՋ}Lya};HE 9)^Zx~٘Ut'Dy ඈ; mW`yX ˥'IM O'Ex1I_kUqQaujkޡt?-c7G$J""A)oV2Zm8UJBvor#14xE QFTKE~~IgkBV-FMϒ=Qa95+:40,/¦8/I.;CJ|ܾw8Q1Z jfR[)M@CW4,&=BZ TSHy2QG&%1'Q ?c2'3SyDYE;T%z%+ATiAZE.P~!vU'5q)kT-.yYj͑XBb%I7k`@wL~vo\/&yk F_~Oԣ\~6 DBjm[ϯH2iy^c(k$/ca $]4e eTpXb%\u5&`~7i겭uhNr} !hg nvKKxMi3}lGC`ӆϰ8,eޙ?ߝ}[YLWAfe{2704|D< ~fD$,h +`Q$3ɸ[埊1sS-*^rLE`[% =C! ` ô*+ahӶ%+p8Rޏg1JM 7D._Tq"uNȁIWXqa'|`[| +XsڡypmMH+5\B|~x].d!0b7@ )pF_ZnSnyO[xc 0xӶ{e_3;̗z8 iG˪gŚ=9+pER1Bi>+p1ˣ/cz5`eȱj ͣe,RռkRDox Ui{G(dǒڗyJ'ޟI@&8a160IKq wid&ђrtΜלO 2~\S~S;d]A7$Ma#5JrB^'6rVocƪ<3b} [bn _[H9xS{˜1Cm *4^.LvEziTGhٵH#7p|C}nW LS~ ƮPppxX,%_VZ%/Mk!)oP֑8:g0y$-!ak B&31 aorYڑKX>Ljh0"#{|^/NRGU?\$)^d_gדpH DYQvGɈ 8T*Ksey!kOyu#\*1Y-DBc~!4 _uf+YE=t*N7RmX^v1POUL't-ĤkҮ'5 zr%lɟ1¥]M }B9%ƹ_;94+ 5Cr;z-W%^J®/_弢qP4 p<9p3phF ۭOT,H Gtu[+BF"*~;?teTp6I=aD,=Ęp1JAХ̒ 󴼡}0NeATEE]$%6Wn^ LrG?sAc#D9oClmJG)(Y- +_lI#HM{?*Ը7MFH7]:0N fsIUe9ˇ];F0L=DuVZAUs b a+>"LƇz}<[L4PAgpFȿ`J*u`<$*! `W3N%/z ;AhVuuzE.=ѿx7>Ŗ?nS8W 񟩸V3WTnm^S,6\;0NR*4CSR}cCzܕ5iV~( &w@u>vfFhV=ViQOEW?AmbIQc.;v=pe.>p"dm N(RNYe,*fQg*ieiY6:yl]tФDQs;^Po ݁E{$~?Lj]E })sBmS\t<ܞ ֗=ZzipnHN΃BԤƐYGRcz{xN)A^)s"#< lteC=׷`ۋ("Vt}xkv8HU˃,C)ɽzxfye2:vFFh2|o8qA_nz}җ%}28O;"vіxںt&̶97YE4Qd4制47JpQc$1b#)12dN5z z7\ҧ{ěS_kdBخw0P=D?diMs56! ٓ'8|Xw~IaظmDQ"9vIj+h"<vhuk=ß6h10@>NI N-S.o.Ƒ|kCa޷MyLlZ}吇پU2KO8oM)<$2K|*ؔqaqƊ]9 Y?|t*D:ZNEYG;H_A/Sbe^Kwg˝>rRhwjZ-(W8( BwVZ5u$|vGg(,y|Zt`n}.Ӈ1}iǵ-¡WAgr6 jMh#NJ&X୘? ? ,Ȼ]щ#D9ڹ-*,NLK񅱳-0q<&hx۷$0BCU=D32]ܐjKXq ހ(|:~ݩ*hx fjWaee=U?Cc#4 y(>JcTʰwMi$}w pCO,oW֥]gHPxVi '@FO; Ÿ ynK '|3֨ܚeRE@@jy\y)t*z>ե^I xj͊>~NJ}`iuk-JbÑ A1/dSѢɱbߜB[%iզĎ}UvH?Jh|x6[7ŲgYƭ:Zy$RpP Ak[h,aӜzM>Qlf]<3z [Z*̀ (gLO?LEUȹ!?dq**3 H"[fu oEgQ k3'!$2AmzV7A0o,&9.Y0ά<>v ԡgF $7%&ysAsy?8~otz:^TUT\OR[g+JXͻF'gI1E\'L-<].99/3򶔷KG+D..mc_ @ Gja b|DЭڬH%_Th 5~8:mwr۾iXw۩\Dv0 ٝ*#iY52b%NZ8Off0X ӓ'ڏ6fG "K?ezSC .w'cF?YȖhԄQ< /&hayuFmx~5 4y #Tv=Kh#?n4#bnD&"{dI7r^"rt[Woa8Ait҄6l^ɂ܁~mwu+%[i RbXّ! dY<A^arU=֋FNlF3xe5ymbZxbE~Jn D2$@X-LЂwCNP)sBMNLdP iͷ,%ZpЈjsT4a/ Lu*V3KTgR[@θpé)"-r\eO dp *X*PY x=>.Ck](?޲psҲ8HO#G䨣pAed/) B?Kx" ~jL0,,%KZyP%tY$Ɇ t Gp^.""ߍi-Rmց+FnogWAFi]8Q`n+8댥k *g7~b7fF epO"8. 4L mOC 1:#\a+U ^f6gq9I0n{7vVoa֋pʡ_9h2(zINMYt x ~,F~H5ruYOVTmG6;G3)b`cT9" OhT&XȘٓGs/R`e"-FG0OxzZ6tMs% rW"OQA=+T<.T 6C h@ZobpzIpyʼa4C7\&Qd 鸹!C14ZΆ`^2K7uaVӣ9Vj{fPuv:^X*L'Q|mۉ&݋N|8JT`\m;1Pby p .NB,{hJɊY~U%6u~f<CN_ZOR. ,͹`.v FbBam0:%jX^Y`ɬNv ZuF[%" dyZ6QŞO=c˺!ƞVO±51Zaց$c{"6ʇDL1)ę[q3Aa)oCrg%',rQGZqM;# %V>4@N=}j^`6$#g4#Ϗ'1tk=b[}l-F 0V@QJ &ʃ3e 7fi]Se }@QHl92:wp]\bat6p<;8mfpɼ~])f}ƚgZN YDzVF#ʉ^YFJW6V&BnLDCeñmk#bJ0q'RB3Xؙ sNNֺKþwfʺ544'-B>NQe2ԩrl#F̻,UbOV L$OmI)]3XOc5ekp $5a` { J1Τ|@!QKIzEC\iyYJ#_1m %tXu E"FO`O; 5n=8'yZKec P)Zu{~h6U6bzP/UlG<;_ !8LslytHh(p>F;%6L,DK"F~!R6U=E$)Sxu}DW?-/"'8(8e[]J2wͻ;B@c e; bSiR?X Ïؐ<[Q}  5w)1.lˏKDX/b=H%@i##4.=`WLg=ׇjs]t=JRQ ^BEm9aO &CAnwJnr21*ؿd/!}3S%}y 0+xqz pg+woSR)s_z{gCs.}lw\*BYy]AII>ZHkD#Mae׼ .T3ؼXIRcȓuWF<أѻrTR0OͺTYz,Hb >/L!CTFo|ZNrm`mkU4o7' yY`F,6Y>HW,C̈́ʙMy;hYsI2־X c\1]C-WiUh߻ZjJKOCKoޕǘbLO.pslnnܐWXXRKBƂ׾ӝKO~@2 ?_y=R A唱$ =gMչ"lP,c/*@οo~NaVO ev5yP,"cQ;aX r8~+[3 ]ȨnAp9b݅yf4vd8ЋP] \5ESTAJVN]b4ߨ?GBׇ#n#O*LRs^ҢZ6pF3f8~<#NAa))d;nR`ʳBZKTڟ֞ #޵Cz1D3noT_!Kit}[^K5zk^ DݾH6ՆZb(5\x$Aq/$͔굅 xIW8|ۏ}1۟*V`XAJ3ͽ|^?O j*c mji3|*6זy5SZ,Kgz[MT'QAtZǒYn3[fy-AWhk!<'Pn'l-n+]qްitrBatnPQaݦ_'f8d^ u+ [W`ߓ!p+ϯ$|H--|! 5N  l>,^"6^n"7p5Tyat9qj[w_׍L^)#1^_0+7Rӟya?M[$)hٴJ86gc@%:Z' ~ˌ6ņ0HW>(5}0"!uŇ_rK1KO]CͶ_Lmô돖qJpt E%@H (:Ңc*ֳӼb7@F"\hz\~mw͖Jc!A-s<T&9!zoOH/:":eߪ@ZY_Ya bd>eLtifك?8CNw#*NmJ(j R(Rx J6ufw 3@p*I>@%Lo_)s(vS@}.l ¸9F{\drEgš᪸Nu L$ N2ui̵T 3Ď!o^HͻRI8~&i#Z=:& w\Eu[H endstream endobj 514 0 obj << /Length1 1644 /Length2 5523 /Length3 0 /Length 6364 /Filter /FlateDecode >> stream xڭTu\m.Fn`dfRAB$$AAR$ApGoydܼ$!'DaPu $A11,!'@ G#n(C ^~~Y~_8`<`7(  ( Cv4(w  4<fMBFN3@ "AWpA]KC aT 91n ?g7$`$#n  C!.]a#` CfC0D5R+O;;60WM` H  p# CGCr"\ $Cݝ /p7ϭF!AW!BQ1LLg&J({V0_vo?0Ox~ /& A\@0&$пO-Fߩ5!'f1̒B=^4 =_ȴQ@L[Tnie$dDdH rv!A]@ AQa`go!$@PWO *} @0 *%f,Ph8,a.<&TUEdb2׈IMVL"H_g} ؈bHE~`7PgA2A.7@`$0@~ gs0g2^hsGm߉՚=uEȖ:^U Ս4gw:|h ܝ)\ vޮZKo?/goG1Ogp`Ԛx6:,ʪ7{\/q u~`ώ''KBko.}e/|yrƭP:gq.<{A'BQuXmTǾmN{o^jaFQ.#c^6LU|N3=_ 9VLuD +c+  JI+W=z\kߊ bЁUnSg$د%+뾈գۗK$3,Ѩ{T6RZ}\;E:%}$ֲg\vII}cM{GPi%lj/uwеVZXźq%Ig*loۮ2fdtFK%3gξJЬq( DE{NUQ a:@vt*, jl\ksx;ͯ]-VcTN1:}edlZ[x+҄~bJ{ǠsE .6bqc_ǧ3LH"F^7\ӅԲ/D@/K\ғIDC_5Ҝ/ ~W4H\ ݒ\D ⼜ /Zi2>k`ܦʃ/7%HFb5F}@q8H.ku+T{.{G/iS}+x$g>zƠWt:][Ah,lEc2OaUcOjLxenBY&r#^-:# m\ (y*#dYAVH?ai?´* Xr13Qi)kK_ͽz1l^wHqjťݠ[8C1 g.J_2-#P0^ҟF;Sf(Ԇ[,6zsS[bg] Ŏ|W1`v-O`Ǵ-cǯ) AwԂa:jv?e2 gi#xGh|ōu-/'p G=,!:T.kex#5ā?4\,V+@,J)|Z uܴ y9i_"/9_S`+7>KtYE?k Z*3¦y]Kj4Z`*p+Y\@TPMkT{^Aq^4q=:٤7M#iGݷvJxx{ߣbح?o;_Gm[m3y*=4-Fyjv׼Druk/`xKõ 7!g0Z1"܀/Ot]Lڗ8pX)bLJ<8igT%Eæ_+fҍx]}h,AE̎ͅʭp!SڤarH)% }i@sHTe0uw9MTi pHP:1U\3_uhOhbs(̜+j+nM殓\جC!çk\#GЕT g[ SE*G_T*=ؘ?iiO>~lgSu "M[' kg^9 Å% S7:2.edz_Z"XX(, rx ,5S\YS5Ujz$C1O_mV'1fp TXeKc )i`֫JQF[7%=&KFِvŁ٦"^TZΦfT`N5eUi%"~2^JͳTAO,Iz6-B9RF-xxTB%@i֣{= %fáL]u_>mv]<;i}DDu[WXnF:qYis םgcCg.M%/xT_Ƥ a3]O]6(ŨRW("ކ A*o&Q53O(Ja'xҊN^<$ k9yT0)jß.R>?E"s|iE2?/dXq7.ğzj*v2Ay%X!Tilˠv: 9esSTד^ e 1$rx[| Iت?prғ^@֓S|v\Jx<2 0yʷY[SZr>!tn5k_qԞ5HhZE? U71 #L8$/Ϡk-u{@]h1c._^_~Qw/M^Zcƈ߾bԭG˛/G5O|;v֓KaI> frdKm*{SͿn=+wAQ yմ}UF B*6E5Y*d k *M4YIWZy_>ur[Pcsk`IvR.$r^k_ ׃*on1g'UZT,-qRwĤ~$hPQɍHX |§I?8-U<L ӱ^Z]^q̋U0jяS ,o e߷ ,xx Ѵ1HI/Xe#mdTeCHA ص#o׶0 B"Q7Z{!?y#hnhs:HA@G^1!p Qđ^L &fa=n t3Y:j^$ZY.?{1b-޼ek "W8)j>lŭ$Ny[0(Sw\yiy<}}Gh>{p{~&ۑFI:VƓxs,Fm ro#|;ms.ҡϖzWpp|ט0hqHYVw. 3؁za!Ez^+)Z}*뺓KRS[,GP8EZ*^((vv-+3'&8P6#<&\Oƭ5M-APϾ'Ca|\jC[>GXe W{s@ M uEO Nl'<\yޛ/=>$ K>}YTbwatü->1‡';w7Q~棹wMYS.DTueu1nfKEyuMТZM;E ӝ oN{G1OJx?jgV`xn=΢yYL Ř UQ'v5;uxh!)D&V I7L(g\a,u^x+B.G8;Na/S󔝥s8yCĭvlߑ{p<7+uoԔώcz46%C aCqx"fxpw 넡யnz\|{kA@cu#.!J|fx_-Ma8^5//4`aԙ7-;mXV6z.RYbsXݦo.1xJN0=pɔ/&I݉T75*? R\3zNlxηO֒ 9<Yo{h,*"oI~K:r"`ٮ'^q"Ud*Oyfe~ͫBzPW%Rm2 Bj2.:qL?kI/BB<6C4bZZKZeŐ18U~)4W_ZQddArpz:ў v0EvY'zlP=Q`96Xœ$-J[*XA[>]qmu`:+"V%{#AHn($cT]ǔo7BZ|Y1P<;Iyz=7fĉ.oڨKN;Sq7Z|갸k"v~z3=62ebLD k&oJ>SeudA\fԬ%]e;1rr 'HÛ` R:KZ?Y-71 "[_nSptݕŠbI\y)znnuH J{S+9O?HḄp%e}sY;9CgP9[Ccnu\It՗_FPub݇>Ο4yP@GcUᛜ͌c.N /Yvyxitش<4N-/b*:49)ěiD{E -UIHCxSM۔LJ&Z:RԋWO;[$%L_5eE NLt*Rd)gZ! Mc2Ɛ=9&.>Fӭ|D3l0{ }Db[,'$Rglb"dyOZ窑 ;X"|/'ŮvJ:oتzG MoUlr-u캷(Y;Ԙ9W/]I3 #(H,x3seJBNay>,RdjOvwM oKAP7} R6 2)jSZ*t'G6fƌVPʔ NVO8(5`ʎ=_\VtFzRj.v> stream xڭteXے5ݥq .ݡ%wKnCΙ;w}g~]jU^TIA(io Pٚ:*3-\e\m<%do'nh@S++ ftШh {3@wڹSU@%`>)i(JhR@;{J&6 S<h ;l>L@Zsf|q0)t9;@ 'c;;pLm\n7 'wwL xϪ$.w..r;a럖iQc3' `rv1|N Wg?+pZ;i޹?lc#dO#FWG7.Ww$oW@;t{zo4eWzi΍M^gזbpL.@:XӰsԽf”MzYn7ƕT$I&K|Mc-vV>5u,[QW|Ăe/ r%v OЅc[ҥ> #jSlh6!^ yd'N*LG̥UV/,U0{0 0 T\0ݵ\ƭ] O'|s^[ K𖨛,}f9k4jiY+_IhFog4ځ ݾA6o_<]⏭ۊž=E$" WHPkg,x¯s;IBTnmyﴕn&ށ+Tb,Dl~NNCo`?$ʢmGćk`}% rʎ`) !NF9 9dc4?N'f'-? P^'p{} a5f eX7Ln34(OѤP"I2PĥF0:r"y-)Hꅲ C.Ţ#{|"ey%|&d[P?;jwģ Q jE;"h|D=y/'H-롚{ Don*O4ZF穸׃LjRa]imB_ 0 $9R<N9̀U&9nan?V)O4*U>,.YOmM82DQ=z:-UcEqse~u^i|6[@Mݣ;!41IWBu&`a"I44Hwhת5DIΥA N%:Э(G_9((ӫoQj;#0G*2HYuy WJD+81M@>E$OiP<5-GJ^D#qu\g)=ހƎ) ,'3oCG,.]YB ̦ {aO_Q5:ǻ=ŽA)΃k$W&E&?oB-nPZ~ͮLK ;Dž&R̩tꭜϛ#@jŅ:LF"v0:p:>ʞy7<~g{ ,B0C_7Ճ2¾[F%Qy&܊^mm8n'G(CNuOAEi P(!Xt|i8K%bL`Rp}WiV%ZEGbR 1&aufdbvD+34=% džCn*pݽ섘8 *N0ڣpv)~eggU]5xutH얍*+!#˜vܼ,&NZDZW6cDž2'TeĂfas\ |5(hHж$|LUd(jтC3w1_Hn೸}B[p5W\ZinH@fhC[!+&)#k3CɞiUm^%f]|@ !oXpկ<:9ӕ1dh;T@Bevit\UY4TQD)K VmC hn| jT:[s|hh >>V2^ͯsƒC$e&+fșW`P- Jϸzn%;Rc.+|#d] XPc/ߛ{p#5w(wM`BCc=~٤eRe[lӭ7T yFV -]/*ZXA}/Qf*',m:dұ}CJ2ke$d]+z67'H eS/>̲A UUr-K *s&k'kBGv׻$W WpVȅ7:Tς](dxyuĀRe'ܱ6cI hozGDh2֢=LR\Ќi^DGm:rVDa?3}_Sj۫ lGl{kiE1:a'o1~\xK996^p>Êc r?)^tXZ8H_y5ClL6,1Hm9i\21JkOhMNn):d ׌Wjms fyIJsUPp;w~,^lGih.h&>%+tt{cqZMSvطHxX* $jE+~e)Դa/oְ]£YgFb'{RR,DI+}ӲXޮM` w A75sXH!UD-}g"(@$g;G?]Q睥ZtJ~;͍#⇚C"5 ~"x/݊7w)vI41rIg?#XVk7tjg#%007N#ˤy2dWӂ6@v 'g*k+X\G (N೵`izd!ڇsh{\0sEOha??w "WsՄ$>jX q~uhAKuMk/4SL-nM9W+cZK~6gK(87_,RyojfГʮWA.)h$L-U*uB;t$ hټ |Yߒ>F$1fOV[ۥ:vDl!cDMxrKHe{@V;VxQ棧FCB{,UYU§o8`|ӗcEPة<ۭslrPޗD3u:E ]/ro>INuE$_* &flY>Nfx(sY_K3%CIap7 qw͈:FKa=a_ͯZf`ZN0M$7 U;sɗO[[=Y ~|5BBm)~i+='~癐T4<+#aUdsѥqYt bd~.ιԛ:  iunp|PYkwDdZp ~ݕބ1b[Wig0%΂X0\M1Y|QOE45-6ݔ0G:쌠L0H=(]l8I=} B<-ĕOP[mfF:ד`i ZbQփ oǼF)xݽn>g<י-9.JEŪo ̤LI9gc^!|ߓ/~ j6ZI9I.x'ʹͳ! +P*_Ñ"q3Wy_:nN􊛰贈=.9,$L~[[el2˘l!,='CnVv!("eϕkYg2k)fhe ہ9us[D1hSt8yA ߲o&HKQ}O(ZМGgqKg"Ix$,FftDQ(0rAztC]X}'6j0"!t%~RHfDr&qULCɼpJ1F~C4jAr]2ue[Mo?|gk׽#|3D3 G.#~k*Qf^ax\-&,Ka{,dv8ՉO!<'zW8?JB$̾0HU>Ss~,ag*%{h&yZC!vgStO( spuٶOR [=D_w ǘ~WSݵ' ^X7K}a§-Ǎ4b{SA !9UsKv [R.VN0-'&Km! ی[/tӅLs^#_mܯ)O^{AQ;oaeW yiηzW QFɹEYHxbw8V ` vg #M|=1BU©O&dn*nzNʚ*7_Y㱅  . (1 @~_L|]S3Ҭ4FԞ,KR}R5~\Z}[P[C  !y&/C09=ҢuG6X*1S9( 7WU܈}_SBgRsS*x1}0(`;n~F+&jbޭ*ҝpm[X<;ǚna|\gئ̣2#<2zZ_%!k. :E|"JY}֖d;$|9pvkiYp~Ě.-4xK*{$\24;r}u!9FeǿY1<=?dRDWnpj%Dag#Q܇d}oo@/?f9Eqn|$Y$N[øJl#A ޚQ u¼_ހ_qyѢ?%Jcբ`8 C9OaoKĦJGNβwmlN+܆{eBQ8MRMCڵZ`2E9O^#Ye˟kᘢXBA>䎢sboLnwѴsZmX~тk v- N]Zy9f\ˋtOzqn \U5n@vpWSG 4rR9ZJm\jӷil{w07pЯ/ O Ę$DX(C6zvvќI8CzP\}"W r ^5S^Q9Ч ^;~T!DX!f)f+A\fc}UO:J0Flk;F12o4~FA 9H5;)a[ F eO`qs2 <ѵJz}CH+Qr U+?p7F8IwwxNw6~`V8ư;OE9l1i5=XD%8,NMz!К˂UW٩co5~f !e0b*2_M b(MK[xZY gT7z) :J{5VUb4؀4 XZD>tj&6,WG$[-.<|-ŹSEu'raeZ@Sxg %#=AJR1?5G Š^V^dY,`e* pF e&1(ȼ~t9XT[}b2X$ƃkS،.0z)2#B.e> J!Xp'j) SZIg>}U6Ct$'Nn'9UB+jZ RqEക1?_<'nӓzd`s%d"ۖ׺uv-.}Ѵű<g!֣Y4JUf)"HJT&>h#Qʖ3;LȪM55EG\k ^W2Y@( B։jb-@9LO샵/1TtA(8C0S?5Y6qzSfE^\YWod' hvhs±&nL"c2ϱhK}>ɇ2$`Le4nqP곒lf؅UÀCTkOڟlūhH# ;w"_H,K"Ŵ0+WwGO-, endstream endobj 518 0 obj << /Length 696 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS >_P{=s@dkx;`VY`s4JaQܡn.Uu9\Y6><ٴ.Z.4>Dӗ}~r:-d0VWk,8yLһʮӮђ[*mLr?q 5F8@=@)& 8Rx uD\j2HV0CzL] bctI g$`htы0\F0s jd< I6zg W qȐ+#k .bsrbmXK7ǵH7Gnb>&jؐu1VljOu$՟qWS/%1{\xB!K(hHTЖ枃Jρϯv=k2UKς_:~$/ ~E+7ˢ/ l(/} -+ZXukoԝE?ZKq endstream endobj 519 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdCmU^!1H#x?gx]OTm$|͜s_Iss :L;<Sz==׾f`*_`ɫڟk3'iѴ}=M;7rfnj-eSӵOLg~8 )ok A8 $`I\3`Af<Z]! xNky"7 _㓧q H`nḱRONH=CpB:# =%888QA~!*zƜАT?!~> tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw%g43>\ 6 EJ78 1{~`W(-;]%=xe_,b+-O;q\L}UI--=BKE1p[! Mߊyu>.N5K)Wb٬8i[_uʕMzQ)V(Txޢjy!Z2P="Zd0\ÃGR\).2*Шa!U,H`+j.5Nα@VK-x%3%AYӀzΚ>kP#5m0Woþj.ZT$X/)n)#Wo(oRZ $Kp4Z-b\1ܰJ P"GXQi/8k^Zq:Zs9dB )sL-7xJ`aɽ)f$1 dъcCZC<73JgznHȰYɚTa,_-O87}KԴܗLloK+gJ.GZyVc48Wt]:P~`rZq.n1] S/Pu7Ue:?&?!d&1yHn5)yғBx#1ޞ]Go׏M?X endstream endobj 521 0 obj << /Length 851 /Filter /FlateDecode >> stream x}Un0+CW`$ MEDbɐCuA6ّD^}{l;~\N=Cu.7զOu½t}5sM7dz0;nMfMK-ٖ?xN[E_EzIVCH޾&w!X.ouc׿z|<:Q:XTߙOoGBZ ;ww ZԲWcv+>7+>S} ~!>_Sϔ+>cB|&LOr`B,&+jwRP{xᇣI^U E'b\!'}sG =C:wWq8"~t]Q|" endstream endobj 522 0 obj << /Length 851 /Filter /FlateDecode >> stream x}Un0+CW`$ MEDbɐCuA6ّD^}{l?YtգиY}w 9]7puewSClݤMӍ'oܺ sR^}5s8dz8'7&3Hy:LK-ٖ?0N[l "N/rDz=49z}'wt>X.oFzoкнz|::Q:XTߙOo'BZO KWjY׫u{FRsuB`ilB =@ )U 9yI(ѥ S*043``]߻A 𭑦 btX& #q,pg'~ι58|%Nb'QDa 8g"h~ ' ~Xkzǚ_81Bx.BzҬÀhƘ'g 2xk=6u2,bق6E0F,eL燆LY` YecODV3Μ蛳;zr֟P.O0{S3ux9(uF: }6,V|ƌV|gegV|F_+>O+>G|V|~+>C1 V|B|FB|/g)g1{!>_|&~'a9i0K!cB{XTK5;)NŽbPq<${y儢 19螡SsWѩ?!~t]QiT endstream endobj 523 0 obj << /Length 851 /Filter /FlateDecode >> stream x}Un0+CW`$ MEDbɐCuA6ّD^}{l?YtգиY}w 9]7puewSClݤMӍ'oܺ sR^}5s8PYsfi<WOlKQn}w̭][G 6sCP=Co`BIVCH޾;n},j7ix#7~hp^g=a{>^(Vu{_cwtj̧S! kl֍]]₥+U=#) wU4H6!L@@B@q\s *x\i"EܰpJMkl4\??ˏ5=cMu/x! !=iaM4c̓ʳGym: C[1Flx L^"K~2&NCC&^P_,KV0d 1էMw"CgcY ~Y =9O('=g)YB|֙Bs:Sb+>cF+>3qg3K+>#>cv+>CӊϘ݊͊T_|~+>Cg!>o!>_33Ϙ/>?㓁41K!=,ߊTG^1|8Gh=¼WrBщWIߜ_tЩйԟE?.(Vu endstream endobj 524 0 obj << /Length 851 /Filter /FlateDecode >> stream x}Un0+CW`$ MEDbɐCUA6ّD^}{l?Ytգ;q\]U}s9n\i|ٺQ]jOtusR^}5s89Ηfi<WOlKQn8N[-#;skQ70j(+o!$oΣ;n},j7Fzoкнzr::Q:XTߙOo'BZ;vv݋ ZԲW<'suB`ilB =@ )U 9yI(ѥ S*043``MSin|kiCXc, pDˆzA:x0)ljsn l9u}SrI4"nXCA8%&ٵ6AIǚc:7^EHOupQF^odž1BЖEQ?[0^׆ƨАԗ0 9+ãbLi~jЙ}s~zrCOe fYJ|֟uМ8gΈrYφ}ŊϘъ1LҊkgigϘ݊og3f3|3ߊY[3 =L3f/gd ,' f)Rx jb&'W *~8d0UPt" ~7a3t> stream x}Un0+CW`$ MEDbɐCUA6ّD^}{l?Ytգ;q\]U}s9n\i|ٺQ]jOtusR^}5s8dz8;_Nnft_= [-E~|;en>ڲ?bs0qj>vzЌBRe]*q8cMC0c F F 14Ej~1F60aG+ıcW c rn q9Qܗ8% DMq.5Sh]`4$a]~9Vk?qc.\Y7ь1O*ezl,d mY50ymȋ,aYʘ8 xA} /Y1<*T71މf 97g19w(g1?\֟`g Yg 9LsQ.(ulgYˊx/V|V|&٭ V|N+>cv+>7+>S} ~!>_Sϔ+>cB|&LOr`B,&+jwRP{xᇣI^U E'b\!'}s =C:CޯSBQY endstream endobj 526 0 obj << /Length 851 /Filter /FlateDecode >> stream x}Un0+CW`$ MEDbɐCUA6ّD^}{l?Ytգ;q\]U}s9n\i|ٺQ]jOtusR^}5s8PYs/'7F3Hy:K-ٖ?p>ݝ2ZkXwm1985];B U{hFYs!yvq`TGy7{ E]&AjZu/?vG_L|z;9ڰƦokܰ^\zu \g$y?qמk(_KdR$| 4hd52HHNsL F.8XV`TR!fn"_LS5w[#McL#F X1+N978Nsk`q KpN8q )q4ϮEp O.?5Yş81Bx.BzҬÀhƘ'g 2xk=6u2,bق6E0F,eL燆LY` YecODV3Μ蛳;zr֟P.O0{S3ux9(uF: }6,V|ƌV|gegV|F_+>O+>G|V|~+>C1 V|B|FB|/g)g1{!>_|&~'a9i0K!cB{XTK5;)NŽbPq<${y儢 1 螡SsWѩ?!~tM(Vu endstream endobj 527 0 obj << /Length 833 /Filter /FlateDecode >> stream xmUMo0Wx8T·~h[ ۍT~3r#_)9۞c$_{t]P܂~ݣP_(&w(R|vp#P)->g_B?q8SG AC۽[ia߿{2ZE_cf/1/{/4G+)bUUwkuTO4[@ 0@`%! #P .w)úp%KcJe Rͤ(*1:bDDR@ ȓ2UR*N)KIΡԀ0CS,km:5Bͦ&[Y{Ł@꒩)NMvSpJs}irphS ᐙ2L9ΙV}yXi8'z Ԛxq1GyלNZ1fXt:s0>wpVR.խr)>1qҾKvHX1iS5rM yR6FBlH>]6b 5&5&0a'evb_dfQTtQ]zK/WБ^Zz&孯ӷrW.&_rUOz䢓n9)C]!􁠧r7dE?_;~T?m endstream endobj 528 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTMk0WhFG*! miʲVZCcYy#9톅ļ{3񼛤es^7箰 nn8l=hzI-._뫦~^JIu]f `tTsr*o8{&X,dew+mWos~X(2X.EiTz}ܟ^7uY~lVNMєo R.bY.֔O9؄b%9vsr(MXa#D$ar bqMDs!FKRLDP0.BEHQ#͸FuŎ577v}QȕanOd$g;A,əCR;6+ѧx**Ę$90q'oקfQ%n;5pX2]$^q~+s"F!CyhIh~CMnOf1$#h)r~hмj5F̹k#ni<7>Tsa>s\8s&wsaY1:+r1\ut[ZM,k4w6_%aJ endstream endobj 529 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTMk0WhFG*! miʲVZCcYy#9햅ļ{3񸟤e&Oo]&C]]Mq>zwt߉Ǯ)n.pCx?nڽVgx=itO"i [\l\WM}'ԭ̚t4pXeȉeU oq yM\-CnCW_Ey}wP dZz891euB)] W-\v\]~[S!8&+Zce"'2Ɍ5I@|"B2AQhSlLء28a}ɑFq5ҍnnbfǮCG= Wܢe$g;A,:sx l=NOTƘ$0_س/vЧQ%~Zx pX2]$^qnaK??q FqMyc0=) &l(mi,3|d &\c ]͹&ӈ9w{d-tx\ \cΜekqLJs?<@>qhx .׷8wl~1V<*m"mmDa endstream endobj 530 0 obj << /Length 666 /Filter /FlateDecode >> stream xmTn0C6U@"۪V{Mi@Կyct+%13nUķR<=]tuU*Wo;зΝu-M}mS+7F?h^q~M}k $|y'BpOu u+$bTy{!y1  GҢSX< {NmmX#N;{}y[D]`Ah;P5K_;'4S}}⢅Klkީ|cSs&^s 1eΘOd~`xՌk?s׾G0N-۰o|e>ha>6h Z8sseY1:@++܊psqsoZ׺q=7÷c endstream endobj 531 0 obj << /Length 988 /Filter /FlateDecode >> stream xmVnH+Ap 6 bcW;lJ>S]WX`U쮮~pF7|XaW y;nn?=! oy?Sr4D= / $>i 5|4Pr %O~_RhPqYD$qEI]T'؟oٿN x o~&_4/͏y8$⃇ "Qdϑ/}'}x<B{JM~înz RwɶVaL yz^|5|u?v %@ !P vh#/&%`Pm(0YJp(s9HKV$ @Z1āBHEiᦓ4("ܲVT飇.@E-]ݖpUtI>Ejypxr z m#)u:f6FyY\fͱdzbuN\슶BRўLdt'|A9وOI+ȕ״%Fla)qttSTX8]9Ē+p9ÞwVp7^v%kcŇz,j,y} k_v+U1gBs9e.++si2b3G?θ菑\\F,66j46XRK^%/m.]?!J-}P[*`}򝒞;mة)4me粷zdݢGlWר=şzj{54;_5y_rr({s9> stream xmTMo0WxvB+8l[jWHL7RI;onDo3ތ?n~<&Y$ŝK_IsE77E[^N\5sߖ;7|[lzmS_*7F?h3΃;mc-bB`ew\_7oK׽;(2Z.ETz}ܟ~o9V^MVK7-\f\S}[S!pcSs|TXo1/ȡ aeuC> stream xmTMo0WxvB+8l[+ML7RI;onDo3ތ?n~<&YվI|/ŋ;t硋nn\3<:Wj\=?-wn6pGۦ|Tnʽgxté7~qzxKlqrnX7UޞMjuSAxHiQ,'wͱ 1}hW7q{UEݥ-rG*F>NNL7u]tNhWS;wE )b,#TTHy=)9>*QKr7P:MȡQ^s$LD6aȑ*s.$S56`>ƄmÁ#TL 5kd}WXssc*zRh/#? bE$L|ږ8^y>eSQc̯bV̯cNa'_OAJ195kd3EH@8ܰ%~As*=F 0`{RLPh33Y$LƹǬ oqMsȼ tx\ \cΜ-eksL ?"@>qhx ׷=l~1֍>*]!MBa endstream endobj 534 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTn0C6U@"mTt@;olvR3ތm~<&YվI|+œ;t羋<]3;Wj|{}[ mmᆂMv{Kt=c_~B?zxoBS6wBJ)X7UaMuSxHiQV,4$O;nC-bD/OCnC_n^ѻs׽9X2Z.ET~{~ʶrn_~߼h!R,6ew*ؔb%k e+Kӄ$a"1x*s.$S56P>Ƅm„A Fs 5577vرϾ+uaя6R:!,əCxg+ѧy*JcL|*m:fvuiWUꧏɩ\g%<Ϛ"sÖ0_:3x0kjhyIYx0aCnOg3$cx0<<v5O#ܵu7A 6*sZ ZcΜ-ܠeYksL ?"@>qh|tngk;dGGM@c endstream endobj 535 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTn0C6U@"mTt@;olvR3ތm~<&YվI|+œ;t羋<]3;Wj|{}[ mmᆂMv{Kt=cߚ~B?zxoBS6wBJ)X7UaMuSxHiQV,4$O;nC-bD/OCnC_n^ѻs׽9X2Z.ET~{~ʶrn_~߼h!R,6ew*ؔb%k e+Kӄ$a"1x*s.$S56P>Ƅm„A Fs 5577vرϾ+uaя6R:!,əCxg+ѧy*JcL|*m:fvuiWUꧏɩ\g%<Ϛ"sÖ0_:3x0kjhyIYx0aCnOg3$cx0<<v5O#ܵu7A 6*sZ ZcΜ-ܠeYksL ?"@>qh|tngk;dGGMc endstream endobj 489 0 obj << /Type /ObjStm /N 100 /First 922 /Length 4746 /Filter /FlateDecode >> stream xڽ\YsF~ׯc<./USSbHJl92EK E*$8tlMTfnB|gaLBai~DR 21?uB)c`M$Hx ZÃL&F'*v"a4,~K3Ɏaه{$]LI=)wEr>-}R1zE Iey*) @h+MIߦWu??>lv=[]?ܹl~S4 a:Oox/+? 0uc06^4('Ga7C3yrc$T[6_Wu ?0׫eߕ1tuYw]&gRHC7:w|fRrkmk7o>uekӄKxb9Zuw øHrT:{j8?,7;L<@k ǚ-UR|REMr%95 u<~|ea4G. '#H:Ҿ|F*2>Te[ܛOQWC. G*(S{^vZltq3]\ywCC8՞2˛c%Z fè'_?@@ofE_rބowK{~zQv觰.Gp+%=V=bwjEǒ`*WA הѠ `;HFHSfPv+>ڵ7#Qo~&ۓyTtɘLMdW: yTVof^]Cm[=/y=l::i9WwzW;Ux68|-vJ^q#wz5.6G{( h֧Go2 ,`.T}5k& '[=uPᄠ w\<~qn?m rq ᰸f?p]A M ?p(.;4a!ѻ@WoTp!D{CG>M x_>Ҡ3wi#Q|<&0%Ban3iس׵ֳTPQ +xu͚ cuGfO?۳!Q3fͷ.Jξ˯<: r(2P{] }pwn"yy䪂J %!c:yL8p_>] |_5/X?srܺO߻???e ;$u< s$@'_S8L5]LoΚOt=K{ӕ]h1\xOu ~Ml G}s9獄=u?/f>[ຍ'BOOe8Sob|rϒU{bn*3-^Kڮ&aD)s.=6,9ݠ̚IK,,*~:;xF eˆJ(Uh7l& m`x #+&URNHHtDQZìڐ jܬ(VڊgέGgGTYeHA31A}쥓\Y0p+j9]F\Jf-LƦ&P<`JyY@ZhѢ*p#Q󊱢d6v ݵ EQV0v&G$/ JS& D6X b $,"& b6T|>:;xY-ЙEA8:;8- 9Ha o#0b 2(x($%ȧ֥/JMV7|BXљY &VU,_΅0FH*1GgG&ϋrYyFTr&B 37y;VvjބBǪ/+hɳBBn+!}tvTq0L ]lQcidC F hiD[]@5̬X H6oMeRR.HOjX^bTP1Z)YUC?#<"eY(SwuzW{~(%ѾkZSg)2RK0S{;]6ُ^F`mc.%*|$Q= vƍ9V-i\7˸ACh-ޠ39ڍ̠/ho Vm=v/03AiS\vT!z(7#Moա6Xq c@ uQ;!=6\dpdžH9T҃A#C[cL} R/c\NHm ^)"}q#p 9b06}/(Bk _rC!]xA&˦F_K'FkFB@p̐N9B GGԀyXC_zGo×v ߖM`0 a>&cFX)ȜK3NF2ٌ)"*BYX:٣:X$nEl)a;d8Ϫ 騟&W56a"&.zEwD5۫ hZÐT05JWN^*л/5:WFt3/oOO_!HⶾXOra}Ț?̝9 endstream endobj 573 0 obj << /Producer (pdfTeX-1.40.24) /Author(\376\377\000S\000e\000b\000a\000s\000t\000i\000a\000n\000\040\000G\000u\000t\000s\000c\000h\000e\000\040\000;\000\040\000M\000a\000x\000\040\000H\000o\000r\000n)/Title(\376\377\000A\000u\000t\000o\000D\000o\000c)/Subject()/Creator(\376\377\000L\000a\000T\000e\000X\000\040\000w\000i\000t\000h\000\040\000h\000y\000p\000e\000r\000r\000e\000f\000\040\000p\000a\000c\000k\000a\000g\000e\000\040\000/\000\040\000G\000A\000P\000D\000o\000c)/Keywords() /CreationDate (D:19700101000000Z) /ModDate (D:19700101000000Z) /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) kpathsea version 6.3.4) >> endobj 574 0 obj << /Type /XRef /Index [0 575] /Size 575 /W [1 3 1] /Root 572 0 R /Info 573 0 R /ID [ ] /Length 1389 /Filter /FlateDecode >> stream x%7]E}oi^zs]紶aDd#YXB4`( Dq rAJCi  249νsϙI)絔jҔDty .h6NJm.mzjIǁj[m#&PNm+D0Yj[H'ΒV N]VPL:LZt0FjH+0jIgnjm P;Jm=\01jHQ[K,6Hm bBm5RjH>ji&Kie`y:äLD/DesA4g/ 8#p p9Rw.!p\c༥O4*f c!6dp?Q)bGahlR]!?O6~[0pt6P#՜O8`B=7n )pS X*T`RAⴥ=zF n r <Wqސ7k`Q0}@ 4:hXUW'b;6Ɓ@{$KFLSXݕz]YScf4:CF6}ѯ2 Z hKңuz ~Vk-=-6]`o:MFPZ*%|`$1Hu[cRApSҏ_k8N3 (yna΃ eY]SPPyF-1o9>p x ^7k} l#8>pv'[8rw8-ξƵGѮ ]; _ {ofSq(((((lю܎7 #wu=CxWg;$Rq8±;>pm8/l±!G8a wĬ碢QS:uyqk_dJ5Yִ򲢆5=~KQ{+jEVNQo귞)gGuX֘3h5wY;TpN /`o n~Vp띂Wn}ވ-F44#h֙ A3fQ0KA7`F3 fuC,/#^FxYk2euhǬ??~ endstream endobj startxref 367608 %%EOF AutoDoc-2023.06.19/doc/times.css000644 000766 000024 00000000261 14444021302 016334 0ustar00mhornstaff000000 000000 /* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { font-family: Times,Times New Roman,serif; } AutoDoc-2023.06.19/doc/toggless.css000644 000766 000024 00000001672 14444021302 017051 0ustar00mhornstaff000000 000000 /* toggless.css Frank Lübeck */ /* Using javascript we change all div.ContSect to div.ContSectOpen or div.ContSectClosed. This way the config for div.ContSect in manual.css is no longer relevant. Here we add the CSS for the new elements. */ /* This layout is based on an idea by Burkhard Höfling. */ div.ContSectClosed { text-align: left; margin-left: 1em; } div.ContSectOpen { text-align: left; margin-left: 1em; } div.ContSectOpen div.ContSSBlock { display: block; text-align: left; margin-left: 1em; } div.ContSectOpen div.ContSSBlock a { display: block; width: 100%; margin-left: 1em; } span.tocline a:hover { display: inline; background: #eeeeee; } span.ContSS a:hover { display: inline; background: #eeeeee; } span.toctoggle { font-size: 80%; display: inline-block; width: 1.2em; } span.toctoggle:hover { background-color: #aaaaaa; } AutoDoc-2023.06.19/doc/chap2.txt000644 000766 000024 00000071670 14444021275 016264 0ustar00mhornstaff000000 000000 2 AutoDoc documentation comments You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declaration. An AutoDoc comment always starts with #!. This is also the smallest possible AutoDoc command. If you want your declaration documented, just write #! at the line before the documentation. For example:  #! DeclareOperation( "AnOperation",  [ IsList ] );  This will produce a manual entry for the operation AnOperation. Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces. 2.1 Documenting declarations In the bare form above, the manual entry for AnOperation will not contain much more than the name of the operation. In order to change this, there are several commands you can put into the AutoDoc comment before the declaration. Currently, the following commands are provided: 2.1-1 @Description descr Adds the text in the following lines of the AutoDoc to the description of the declaration in the manual. Lines are until the next AutoDoc command or until the declaration is reached. 2.1-2 @Returns ret_val The string ret_val is added to the documentation, with the text Returns:  put in front of it. This should usually give a brief hint about the type or meaning of the value returned by the documented function. 2.1-3 @Arguments args The string args contains a description of the arguments the function expects, including optional parts, which are denoted by square brackets. The argument names can be separated by whitespace, commas or square brackets for the optional arguments, like grp[, elm] or xx[y[z] ]. If GAP options are used, this can be followed by a colon : and one or more assignments, like n[, r]: tries := 100. 2.1-4 @Group grpname Adds the following method to a group with the given name. See section 2.5 for more information about groups. 2.1-5 @Label label Adds label to the function as label. If this is not specified, then for declarations that involve a list of input filters (as is the case for DeclareOperation, DeclareAttribute, etc.), a default label is generated from this filter list.  #! @Label testlabel DeclareProperty( "AProperty",  IsObject );  leads to this: 2.1-6 AProperty AProperty( arg )  property Returns: true or false while  #! DeclareProperty( "AProperty",  IsObject );  leads to this: 2.1-7 AProperty AProperty( arg )  property Returns: true or false 2.1-8 @ChapterInfo chapter, section Adds the entry to the given chapter and section. Here, chapter and section are the respective titles. As an example, a full AutoDoc comment with all options could look like this:  #! @Description #! Computes the list of lists of degrees of ordinary characters #! associated to the $p$-blocks of the group $G$ #! with $p$-modular character table modtbl #! and underlying ordinary character table `ordtbl`. #! @Returns a list #! @Arguments modtbl #! @Group CharacterDegreesOfBlocks #! @Label chardegblocks #! @ChapterInfo Blocks, Attributes DeclareAttribute( "CharacterDegreesOfBlocks",  IsBrauerTable );  2.2 Other documentation comments There are also some commands which can be used in AutoDoc comments that are not associated to any declaration. This is useful for additional text in your documentation, examples, mathematical chapters, etc.. 2.2-1 @Chapter name Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their AutoDoc comment via @ChapterInfo will be added to this chapter. Also all text comments, i.e. lines that begin with #! without a command, and which do not follow after @Description, will be added to the chapter as regular text. Additionally, the chapters label will be set to Chapter_name. Example:  #! @Chapter My chapter #! This is my chapter. #! I document my stuff in it.  The @ChapterLabel label command can be used to set the label of the chapter to Chapter_label instead of Chapter_name. Additionally, the chapter will be stored as _Chapter_label.xml. The @ChapterTitle title command can be used to set a heading for the chapter that is different from name. Note that the title does not affect the label. If you use all three commands, i.e.,  #! @Chapter name #! @ChapterLabel label #! @ChapterTitle title  title is used for the headline, label for cross-referencing, and name for setting the same chapter as active chapter again. 2.2-2 @Section name Sets an active section like @Chapter sets an active chapter. The section automatically ends with the next @Section or @Chapter command.  #! @Section My first manual section #! In this section I am going to document my first method.  The @SectionLabel label command can be used to set the label of the section to Section_label instead of Chapter_chaptername_Section_name. The @SectionTitle title command can be used to set a heading for the section that is different from name. 2.2-3 @Subsection name Sets an active subsection like @Section sets an active section. The subsection automatically ends with the next @Subsection, @Section or @Chapter command. It also ends with the next documented function. Indeed, internally each function manpage is treated like a subsection.  #! @Subsection My first manual subsection #! In this subsection I am going to document my first example.  The @SubsectionLabel label command can be used to set the label of the subsection to Subsection_label instead of Chapter_chaptername_Section_sectionname_Subsection_name. The @SubsectionTitle title command can be used to set a heading for the subsection that is different from name. 2.2-4 @BeginGroup [grpname] Starts a group. All following documented declarations without an explicit @Group command are grouped together in the same group with the given name. If no name is given, then a new nameless group is generated. The effect of this command is ended when an @EndGroup command is reached. See section 2.5 for more information about groups. 2.2-5 @EndGroup Ends the current group.  #! @BeginGroup MyGroup #! DeclareAttribute( "GroupedAttribute",  IsList );  DeclareOperation( "NonGroupedOperation",  [ IsObject ] );  #! DeclareOperation( "GroupedOperation",  [ IsList, IsRubbish ] ); #! @EndGroup  2.2-6 @GroupTitle title Sets the subsection heading for the current group to title. In the absence of any @GroupTitle command, the heading will be the name of the first entry in the group. See 2.5 for more information. 2.2-7 @Level lvl Sets the current level of the documentation. All items created after this, chapters, sections, and items, are given the level lvl, until the @ResetLevel command resets the level to 0 or another level is set. See section 2.6 for more information about levels. 2.2-8 @ResetLevel Resets the current level to 0. 2.2-9 @BeginExample and @EndExample @BeginExample marks the start of an example to be put into the manual. It differs from GAPDoc's  (see 'GAPDoc: Log'), in that it expects actual code (not in a comment) interspersed with comments, to allow for examples files that can be both executed by GAP, and parsed by AutoDoc. To achieve this, GAP commands are not preceded by a comment, while output has to be preceded by an AutoDoc comment. The gap> prompt for the display in the manual is added by AutoDoc. @EndExample ends the example block. To illustrate this command, consider this input:  #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample  This results in the following output:  Example  gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120  The AutoDoc command @Example is an alias of @BeginExample. 2.2-10 @BeginExampleSession and @EndExampleSession @BeginExampleSession marks the start of an example to be put into the manual, while @EndExampleSession ends the example block. It is the direct analog of GAPDoc's  (see 'GAPDoc: Log'). To illustrate this command, consider this input:  #! @BeginExampleSession #! gap> S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) #! gap> Order(S5); #! 120 #! @EndExampleSession  This results in the following output:  Example  gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120  It inserts an example into the manual just as @Example would do, but all lines are commented and therefore not executed when the file is read. All lines that should be part of the example displayed in the manual have to start with an AutoDoc comment (#!). The comment will be removed, and, if the following character is a space, this space will also be removed. There is never more than one space removed. To ensure examples are correctly colored in the manual, there should be exactly one space between #! and the gap> prompt. The AutoDoc command @ExampleSession is an alias of @BeginExampleSession. 2.2-11 @BeginLog and @EndLog Works just like the @BeginExample command, but the example will not be tested. See the GAPDoc manual for more information. The AutoDoc command @Log is an alias of @BeginLog. 2.2-12 @BeginLogSession and @EndLogSession Works just like the @BeginExampleSession command, but the example will not be tested if manual examples are run. It is the direct analog of GAPDoc's  (see 'GAPDoc: Log'). The AutoDoc command @LogSession is an alias of @BeginLogSession. 2.2-13 @DoNotReadRestOfFile Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files.  #! This will appear in the manual  #! @DoNotReadRestOfFile  #! This will not appear in the manual.  2.2-14 @BeginChunk name, @EndChunk, and @InsertChunk name Text inside a @BeginChunk / @EndChunk part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. That chunk of text can then later on be inserted in any other place by using the @InsertChunk name command. If you do not provide an @EndChunk, the chunk ends at the end of the file.  #! @BeginChunk MyChunk #! Hello, world. #! @EndChunk  #! @InsertChunk MyChunk ## The text "Hello, world." is inserted right before this.  You can use this to define an example like this in one file:  #! @BeginChunk Example_Symmetric_Group #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample #! @EndChunk  And then later, insert the example in a different file, like this:  #! @InsertChunk Example_Symmetric_Group  2.2-15 @BeginCode name, @EndCode, and @InsertCode name Inserts the text between @BeginCode and @EndCode verbatim at the point where @InsertCode is called. This is useful to insert code excerpts directly into the manual.  #! @BeginCode Increment i := i + 1; #! @EndCode  #! @InsertCode Increment ## Code is inserted here.  2.2-16 @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly Code inserted between @BeginLatexOnly and @EndLatexOnly or after @LatexOnly is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary LaTeX-commands.  #! @BeginLatexOnly #! \include{picture.tex} #! @EndLatexOnly  #! @LatexOnly \include{picture.tex}  2.2-17 @NotLatex text, @BeginNotLatex, and @EndNotLatex Code inserted between @BeginNotLatex and @EndNotLatex or after @NotLatex is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version.  #! @BeginNotLatex #! For further information see the PDF version of this manual. #! @EndNotLatex  #! @NotLatex For further information see the PDF version of this manual.  2.3 Title page commands The following commands can be used to add the corresponding parts to the title page of the document which generated by AutoDoc if scaffolding is enabled.  @Title  @Subtitle  @Version  @TitleComment  @Author  @Date  @Address  @Abstract  @Copyright  @Acknowledgements  @Colophon Those add the following lines at the corresponding point of the title page. Please note that many of those things can be (better) extracted from the PackageInfo.g. In case you set some of those, the extracted or in scaffold defined items will be overwritten. While this is not very useful for documenting packages, they are necessary for worksheets created with AutoDocWorksheet (3.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted. 2.4 Plain text files Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.1-1), resp. are contained in one of the directories listed in autodoc.scan_dirs, are treated as AutoDoc plain text files. These work exactly like AutoDoc comments, except that lines do not need to (and in fact, should not) start with #!. 2.5 Grouping In GAPDoc, it is possible to make groups of manual items, i.e., when documenting a function, operation, etc., it is possible to group them into suitable chunks. This can be particularly useful if there are several definitions of an operation with several different argument types, all doing more or less the same to the arguments. Then their manual items can be grouped, sharing the same description and return type information. You can give a heading to the group in the manual with the @GroupTitle command; if that is not supplied, then the heading of the first manual item in the group will be used as the heading. Note that group names are globally unique throughout the whole manual. That is, groups with the same name are in fact merged into a single group, even if they were declared in different source files. Thus you can have multiple @BeginGroup / @EndGroup pairs using the same group name, in different places, and these all will refer to the same group. Moreover, this means that you can add items to a group via the @Group command in the AutoDoc comment of an arbitrary declaration, at any time. The following code  #! @BeginGroup Group1 #! @GroupTitle A family of operations  #! @Description #! First sentence. DeclareOperation( "FirstOperation", [ IsInt ] );  #! @Description #! Second sentence. DeclareOperation( "SecondOperation", [ IsInt, IsGroup ] );  #! @EndGroup  ## .. Stuff ..  #! @Description #! Third sentence. #! @Group Group1 KeyDependentOperation( "ThirdOperation", IsGroup, IsInt, "prime );  produces the following: 2.5-1 A family of operations FirstOperation( arg )  operation SecondOperation( arg1, arg2 )  operation ThirdOperation( arg1, arg2 )  operation First sentence. Second sentence. Third sentence. 2.6 Level Levels can be set to not write certain parts in the manual by default. Every entry has by default the level 0. The command @Level can be used to set the level of the following part to a higher level, for example 1, and prevent it from being printed to the manual by default. However, if one sets the level to a higher value in the autodoc option of AutoDoc, the parts will be included in the manual at the specific place.  #! This text will be printed to the manual. #! @Level 1 #! This text will be printed to the manual if created with level 1 or higher. #! @Level 2 #! This text will be printed to the manual if created with level 2 or higher. #! @ResetLevel #! This text will be printed to the manual.  2.7 Markdown-like formatting of text in AutoDoc AutoDoc has some convenient ways to insert special format into text, like math formulas and lists. The syntax for them are inspired by Markdown and LaTeX, but do not follow them strictly. Neither are all features of the Markdown language supported. The following subsections describe what is possible. 2.7-1 Lists One can create lists of items by beginning a new line with *, +, -, followed by one space. The first item starts the list. When items are longer than one line, the following lines have to be indented by at least two spaces. The list ends when a line which does not start a new item is not indented by two spaces. Of course lists can be nested. Here is an example:  #! The list starts in the next line #! * item 1 #! * item 2 #! which is a bit longer #! * and also contains a nested list #! * with two items #! * item 3 of the outer list #! This does not belong to the list anymore.  This is the output: The list starts in the next line  item 1  item 2 which is a bit longer  and also contains a nested list  with two items  item 3 of the outer list This does not belong to the list anymore. The *, -, and + are fully interchangeable and can even be used mixed, but this is not recommended. 2.7-2 Math modes One can start an inline formula with a $, and also end it with $, just like in LaTeX. This will translate into GAPDocs inline math environment. For display mode one can use $$, also like LaTeX.  #! This is an inline formula: $1+1 = 2$. #! This is a display formula: #! $$ \sum_{i=1}^n i. $$  produces the following output: This is an inline formula: 1+1 = 2. This is a display formula: \sum_{i=1}^n i.  2.7-3 Emphasize One can emphasize text by using two asterisks (**) or two underscores (__) at the beginning and the end of the text which should be emphasized. Example:  #! **This** is very important. #! This is __also important__. #! **Naturally, more than one line #! can be important.**  This produces the following output: This is very important. This is also important. Naturally, more than one line can be important. 2.7-4 Inline code One can mark inline code snippets by using backticks (`) at the beginning and the end of the text which should be marked as code. Example:  #! Call function `foobar()` at the start.  This produces the following output: Call function foobar() at the start. 2.8 Deprecated commands The following commands used to be supported, but should not generally be used anymore. They will be removed in a future version of AutoDoc. @EndSection You can simply remove any use of this, AutoDoc ends sections automatically at the start of any new section or chapter. @EndSubsection You can simply remove any use of this, AutoDoc ends subsections automatically at the start of any new subsection, section or chapter. @BeginAutoDoc and @EndAutoDoc It suffices to prepend each declaration that is meant to be appear in the manual with a minimal AutoDoc comment #!. @BeginSystem name, @EndSystem, and @InsertSystem name Please use the chunk commands from subsection 2.2-14 instead. @AutoDocPlainText and @EndAutoDocPlainText Use .autodoc files or AutoDoc comments instead. AutoDoc-2023.06.19/doc/chap3.txt000644 000766 000024 00000001451 14444021275 016253 0ustar00mhornstaff000000 000000 3 AutoDoc worksheets 3.1 Worksheets 3.1-1 AutoDocWorksheet AutoDocWorksheet( list_of_filenames: options )  function The intention of these function is to create stand-alone pdf and html files using AutoDoc without having them associated to a package. It uses the same optional records as the AutoDoc command itself, but instead of a package name there should be a filename or a list of filenames containing AutoDoc text from which the documents are created. Please see the AutoDoc command for more information about this and have a look at 1.5 for a simple worksheet example. AutoDoc-2023.06.19/doc/chapBib.html000644 000766 000024 00000004720 14444021302 016723 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - References

Goto Chapter: Top 1 2 3 4 Bib Ind

References

[LN12] Lübeck, F. and Neunhöffer, M., GAPDoc (Version 1.5.1), RWTH Aachen (2012)
( GAP package, http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html ).

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chap0.html000644 000766 000024 00000037303 14444021302 016371 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Contents
Goto Chapter: Top 1 2 3 4 Bib Ind

AutoDoc

Generate documentation from GAP source code

2023.06.19

19 June 2023

Sebastian Gutsche
Email: gutsche@mathematik.uni-siegen.de
Homepage: https://algebra.mathematik.uni-siegen.de/gutsche/
Address:
Department Mathematik
Universität Siegen
Walter-Flex-Straße 3
57072 Siegen
Germany

Max Horn
Email: mhorn@rptu.de
Homepage: https://www.quendi.de/math
Address:
Fachbereich Mathematik
RPTU Kaiserslautern-Landau
Gottlieb-Daimler-Straße 48
67663 Kaiserslautern
Germany

Abstract

AutoDoc is a GAP package whose purpose is to aid GAP package authors in creating and maintaining the documentation of their packages.

Copyright

© 2012-2022 by Sebastian Gutsche and Max Horn

This package may be distributed under the terms and conditions of the GNU Public License Version 2 or (at your option) any later version.

Acknowledgements

This documentation was prepared using the GAPDoc package [LN12].

Contents


Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chap1.txt000644 000766 000024 00000065647 14444021275 016272 0ustar00mhornstaff000000 000000 1 Getting started using AutoDoc AutoDoc is a GAP package which is meant to aid GAP package authors in creating and maintaining the documentation of their packages. In this capacity it builds upon the GAPDoc package (see https://www.gap-system.org/Packages/gapdoc.html). As such, it is not a replacement for GAPDoc, but rather complements it. In this chapter we describe how to get started using AutoDoc for your package. First, we explain in Section 1.1 how to write a new package manual from scratch. Then we show in Section 1.3 how you might benefit from AutoDoc even if you already have a complete manual written using GAPDoc. In Section 1.4, we explain how you may use AutoDoc to generate a title page and the main XML file for your manual. Finally, Section 1.5, explains what AutoDoc worksheets are and how to use them. 1.1 Creating a package manual from scratch Suppose your package is already up and running, but so far has no manual. Then you can rapidly generate a scaffold for a package manual using the AutoDoc (4.1-1) command like this, while running GAP from within your package's directory (the one containing the PackageInfo.g file):  LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) );  This first reads the PackageInfo.g file from the current directory. It extracts information about package from it (such as its name and version, see Section 1.4-1). It then creates two XML files doc/NAME_OF_YOUR_PACKAGE.xml and doc/title.xml inside the package directory. Finally, it runs GAPDoc on them to produce a nice initial PDF and HTML version of your fresh manual. To ensure that the GAP help system picks up your package manual, you should also add something like the following to your PackageInfo.g:  PackageDoc := rec(  BookName := ~.PackageName,  ArchiveURLSubset := ["doc"],  HTMLStart := "doc/chap0.html",  PDFFile := "doc/manual.pdf",  SixFile := "doc/manual.six",  LongTitle := ~.Subtitle, ),  Congratulations, your package now has a minimal working manual. Of course it will be mostly empty for now, but it already should contain some useful information, based on the data in your PackageInfo.g. This includes your package's name, version and description as well as information about its authors. And if you ever change the package data, (e.g. because your email address changed), just re-run the above command to regenerate the two main XML files with the latest information. Next of course you need to provide actual content (unfortunately, we were not yet able to automate that for you, more research on artificial intelligence is required). To add more content, you have several options: You could add further GAPDoc XML files containing extra chapters, sections and so on. Or you could use classic GAPDoc source comments. For details on either, please refer to 'GAPDoc: Distributing a Document into Several Files', as well as Section 1.3 of this manual on how to teach the AutoDoc (4.1-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 1.2). You will probably want to re-run the AutoDoc (4.1-1) command frequently, e.g. whenever you modified your documentation or your PackageInfo.g. To make this more convenient and reproducible, we recommend putting its invocation into a file makedoc.g in your package directory, with content based on the following example:  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); QUIT;  Then you can regenerate the package manual from the command line with the following command, executed from within in the package directory:  gap makedoc.g  1.2 Documenting code with AutoDoc To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an AutoDoc comment of the form #! directly in front of it. For example:  #! DeclareOperation( "ToricVariety", [ IsConvexObject ] );  This tiny change is already sufficient to ensure that the operation appears in the manual. In general, you will want to add further information about the operation, such as in the following example:  #! @Arguments conv #! @Returns a toric variety #! @Description #! Creates a toric variety out #! of the convex object conv. DeclareOperation( "ToricVariety", [ IsConvexObject ] );  For a thorough description of what you can do with AutoDoc documentation comments, please refer to chapter 2. Suppose you have not been using GAPDoc before but instead used the process described in section 1.1 to create your manual. Then the following GAP command will regenerate the manual and automatically include all newly documented functions, operations etc.:  LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true,  autodoc := true ) );  If you are not using the scaffolding feature, e.g. because you already have an existing GAPDoc based manual, then you can still use AutoDoc documentation comments. Just make sure to first edit the main XML file of your documentation, and insert the line  <#Include SYSTEM "_AutoDocMainFile.xml">  in a suitable place. This means that you can mix AutoDoc documentation comment freely with your existing documentation; you can even still make use of any existing GAPDoc documentation comments in your code. The following command should be useful for you in this case; it still scans the package code for AutoDoc documentation comments and the runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) );  1.3 Using AutoDoc in an existing GAPDoc manual Even if you already have an existing GAPDoc manual, it might be interesting for you to use AutoDoc for two purposes: First off, with AutoDoc is very convenient to regenerate your documentation. Secondly, the scaffolding feature which generates a title page with all the metadata of your package in a uniform way is very handy. The somewhat tedious process of keeping your title page in sync with your PackageInfo.g is fully automated this way (including the correct version, release data, author information and so on). There are various examples of packages using AutoDoc for only this purpose, e.g. io and orb. 1.3-1 Using AutoDoc on a complete GAPDoc manual Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your .g, .gd, and .gi files. Suppose the main XML file is named PACKAGENAME.xml and is in the /doc subdirectory of your package. Then you can rebuild your manual by executing the following two GAP commands from a GAP sessions started started in the root directory of your package:  LoadPackage( "AutoDoc" ); AutoDoc( );  In contrast, the RingsForHomalg currently uses essentially the following code in its makedoc.g file to achieve the same result  LoadPackage( "GAPDoc" ); SetGapDocLaTeXOptions( "utf8" ); bib := ParseBibFiles( "doc/RingsForHomalg.bib" ); WriteBibXMLextFile( "doc/RingsForHomalgBib.xml", bib ); list := [  "../gap/RingsForHomalg.gd",  "../gap/RingsForHomalg.gi",  "../gap/Singular.gi",  "../gap/SingularBasic.gi",  "../examples/RingConstructionsExternalGAP.g",  "../examples/RingConstructionsSingular.g",  "../examples/RingConstructionsMAGMA.g",  "../examples/RingConstructionsMacaulay2.g",  "../examples/RingConstructionsSage.g",  "../examples/RingConstructionsMaple.g",  ]; MakeGAPDocDoc( "doc", "RingsForHomalg", list, "RingsForHomalg" ); GAPDocManualLab( "RingsForHomalg" );  Note that in particular, you do not have to worry about keeping a list of your implementation files up-to-date. But there is more. AutoDoc can create .tst files from the examples in your manual to test your package. This can be achieved via  LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := true ) );  Now files PACKAGENAME01.tst, PACKAGENAME02.tst and so appear in the tst/ subdirectory of your package, and can be tested as usual using Test (Reference: Test) respectively TestDirectory (Reference: TestDirectory). 1.3-2 Setting different GAPDoc options Sometimes, the default values for the GAPDoc command used by AutoDoc may not be suitable for your manual. Suppose your main XML file is not named PACKAGENAME.xml, but rather something else, e.g. main.xml. Then you can tell AutoDoc to use this file as the main XML file via  LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( main := "main" ) ) );  As explained above, by default AutoDoc scans all .g, .gd and .gi files it can find inside of your package root directory, and in the subdirectories gap, lib, examples and examples/doc as well. If you keep source files with documentation in other directories, you can adjust the list of directories AutoDoc scans via the scan_dirs option. The following example illustrates this by instructing AutoDoc to only search in the subdirectory package_sources of the packages root directory.  LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( scan_dirs := [ "package_sources" ] ) ) );  You can also specify an explicit list of files containing documentation, which will be searched in addition to any files located within the scan directories:  LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( files := [ "path/to/some/hidden/file.gds" ] ) ) );  Giving such a file does not prevent the standard scan_dirs from being scanned for other files. Next, GAPDoc supports the documentation to be built with relative paths. This means, links to manuals of other packages or the GAP library will not be absolute, but relative from your documentation. This can be particularly useful if you want to build a release tarball or move your GAP installation around later. Suppose you are starting GAP in the root path of your package as always, and the standard call of AutoDoc (4.1-1) will then build the documentation in the doc subdirectory of your package. From this directory, the gap root directory has the relative path ../../... Then you can enable the relative paths by  LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) );  or, since ../../.. is the standard option for gap_root_relative_path, by  LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) );  1.3-3 Checklist for converting an existing GAPDoc manual to use AutoDoc Here is a checklist for authors of a package PackageName, which already has a GAPDoc based manual, who wish to use AutoDoc to build the manual from now on. We assume that the manual is currently built by reading a file makedoc.g and that the main .xml file is named manual.xml. The files PackageInfo.g, makedoc.g, doc/title.xml and doc/PackageName.xml (if it exists) will be altered by this procedure, so it may be wise to keep backup copies. You should have copies of the AutoDoc files PackageInfo.g and makedoc.g to hand when reading these instructions.  Copy AutoDoc/makedoc.g to PackageName/makedoc.g.  Edit PackageName/makedoc.g as follows.  Change the header comment to match other files in your package.  After LoadPackage("AutoDoc"); add LoadPackage("PackageName");.  In the AutoDoc record delete autodoc := true;.  In the scaffold record change the includes list to be the list of your .xml files that are contained in manual.xml.  If you do not have a bibliography you may delete the bib := "bib.xml", field in the scaffold. Otherwise, edit the file name if you have a different file. If you only have a .bib file (manual.bib or bib.xml.bib say) you should rename this file PackageName.bib.  In the LaTeXOptions record, which is in the gapdoc record, enter any LaTeX newcommands previously in manual.xml. (If there are none you may safely delete this record.) To illustrate this option, the AutoDoc file makedoc.g defines the command \bbZ by \newcommand{\bbZ}{\mathbb{Z}}, which may be used to produce the LaTeX formula f : bbZ^2 -> bbZ.  In the entities record enter any entities previously stored in manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the AutoDoc file makedoc.g defines entities for the names of packages io and PackageName.  Now edit PackageName/PackageInfo.g as follows.  Delete any PKGVERSIONDATA chunk that may be there. One reason for converting your manual to use AutoDoc is to stop using entities such as PACKAGENAMEVERSION.  Copy the AutoDoc record from AutoDoc/PackageInfo.g to the end of your file (just before the final "));".  Replace the Copyright, Abstract and Acknowledgements fields of the TitlePage record with the corresponding material from your manual.xml. (If you do not have an abstract, then delete the Abstract field, etc.) For other introductory components, such as Colophon, consult the file gap/Magic.gd.  If you are using a GitHub repository, as well as running "git add" on files makedoc.g, PackageInfo.g and doc/PackageName.bib, you should run "git rm -f" on files doc/manual.xml, and doc/title.xml. You should now be ready to run GAP and Read("makedoc.g"); in your package root directory. 1.4 Scaffolds 1.4-1 Generating a title page For most (if not all) GAP packages, the title page of the package manual lists information such as the release date, version, names and contact details of the authors, and so on. All this data is also contained in your PackageInfo.g, and whenever you make a change to that file, there is a risk that you forget to update your manual to match. And even if you don't forget it, you of course have to spend some time to adjust the manual. GAPDoc can help to a degree with this via entities. Thus, you will sometimes see code like this in PackageInfo.g files:  Version := "1.2.3", Date := "20/01/2015", ## <#GAPDoc Label="PKGVERSIONDATA"> ##  ##  ##  ## <#/GAPDoc>  However, it is still easy to forget both of these versions. And it doesn't solve the problem of updating package authors addresses. Neither of these is a big issue, of course, but there have been plenty examples in the past where people forget either of these two things, and it can be slightly embarrassing. It may even require you to make a new release just to fix the issue, which in our opinion is a sad waste of your valuable time. So instead of worrying about manually synchronising these things, you can instruct AutoDoc to generate a title page for your manual based on the information in your PackageInfo.g. The following commands do just that (in addition to building your manual), by generating a file called doc/title.xml.  LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := rec( MainPage := false ) ) );  Note that this only outputs doc/title.xml but does not touch any other files of your documentation. In particular, you need to explicitly include doc/title.xml from your main XML file. However, you can also tell AutoDoc to maintain the main XML file for you, in which case this is automatic. In fact, this is the default if you enable scaffolding; the above example command explicitly told AutoDoc not to generate a main page. 1.4-2 Generating the main XML file The following generates a main XML file for your documentation in addition to the title page. The main XML file includes the title page by default, as well as any documentation generated from AutoDoc documentation comments.  LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) );  You can instruct AutoDoc to include additional XML files by giving it a list of filenames, as in the following example:  LoadPackage( "AutoDoc" ); AutoDoc(rec(  scaffold := rec(  includes := [ "somefile.xml", "anotherfile.xml" ]  ) ));  For more information, please consult the documentation of the AutoDoc (4.1-1) function. 1.4-3 What data is used from PackageInfo.g? AutoDoc can use data from PackageInfo.g in order to generate a title page. Specifically, the following components of the package info record are taken into account: PackageName This is used to set the  element of the title page. Subtitle This is used to set the <Subtitle> element of the title page. Version This is used to set the <Version> element of the title page, with the string Version  prepended. Date This is used to set the <Date> element of the title page. Persons This is used to generate <Author> elements in the generated title page. PackageDoc This is a record (or a list of records) which is used to tell the GAP help system about the package manual. Currently AutoDoc extracts the value of the PackageDoc.BookName component and then passes that on to GAPDoc when creating the HTML, PDF and text versions of the manual. AutoDoc This is a record which can be used to control the scaffolding performed by AutoDoc, specifically to provide extra information for the title page. For example, you can set AutoDoc.TitlePage.Copyright to a string which will then be inserted on the generated title page. Using this method you can customize the following title page elements: TitleComment, Abstract, Copyright, Acknowledgements and Colophon. Note that AutoDoc.TitlePage behaves exactly the same as the scaffold.TitlePage parameter of the AutoDoc (4.1-1) function. 1.5 AutoDoc worksheets AutoDoc worksheets can be used to create HTML and PDF documents using AutoDoc syntax and possibly including GAP examples and implementations without having them associated to a package. A file for a worksheet could look like this:  #! @Title My first worksheet #! @Author Charlie Brown  #! @Chapter Some groups  #! @BeginExample S3 := SymmetricGroup( 3 );; S4 := SymmetricGroup( 4 );; #! @EndExample  Now, one can create a PDF and HTML document, like a package documentation out of it. Suppose the document above is saved as worksheet.g. Then, when GAP is started in the directory of this file, the command  AutoDocWorksheet( "worksheet.g" );  will create a subdirectory called doc of the current directory in which it will create the documentation. There are several options to configure the output of the worksheet command, which are identical to the options of the AutoDoc (4.1-1) command. It is even possible to test the examples in the worksheet using the extract_examples option of the AutoDoc (4.1-1) command. Since the worksheets do not have a PackageInfo.g to extract information, all possible tags that GAPDoc supports for the title page can be set into the document. A fully typed title page can look like this:  #! @Title My first worksheet #! @Subtitle Some small examples #! @Author Charlie Brown  #! @Version 0.1 #! @TitleComment Some worksheet #! @Date 01/01/2016 #! @Address TU Kaiserslautern #! @Abstract #! A worksheet showing some small examples about groups. #! @Copyright 2016 Charlie Brown #! @Acknowledgements Woodstock #! @Colophon Some colophon  #! @Chapter Some groups  #! @BeginExample S3 := SymmetricGroup( 3 );; S4 := SymmetricGroup( 4 );; #! @EndExample  �����������������������������������������������������������������������������������������AutoDoc-2023.06.19/doc/chap0.txt��������������������������������������������������������������������000644 �000766 �000024 �00000013164 14444021275 016254� 0����������������������������������������������������������������������������������������������������ustar�00mhorn���������������������������staff���������������������������000000 �000000 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������  AutoDoc   Generate documentation from GAP source code  2023.06.19 19 June 2023 Sebastian Gutsche Max Horn Sebastian Gutsche Email: mailto:gutsche@mathematik.uni-siegen.de Homepage: https://algebra.mathematik.uni-siegen.de/gutsche/ Address: Department Mathematik Universität Siegen Walter-Flex-Straße 3 57072 Siegen Germany Max Horn Email: mailto:mhorn@rptu.de Homepage: https://www.quendi.de/math Address: Fachbereich Mathematik RPTU Kaiserslautern-Landau Gottlieb-Daimler-Straße 48 67663 Kaiserslautern Germany ------------------------------------------------------- Abstract AutoDoc is a GAP package whose purpose is to aid GAP package authors in creating and maintaining the documentation of their packages. ------------------------------------------------------- Copyright © 2012-2022 by Sebastian Gutsche and Max Horn This package may be distributed under the terms and conditions of the GNU Public License Version 2 or (at your option) any later version. ------------------------------------------------------- Acknowledgements This documentation was prepared using the GAPDoc package [LN12]. ------------------------------------------------------- Contents (AutoDoc) 1 Getting started using AutoDoc 1.1 Creating a package manual from scratch 1.2 Documenting code with AutoDoc 1.3 Using AutoDoc in an existing GAPDoc manual 1.3-1 Using AutoDoc on a complete GAPDoc manual 1.3-2 Setting different GAPDoc options 1.3-3 Checklist for converting an existing GAPDoc manual to use AutoDoc 1.4 Scaffolds 1.4-1 Generating a title page 1.4-2 Generating the main XML file 1.4-3 What data is used from PackageInfo.g? 1.5 AutoDoc worksheets 2 AutoDoc documentation comments 2.1 Documenting declarations 2.1-1 @Description descr 2.1-2 @Returns ret_val 2.1-3 @Arguments args 2.1-4 @Group grpname 2.1-5 @Label label 2.1-6 AProperty 2.1-7 AProperty 2.1-8 @ChapterInfo chapter, section 2.2 Other documentation comments 2.2-1 @Chapter name 2.2-2 @Section name 2.2-3 @Subsection name 2.2-4 @BeginGroup [grpname] 2.2-5 @EndGroup 2.2-6 @GroupTitle title 2.2-7 @Level lvl 2.2-8 @ResetLevel 2.2-9 @BeginExample and @EndExample 2.2-10 @BeginExampleSession and @EndExampleSession 2.2-11 @BeginLog and @EndLog 2.2-12 @BeginLogSession and @EndLogSession 2.2-13 @DoNotReadRestOfFile 2.2-14 @BeginChunk name, @EndChunk, and @InsertChunk name 2.2-15 @BeginCode name, @EndCode, and @InsertCode name 2.2-16 @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly 2.2-17 @NotLatex text, @BeginNotLatex, and @EndNotLatex 2.3 Title page commands 2.4 Plain text files 2.5 Grouping 2.5-1 A family of operations 2.6 Level 2.7 Markdown-like formatting of text in AutoDoc 2.7-1 Lists 2.7-2 Math modes 2.7-3 Emphasize 2.7-4 Inline code 2.8 Deprecated commands 3 AutoDoc worksheets 3.1 Worksheets 3.1-1 AutoDocWorksheet 4 AutoDoc 4.1 The AutoDoc() function 4.1-1 AutoDoc 4.2 Examples  ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2023.06.19/doc/chap4_mj.html����������������������������������������������������������������000644 �000766 �000024 �00000053464 14444021302 017071� 0����������������������������������������������������������������������������������������������������ustar�00mhorn���������������������������staff���������������������������000000 �000000 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script> <title>GAP (AutoDoc) - Chapter 4: AutoDoc
Goto Chapter: Top 1 2 3 4 Bib Ind

4 AutoDoc

4.1 The AutoDoc() function

4.1-1 AutoDoc
‣ AutoDoc( [packageOrDirectory][,] [optrec] )( function )

Returns: nothing

This is the main function of the AutoDoc package. It can perform any combination of the following tasks:

  1. It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in GAPDoc format to be used as part of your manual: First, a file named doc/PACKAGENAME.xml (with your package's name substituted) which is used as main XML file for the package manual, i.e. this file sets the XML doctype and defines various XML entities, includes other XML files (both those generated by AutoDoc as well as additional files created by other means), tells GAPDoc to generate a table of contents and an index, and more. Secondly, it creates a file doc/title.xml containing a title page for your documentation, with information about your package (name, description, version), its authors and more, based on the data in your PackageInfo.g.

  2. It can scan your package for AutoDoc based documentation (by using AutoDoc tags and the Autodoc command. This will produce further XML files to be used as part of the package manual.

  3. It can use GAPDoc to generate PDF, text and HTML (with MathJaX enabled) documentation from the GAPDoc XML files it generated as well as additional such files provided by you. For this, it invokes MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc) to convert the XML sources, and it also instructs GAPDoc to copy supplementary files (such as CSS style files) into your doc directory (see CopyHTMLStyleFiles (GAPDoc: CopyHTMLStyleFiles)).

For more information and some examples, please refer to Chapter 1.

The parameters have the following meanings:

packageOrDirectory

The purpose of this parameter is twofold: to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. The parameter is either a string, an IsDirectory object, or omitted. If it is a string, AutoDoc interprets it as the name of a package, uses the metadata of the first package known to GAP with that name, and uses the InstallationPath specified in that metadata as the package directory. If packageOrDirectory is an IsDirectory object, this is used as package directory; if the argument is omitted, then the current directory is used. In the last two cases, the specified directory must contain a PackageInfo.g file, and AutoDoc extracts all needed metadata from that. The IsDirectory form is for example useful if you have multiple versions of the package around and want to make sure the documentation of the correct version is built.

Note that when using AutoDocWorksheet (see 3.1), there is no parameter corresponding to packageOrDirectory and so the "package directory" is always the current directory, and there is no metadata.

optrec

optrec can be a record with some additional options. The following are currently supported:

dir

This should either be a string, in which case it must be a path relative to the specified package directory, or a Directory() object. (Thus, the only way to designate an absolute directory is with a Directory() object.) This option specifies where the package documentation (e.g. the GAPDoc XML or the manual PDF, etc.) files are stored and/or will be generated.
Default value: "doc/".

scaffold

This controls whether and how to generate scaffold XML files for the package documentation.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.scaffold is missing but the package's info record in PackageInfo.g has an AutoDoc entry. In all other cases (in particular if opt.scaffold is false), scaffolding is disabled.

If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings.

If opt.scaffold is a record, it may contain the following entries.

includes

A list of XML files to be included in the body of the main XML file. If you specify this list and also are using AutoDoc to document your operations with AutoDoc comments, you can add _AutoDocMainFile.xml to this list to control at which point the documentation produced by AutoDoc is inserted. If you do not do this, it will be added after the last of your own XML files.

index

By default, the scaffold creates an index. If you do not want an index, set this to false.

appendix

This entry is similar to opt.scaffold.includes but is used to specify files to include after the main body of the manual, i.e. typically appendices.

bib

The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file doc/PACKAGENAME.bib then it is assumed that you want to use this as your bibliography.

entities

A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record "SomePackage",

             rec( SomePackage := "<Package>SomePackage</Package>",
                  RELEASEYEAR := "2015" )

then the following entity definitions are added to the XML preamble:

<!ENTITY SomePackage '<Package>SomePackage</Package>'>
             <!ENTITY RELEASEYEAR '2015'>

This allows you to write "&SomePackage;" and "&RELEASEYEAR;" in your documentation, which will be replaced by respective values specified in the entities definition.

TitlePage

A record whose entries are used to embellish the generated title page for the package manual with extra information, such as a copyright statement or acknowledgments. To this end, the names of the record components are used as XML element names, and the values of the components are outputted as content of these XML elements. For example, you could pass the following record to set a custom acknowledgements text:

             rec( Acknowledgements := "Many thanks to ..." )

For a list of valid entries in the title page, please refer to the GAPDoc manual, specifically section GAPDoc: TitlePage.

MainPage

If scaffolding is enabled, by default a main XML file is generated (this is the file which contains the XML doctype and more). If you do not want this (e.g. because you have a handwritten main XML file), but still want AutoDoc to generate a title page for you, you can set this option to false

document_class

Sets the document class of the resulting PDF. The value can either be a string which has to be the name of the new document class, a list containing this string, or a list of two strings. Then the first one has to be the document class name, the second one the option string ( contained in [ ] ) in LaTeX.

latex_header_file

Replaces the standard header from GAPDoc completely with the header in this LaTeX file. Please be careful here, and look at GAPDoc's latexheader.tex file for an example.

autodoc

This controls whether and how to generate additional XML documentation files by scanning for AutoDoc documentation comments.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.autodoc is missing but the package depends (directly) on the AutoDoc package. In all other cases (in particular if opt.autodoc is false), this feature is disabled.

If opt.autodoc is a record, it may contain the following entries.

files

A list of files (given by paths relative to the package directory) to be scanned for AutoDoc documentation comments. Usually it is more convenient to use autodoc.scan_dirs, see below.

scan_dirs

A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].

level

This defines the level of the created documentation. The default value is 0. When parts of the manual are declared with a higher value they will not be printed into the manual.

gapdoc

This controls whether and how to invoke GAPDoc to create HTML, PDF and text files from your various XML files.

The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.gapdoc is missing. In all other cases (in particular if opt.gapdoc is false), this feature is disabled.

If opt.gapdoc is a record, it may contain the following entries.

main

The name of the main XML file of the package manual. This exists primarily to support packages with existing manual which use a filename here which differs from the default. In particular, specifying this is unnecessary when using scaffolding.
Default value: PACKAGENAME.xml.

files

A list of files (given by paths relative to the package directory) to be scanned for GAPDoc documentation comments. Usually it is more convenient to use gapdoc.scan_dirs, see below.

scan_dirs

A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments.
Default value: [ ".", "gap", "lib", "examples", "examples/doc" ].

LaTeXOptions

Must be a record with entries which can be understood by SetGapDocLaTeXOptions (GAPDoc: SetGapDocLaTeXOptions). Each entry can be a string, which will be given to GAPDoc directly, or a list containing of two entries: The first one must be the string "file", the second one a filename. This file will be read and then its content is passed to GAPDoc as option with the name of the entry.

gap_root_relative_path

Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to false), references in the generated documentation referring to external documentation (such as the GAP manual) are encoded using absolute paths. This is fine as long as the documentation stays on only a single computer, but is problematic when preparing documentation that should be used on multiple computers, e.g., when creating a distribution archive of a GAP package.
Thus, if a relative path is provided via this option (or if it is set to true, in which case the relative path ../../.. is used), then AutoDoc and GAPDoc attempt to replace all absolute paths in references to GAP manuals by paths based on this relative path.

On a technical level, AutoDoc passes the relative path to the gaproot parameter of MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc)

extract_examples

Either true or a record. If set to true, then all manual examples are extracted and placed into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... and so on, with one file for each chapter. For chapters with no examples, no file is created.

As a record, the entry can have the following entries itself, to specify some options.

units

This controls how examples are grouped into files. Recognized values are "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, one file is created for each chapter, each section, each subsection or each example. For all other values only a single file is created.

On a technical level, AutoDoc passes the value to the units parameter of ExtractExamples (GAPDoc: ExtractExamples).

skip_empty_in_numbering

If set to true (the default), the generated files use filenames with strictly sequential numbering; that means that if chapter 1 (or whatever units are being used) contains no examples but chapter 2 does, then the examples for chapter 2 are put into the file tst/PACKAGENAME01.tst. If this option is set to false, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file tst/PACKAGENAME02.tst.

maketest

This option is deprecated. Please use extract_examples instead.

Either true or a record. When it is true, a simple maketest.g file is created in the main package directory, which can be used to test the examples from the manual. As a record, the entry can have the following entries itself, to specify some options.

filename

Sets the name of the test file.

commands

A list of strings, each one a command, which will be executed at the beginning of the test file.

4.2 Examples

Some basic examples for using AutoDoc were already shown in Chapter 1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/manual.css000644 000766 000024 00000015754 14444021302 016505 0ustar00mhornstaff000000 000000 /* manual.css Frank Lübeck */ /* This is the default CSS style sheet for GAPDoc HTML manuals. */ /* basic settings, fonts, sizes, colors, ... */ body { position: relative; background: #ffffff; color: #000000; width: 70%; margin: 0pt; padding: 15pt; font-family: Helvetica,Verdana,Arial,sans-serif; text-align: justify; } /* no side toc on title page, bib and index */ body.chap0 { width: 95%; } body.chapBib { width: 95%; } body.chapInd { width: 95%; } h1 { font-size: 200%; } h2 { font-size: 160%; } h3 { font-size: 160%; } h4 { font-size: 130%; } h5 { font-size: 100%; } p.foot { font-size: 60%; font-style: normal; } a:link { color: #00008e; text-decoration: none; } a:visited { color: #00008e; text-decoration: none; } a:active { color: #000000; text-decoration: none; } a:hover { background: #eeeeee; } pre { font-family: "Courier New",Courier,monospace; font-size: 100%; color:#111111; } tt,code { font-family: "Courier New",Courier,monospace; font-size: 110%; color: #000000; } var { } /* general alignment classes */ .pcenter { text-align: center; } .pleft { text-align: left; } .pright { text-align: right; } /* layout for the definitions of functions, variables, ... */ div.func { background: #e0e0e0; margin: 0pt 0pt; } /* general and special table settings */ table { border-collapse: collapse; margin-left: auto; margin-right: auto; } td, th { border-style: none; } table.func { padding: 0pt 1ex; margin-left: 1ex; margin-right: 1ex; background: transparent; /* line-height: 1.1; */ width: 100%; } table.func td.tdright { padding-right: 2ex; } /* Example elements (for old converted manuals, now in div+pre */ table.example { background: #efefef; border-style: none; border-width: 0pt; padding: 0px; width: 100% } table.example td { border-style: none; border-width: 0pt; padding: 0ex 1ex; } /* becomes ... */ div.example { background: #efefef; padding: 0ex 1ex; /* overflow-x: auto; */ overflow: auto; } /* Links to chapters in all files at top and bottom. */ /* If there are too many chapters then use 'display: none' here. */ div.chlinktop { background: #dddddd; border-style: solid; border-width: thin; margin: 2px; text-align: center; } div.chlinktop a { margin: 3px; } div.chlinktop a:hover { background: #ffffff; } div.chlinkbot { background: #dddddd; border-style: solid; border-width: thin; margin: 2px; text-align: center; /* width: 100%; */ } div.chlinkbot a { margin: 3px; } span.chlink1 { } /* and this is for the "Top", "Prev", "Next" links */ div.chlinkprevnexttop { background: #dddddd; border-style: solid; border-width: thin; text-align: center; margin: 2px; } div.chlinkprevnexttop a:hover { background: #ffffff; } div.chlinkprevnextbot { background: #dddddd; border-style: solid; border-width: thin; text-align: center; margin: 2px; } div.chlinkprevnextbot a:hover { background: #ffffff; } /* table of contents, initially don't display subsections */ div.ContSSBlock { display: none; } div.ContSSBlock br { display: none; } /* format in separate lines */ span.tocline { display: block; width: 100%; } div.ContSSBlock a { display: block; } /* this is for the main table of contents */ div.ContChap { } div.ContChap div.ContSect:hover div.ContSSBlock { display: block; position: absolute; background: #eeeeee; border-style: solid; border-width: 1px 4px 4px 1px; border-color: #666666; padding-left: 0.5ex; color: #000000; left: 20%; width: 40%; z-index: 10000; } div.ContSSBlock a:hover { background: #ffffff; } /* and here for the side menu of contents in the chapter files */ div.ChapSects { } div.ChapSects a:hover { background: #eeeeee; } div.ChapSects a:hover { display: block; width: 100%; background: #eeeeee; color: #000000; } div.ChapSects div.ContSect:hover div.ContSSBlock { display: block; position: fixed; background: #eeeeee; border-style: solid; border-width: 1px 2px 2px 1px; border-color: #666666; padding-left: 0ex; padding-right: 0.5ex; color: #000000; left: 54%; width: 25%; z-index: 10000; } div.ChapSects div.ContSect:hover div.ContSSBlock a { display: block; margin-left: 3px; } div.ChapSects div.ContSect:hover div.ContSSBlock a:hover { display: block; background: #ffffff; } div.ContSect { text-align: left; margin-left: 1em; } div.ChapSects { position: fixed; left: 75%; font-size: 90%; overflow: auto; top: 10px; bottom: 0px; } /* Table elements */ table.GAPDocTable { border-collapse: collapse; border-style: none; border-color: black; } table.GAPDocTable td, table.GAPDocTable th { padding: 3pt; border-width: thin; border-style: solid; border-color: #555555; } caption.GAPDocTable { caption-side: bottom; width: 70%; margin-top: 1em; margin-left: auto; margin-right: auto; } td.tdleft { text-align: left; } table.GAPDocTablenoborder { border-collapse: collapse; border-style: none; border-color: black; } table.GAPDocTablenoborder td, table.GAPDocTable th { padding: 3pt; border-width: 0pt; border-style: solid; border-color: #555555; } caption.GAPDocTablenoborder { caption-side: bottom; width: 70%; margin-top: 1em; margin-left: auto; margin-right: auto; } td.tdleft { text-align: left; } td.tdright { text-align: right; } td.tdcenter { text-align: center; } /* Colors and fonts can be overwritten for some types of elements. */ /* Verb elements */ pre.normal { color: #000000; } /* Func-like elements and Ref to Func-like */ code.func { color: #000000; } /* K elements */ code.keyw { color: #770000; } /* F elements */ code.file { color: #8e4510; } /* C elements */ code.code { } /* Item elements */ code.i { } /* Button elements */ strong.button { } /* Headings */ span.Heading { } /* Arg elements */ var.Arg { color: #006600; } /* Example elements, is in tables, see above */ div.Example { } /* Package elements */ strong.pkg { } /* URL-like elements */ span.URL { } /* Mark elements */ strong.Mark { } /* Ref elements */ b.Ref { } span.Ref { } /* this contains the contents page */ div.contents { } /* this contains the index page */ div.index { } /* ignore some text for non-css layout */ span.nocss { display: none; } /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000097; font-weight: normal; } span.GAPbrkprompt { color: #970000; font-weight: normal; } span.GAPinput { color: #970000; } /* Bib entries */ p.BibEntry { } span.BibKey { color: #005522; } span.BibKeyLink { } b.BibAuthor { } i.BibTitle { } i.BibBookTitle { } span.BibEditor { } span.BibJournal { } span.BibType { } span.BibPublisher { } span.BibSchool { } span.BibEdition { } span.BibVolume { } span.BibSeries { } span.BibNumber { } span.BibPages { } span.BibOrganization { } span.BibAddress { } span.BibYear { } span.BibPublisher { } span.BibNote { } span.BibHowpublished { } AutoDoc-2023.06.19/doc/chap4.txt000644 000766 000024 00000050311 14444021275 016253 0ustar00mhornstaff000000 000000 4 AutoDoc 4.1 The AutoDoc() function 4.1-1 AutoDoc AutoDoc( [packageOrDirectory][,] [optrec] )  function Returns: nothing This is the main function of the AutoDoc package. It can perform any combination of the following tasks: 1 It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in GAPDoc format to be used as part of your manual: First, a file named doc/PACKAGENAME.xml (with your package's name substituted) which is used as main XML file for the package manual, i.e. this file sets the XML doctype and defines various XML entities, includes other XML files (both those generated by AutoDoc as well as additional files created by other means), tells GAPDoc to generate a table of contents and an index, and more. Secondly, it creates a file doc/title.xml containing a title page for your documentation, with information about your package (name, description, version), its authors and more, based on the data in your PackageInfo.g. 2 It can scan your package for AutoDoc based documentation (by using AutoDoc tags and the Autodoc command. This will produce further XML files to be used as part of the package manual. 3 It can use GAPDoc to generate PDF, text and HTML (with MathJaX enabled) documentation from the GAPDoc XML files it generated as well as additional such files provided by you. For this, it invokes MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc) to convert the XML sources, and it also instructs GAPDoc to copy supplementary files (such as CSS style files) into your doc directory (see CopyHTMLStyleFiles (GAPDoc: CopyHTMLStyleFiles)). For more information and some examples, please refer to Chapter 1. The parameters have the following meanings: packageOrDirectory The purpose of this parameter is twofold: to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. The parameter is either a string, an IsDirectory object, or omitted. If it is a string, AutoDoc interprets it as the name of a package, uses the metadata of the first package known to GAP with that name, and uses the InstallationPath specified in that metadata as the package directory. If packageOrDirectory is an IsDirectory object, this is used as package directory; if the argument is omitted, then the current directory is used. In the last two cases, the specified directory must contain a PackageInfo.g file, and AutoDoc extracts all needed metadata from that. The IsDirectory form is for example useful if you have multiple versions of the package around and want to make sure the documentation of the correct version is built. Note that when using AutoDocWorksheet (see 3.1), there is no parameter corresponding to packageOrDirectory and so the package directory is always the current directory, and there is no metadata. optrec optrec can be a record with some additional options. The following are currently supported: dir This should either be a string, in which case it must be a path relative to the specified package directory, or a Directory() object. (Thus, the only way to designate an absolute directory is with a Directory() object.) This option specifies where the package documentation (e.g. the GAPDoc XML or the manual PDF, etc.) files are stored and/or will be generated. Default value: "doc/". scaffold This controls whether and how to generate scaffold XML files for the package documentation. The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.scaffold is missing but the package's info record in PackageInfo.g has an AutoDoc entry. In all other cases (in particular if opt.scaffold is false), scaffolding is disabled. If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings. If opt.scaffold is a record, it may contain the following entries. includes A list of XML files to be included in the body of the main XML file. If you specify this list and also are using AutoDoc to document your operations with AutoDoc comments, you can add _AutoDocMainFile.xml to this list to control at which point the documentation produced by AutoDoc is inserted. If you do not do this, it will be added after the last of your own XML files. index By default, the scaffold creates an index. If you do not want an index, set this to false. appendix This entry is similar to opt.scaffold.includes but is used to specify files to include after the main body of the manual, i.e. typically appendices. bib The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file doc/PACKAGENAME.bib then it is assumed that you want to use this as your bibliography. entities A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record SomePackage,    rec( SomePackage := "SomePackage",  RELEASEYEAR := "2015" )  then the following entity definitions are added to the XML preamble:   SomePackage'>    This allows you to write &SomePackage; and &RELEASEYEAR; in your documentation, which will be replaced by respective values specified in the entities definition. TitlePage A record whose entries are used to embellish the generated title page for the package manual with extra information, such as a copyright statement or acknowledgments. To this end, the names of the record components are used as XML element names, and the values of the components are outputted as content of these XML elements. For example, you could pass the following record to set a custom acknowledgements text:    rec( Acknowledgements := "Many thanks to ..." )  For a list of valid entries in the title page, please refer to the GAPDoc manual, specifically section 'GAPDoc: TitlePage'. MainPage If scaffolding is enabled, by default a main XML file is generated (this is the file which contains the XML doctype and more). If you do not want this (e.g. because you have a handwritten main XML file), but still want AutoDoc to generate a title page for you, you can set this option to false document_class Sets the document class of the resulting PDF. The value can either be a string which has to be the name of the new document class, a list containing this string, or a list of two strings. Then the first one has to be the document class name, the second one the option string ( contained in [ ] ) in LaTeX. latex_header_file Replaces the standard header from GAPDoc completely with the header in this LaTeX file. Please be careful here, and look at GAPDoc's latexheader.tex file for an example. autodoc This controls whether and how to generate additional XML documentation files by scanning for AutoDoc documentation comments. The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.autodoc is missing but the package depends (directly) on the AutoDoc package. In all other cases (in particular if opt.autodoc is false), this feature is disabled. If opt.autodoc is a record, it may contain the following entries. files A list of files (given by paths relative to the package directory) to be scanned for AutoDoc documentation comments. Usually it is more convenient to use autodoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments. Default value: [ ".", "gap", "lib", "examples", "examples/doc" ]. level This defines the level of the created documentation. The default value is 0. When parts of the manual are declared with a higher value they will not be printed into the manual. gapdoc This controls whether and how to invoke GAPDoc to create HTML, PDF and text files from your various XML files. The value should be either true, false or a record. If it is a record or true (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if opt.gapdoc is missing. In all other cases (in particular if opt.gapdoc is false), this feature is disabled. If opt.gapdoc is a record, it may contain the following entries. main The name of the main XML file of the package manual. This exists primarily to support packages with existing manual which use a filename here which differs from the default. In particular, specifying this is unnecessary when using scaffolding. Default value: PACKAGENAME.xml. files A list of files (given by paths relative to the package directory) to be scanned for GAPDoc documentation comments. Usually it is more convenient to use gapdoc.scan_dirs, see below. scan_dirs A list of subdirectories of the package directory (given as relative paths) which AutoDoc then scans for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments. Default value: [ ".", "gap", "lib", "examples", "examples/doc" ]. LaTeXOptions Must be a record with entries which can be understood by SetGapDocLaTeXOptions (GAPDoc: SetGapDocLaTeXOptions). Each entry can be a string, which will be given to GAPDoc directly, or a list containing of two entries: The first one must be the string "file", the second one a filename. This file will be read and then its content is passed to GAPDoc as option with the name of the entry. gap_root_relative_path Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to false), references in the generated documentation referring to external documentation (such as the GAP manual) are encoded using absolute paths. This is fine as long as the documentation stays on only a single computer, but is problematic when preparing documentation that should be used on multiple computers, e.g., when creating a distribution archive of a GAP package. Thus, if a relative path is provided via this option (or if it is set to true, in which case the relative path ../../.. is used), then AutoDoc and GAPDoc attempt to replace all absolute paths in references to GAP manuals by paths based on this relative path. On a technical level, AutoDoc passes the relative path to the gaproot parameter of MakeGAPDocDoc (GAPDoc: MakeGAPDocDoc) extract_examples Either true or a record. If set to true, then all manual examples are extracted and placed into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... and so on, with one file for each chapter. For chapters with no examples, no file is created. As a record, the entry can have the following entries itself, to specify some options. units This controls how examples are grouped into files. Recognized values are "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, one file is created for each chapter, each section, each subsection or each example. For all other values only a single file is created. On a technical level, AutoDoc passes the value to the units parameter of ExtractExamples (GAPDoc: ExtractExamples). skip_empty_in_numbering If set to true (the default), the generated files use filenames with strictly sequential numbering; that means that if chapter 1 (or whatever units are being used) contains no examples but chapter 2 does, then the examples for chapter 2 are put into the file tst/PACKAGENAME01.tst. If this option is set to false, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file tst/PACKAGENAME02.tst. maketest This option is deprecated. Please use extract_examples instead. Either true or a record. When it is true, a simple maketest.g file is created in the main package directory, which can be used to test the examples from the manual. As a record, the entry can have the following entries itself, to specify some options. filename Sets the name of the test file. commands A list of strings, each one a command, which will be executed at the beginning of the test file. 4.2 Examples Some basic examples for using AutoDoc were already shown in Chapter 1. AutoDoc-2023.06.19/doc/ragged.css000644 000766 000024 00000000231 14444021302 016441 0ustar00mhornstaff000000 000000 /* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { text-align: left; } AutoDoc-2023.06.19/doc/chap1.html000644 000766 000024 00000102646 14444021302 016375 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Chapter 1: Getting started using AutoDoc
Goto Chapter: Top 1 2 3 4 Bib Ind

1 Getting started using AutoDoc

AutoDoc is a GAP package which is meant to aid GAP package authors in creating and maintaining the documentation of their packages. In this capacity it builds upon the GAPDoc package (see https://www.gap-system.org/Packages/gapdoc.html). As such, it is not a replacement for GAPDoc, but rather complements it.

In this chapter we describe how to get started using AutoDoc for your package. First, we explain in Section 1.1 how to write a new package manual from scratch.

Then we show in Section 1.3 how you might benefit from AutoDoc even if you already have a complete manual written using GAPDoc.

In Section 1.4, we explain how you may use AutoDoc to generate a title page and the main XML file for your manual.

Finally, Section 1.5, explains what AutoDoc worksheets are and how to use them.

1.1 Creating a package manual from scratch

Suppose your package is already up and running, but so far has no manual. Then you can rapidly generate a "scaffold" for a package manual using the AutoDoc (4.1-1) command like this, while running GAP from within your package's directory (the one containing the PackageInfo.g file):

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true ) );

This first reads the PackageInfo.g file from the current directory. It extracts information about package from it (such as its name and version, see Section 1.4-1). It then creates two XML files doc/NAME_OF_YOUR_PACKAGE.xml and doc/title.xml inside the package directory. Finally, it runs GAPDoc on them to produce a nice initial PDF and HTML version of your fresh manual.

To ensure that the GAP help system picks up your package manual, you should also add something like the following to your PackageInfo.g:

PackageDoc := rec(
  BookName  := ~.PackageName,
  ArchiveURLSubset := ["doc"],
  HTMLStart := "doc/chap0.html",
  PDFFile   := "doc/manual.pdf",
  SixFile   := "doc/manual.six",
  LongTitle := ~.Subtitle,
),

Congratulations, your package now has a minimal working manual. Of course it will be mostly empty for now, but it already should contain some useful information, based on the data in your PackageInfo.g. This includes your package's name, version and description as well as information about its authors. And if you ever change the package data, (e.g. because your email address changed), just re-run the above command to regenerate the two main XML files with the latest information.

Next of course you need to provide actual content (unfortunately, we were not yet able to automate that for you, more research on artificial intelligence is required). To add more content, you have several options: You could add further GAPDoc XML files containing extra chapters, sections and so on. Or you could use classic GAPDoc source comments. For details on either, please refer to GAPDoc: Distributing a Document into Several Files, as well as Section 1.3 of this manual on how to teach the AutoDoc (4.1-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 1.2).

You will probably want to re-run the AutoDoc (4.1-1) command frequently, e.g. whenever you modified your documentation or your PackageInfo.g. To make this more convenient and reproducible, we recommend putting its invocation into a file makedoc.g in your package directory, with content based on the following example:

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) );
QUIT;

Then you can regenerate the package manual from the command line with the following command, executed from within in the package directory:

gap makedoc.g

1.2 Documenting code with AutoDoc

To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an AutoDoc comment of the form #! directly in front of it. For example:

#!
DeclareOperation( "ToricVariety", [ IsConvexObject ] );

This tiny change is already sufficient to ensure that the operation appears in the manual. In general, you will want to add further information about the operation, such as in the following example:

#! @Arguments conv
#! @Returns a toric variety
#! @Description
#!  Creates a toric variety out
#!  of the convex object <A>conv</A>.
DeclareOperation( "ToricVariety", [ IsConvexObject ] );

For a thorough description of what you can do with AutoDoc documentation comments, please refer to chapter 2.

Suppose you have not been using GAPDoc before but instead used the process described in section 1.1 to create your manual. Then the following GAP command will regenerate the manual and automatically include all newly documented functions, operations etc.:

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true,
              autodoc := true ) );

If you are not using the scaffolding feature, e.g. because you already have an existing GAPDoc based manual, then you can still use AutoDoc documentation comments. Just make sure to first edit the main XML file of your documentation, and insert the line

<#Include SYSTEM "_AutoDocMainFile.xml">

in a suitable place. This means that you can mix AutoDoc documentation comment freely with your existing documentation; you can even still make use of any existing GAPDoc documentation comments in your code. The following command should be useful for you in this case; it still scans the package code for AutoDoc documentation comments and the runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) );

1.3 Using AutoDoc in an existing GAPDoc manual

Even if you already have an existing GAPDoc manual, it might be interesting for you to use AutoDoc for two purposes:

First off, with AutoDoc is very convenient to regenerate your documentation.

Secondly, the scaffolding feature which generates a title page with all the metadata of your package in a uniform way is very handy. The somewhat tedious process of keeping your title page in sync with your PackageInfo.g is fully automated this way (including the correct version, release data, author information and so on).

There are various examples of packages using AutoDoc for only this purpose, e.g. io and orb.

1.3-1 Using AutoDoc on a complete GAPDoc manual

Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your .g, .gd, and .gi files. Suppose the main XML file is named PACKAGENAME.xml and is in the /doc subdirectory of your package. Then you can rebuild your manual by executing the following two GAP commands from a GAP sessions started started in the root directory of your package:

LoadPackage( "AutoDoc" );
AutoDoc( );

In contrast, the RingsForHomalg currently uses essentially the following code in its makedoc.g file to achieve the same result

LoadPackage( "GAPDoc" );
SetGapDocLaTeXOptions( "utf8" );
bib := ParseBibFiles( "doc/RingsForHomalg.bib" );
WriteBibXMLextFile( "doc/RingsForHomalgBib.xml", bib );
list := [
         "../gap/RingsForHomalg.gd",
         "../gap/RingsForHomalg.gi",
         "../gap/Singular.gi",
         "../gap/SingularBasic.gi",
         "../examples/RingConstructionsExternalGAP.g",
         "../examples/RingConstructionsSingular.g",
         "../examples/RingConstructionsMAGMA.g",
         "../examples/RingConstructionsMacaulay2.g",
         "../examples/RingConstructionsSage.g",
         "../examples/RingConstructionsMaple.g",
         ];
MakeGAPDocDoc( "doc", "RingsForHomalg", list, "RingsForHomalg" );
GAPDocManualLab( "RingsForHomalg" );

Note that in particular, you do not have to worry about keeping a list of your implementation files up-to-date.

But there is more. AutoDoc can create .tst files from the examples in your manual to test your package. This can be achieved via

LoadPackage( "AutoDoc" );
AutoDoc( rec( extract_examples := true ) );

Now files PACKAGENAME01.tst, PACKAGENAME02.tst and so appear in the tst/ subdirectory of your package, and can be tested as usual using Test (Reference: Test) respectively TestDirectory (Reference: TestDirectory).

1.3-2 Setting different GAPDoc options

Sometimes, the default values for the GAPDoc command used by AutoDoc may not be suitable for your manual.

Suppose your main XML file is not named PACKAGENAME.xml, but rather something else, e.g. main.xml. Then you can tell AutoDoc to use this file as the main XML file via

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( main := "main" ) ) );

As explained above, by default AutoDoc scans all .g, .gd and .gi files it can find inside of your package root directory, and in the subdirectories gap, lib, examples and examples/doc as well. If you keep source files with documentation in other directories, you can adjust the list of directories AutoDoc scans via the scan_dirs option. The following example illustrates this by instructing AutoDoc to only search in the subdirectory package_sources of the packages root directory.

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( scan_dirs := [ "package_sources" ] ) ) );

You can also specify an explicit list of files containing documentation, which will be searched in addition to any files located within the scan directories:

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( files := [ "path/to/some/hidden/file.gds" ] ) ) );

Giving such a file does not prevent the standard scan_dirs from being scanned for other files.

Next, GAPDoc supports the documentation to be built with relative paths. This means, links to manuals of other packages or the GAP library will not be absolute, but relative from your documentation. This can be particularly useful if you want to build a release tarball or move your GAP installation around later. Suppose you are starting GAP in the root path of your package as always, and the standard call of AutoDoc (4.1-1) will then build the documentation in the doc subdirectory of your package. From this directory, the gap root directory has the relative path ../../... Then you can enable the relative paths by

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) );

or, since ../../.. is the standard option for gap_root_relative_path, by

LoadPackage( "AutoDoc" );
AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) );

1.3-3 Checklist for converting an existing GAPDoc manual to use AutoDoc

Here is a checklist for authors of a package PackageName, which already has a GAPDoc based manual, who wish to use AutoDoc to build the manual from now on. We assume that the manual is currently built by reading a file makedoc.g and that the main .xml file is named manual.xml.

The files PackageInfo.g, makedoc.g, doc/title.xml and doc/PackageName.xml (if it exists) will be altered by this procedure, so it may be wise to keep backup copies.

You should have copies of the AutoDoc files PackageInfo.g and makedoc.g to hand when reading these instructions.

  • Copy AutoDoc/makedoc.g to PackageName/makedoc.g.

  • Edit PackageName/makedoc.g as follows.

    • Change the header comment to match other files in your package.

    • After LoadPackage("AutoDoc"); add LoadPackage("PackageName");.

    • In the AutoDoc record delete autodoc := true;.

    • In the scaffold record change the includes list to be the list of your .xml files that are contained in manual.xml.

    • If you do not have a bibliography you may delete the bib := "bib.xml", field in the scaffold. Otherwise, edit the file name if you have a different file. If you only have a .bib file (manual.bib or bib.xml.bib say) you should rename this file PackageName.bib.

    • In the LaTeXOptions record, which is in the gapdoc record, enter any LaTeX newcommands previously in manual.xml. (If there are none you may safely delete this record.) To illustrate this option, the AutoDoc file makedoc.g defines the command \bbZ by \newcommand{\bbZ}{\mathbb{Z}}, which may be used to produce the LaTeX formula f : bbZ^2 -> bbZ.

    • In the entities record enter any entities previously stored in manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the AutoDoc file makedoc.g defines entities for the names of packages io and PackageName.

  • Now edit PackageName/PackageInfo.g as follows.

    • Delete any PKGVERSIONDATA chunk that may be there. One reason for converting your manual to use AutoDoc is to stop using entities such as PACKAGENAMEVERSION.

    • Copy the AutoDoc record from AutoDoc/PackageInfo.g to the end of your file (just before the final "));".

    • Replace the Copyright, Abstract and Acknowledgements fields of the TitlePage record with the corresponding material from your manual.xml. (If you do not have an abstract, then delete the Abstract field, etc.) For other introductory components, such as Colophon, consult the file gap/Magic.gd.

  • If you are using a GitHub repository, as well as running "git add" on files makedoc.g, PackageInfo.g and doc/PackageName.bib, you should run "git rm -f" on files doc/manual.xml, and doc/title.xml.

You should now be ready to run GAP and Read("makedoc.g"); in your package root directory.

1.4 Scaffolds

1.4-1 Generating a title page

For most (if not all) GAP packages, the title page of the package manual lists information such as the release date, version, names and contact details of the authors, and so on. All this data is also contained in your PackageInfo.g, and whenever you make a change to that file, there is a risk that you forget to update your manual to match. And even if you don't forget it, you of course have to spend some time to adjust the manual. GAPDoc can help to a degree with this via entities. Thus, you will sometimes see code like this in PackageInfo.g files:

Version        := "1.2.3",
Date           := "20/01/2015",
##  <#GAPDoc Label="PKGVERSIONDATA">
##  <!ENTITY VERSION "1.2.3">
##  <!ENTITY RELEASEDATE "20 January 2015">
##  <!ENTITY RELEASEYEAR "2015">
##  <#/GAPDoc>

However, it is still easy to forget both of these versions. And it doesn't solve the problem of updating package authors addresses. Neither of these is a big issue, of course, but there have been plenty examples in the past where people forget either of these two things, and it can be slightly embarrassing. It may even require you to make a new release just to fix the issue, which in our opinion is a sad waste of your valuable time.

So instead of worrying about manually synchronising these things, you can instruct AutoDoc to generate a title page for your manual based on the information in your PackageInfo.g. The following commands do just that (in addition to building your manual), by generating a file called doc/title.xml.

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := rec( MainPage := false ) ) );

Note that this only outputs doc/title.xml but does not touch any other files of your documentation. In particular, you need to explicitly include doc/title.xml from your main XML file.

However, you can also tell AutoDoc to maintain the main XML file for you, in which case this is automatic. In fact, this is the default if you enable scaffolding; the above example command explicitly told AutoDoc not to generate a main page.

1.4-2 Generating the main XML file

The following generates a main XML file for your documentation in addition to the title page. The main XML file includes the title page by default, as well as any documentation generated from AutoDoc documentation comments.

LoadPackage( "AutoDoc" );
AutoDoc( rec( scaffold := true ) );

You can instruct AutoDoc to include additional XML files by giving it a list of filenames, as in the following example:

LoadPackage( "AutoDoc" );
AutoDoc(rec(
    scaffold := rec(
        includes := [ "somefile.xml", "anotherfile.xml" ]
    )
));

For more information, please consult the documentation of the AutoDoc (4.1-1) function.

1.4-3 What data is used from PackageInfo.g?

AutoDoc can use data from PackageInfo.g in order to generate a title page. Specifically, the following components of the package info record are taken into account:

PackageName

This is used to set the <Title> element of the title page.

Subtitle

This is used to set the <Subtitle> element of the title page.

Version

This is used to set the <Version> element of the title page, with the string "Version " prepended.

Date

This is used to set the <Date> element of the title page.

Persons

This is used to generate <Author> elements in the generated title page.

PackageDoc

This is a record (or a list of records) which is used to tell the GAP help system about the package manual. Currently AutoDoc extracts the value of the PackageDoc.BookName component and then passes that on to GAPDoc when creating the HTML, PDF and text versions of the manual.

AutoDoc

This is a record which can be used to control the scaffolding performed by AutoDoc, specifically to provide extra information for the title page. For example, you can set AutoDoc.TitlePage.Copyright to a string which will then be inserted on the generated title page. Using this method you can customize the following title page elements: TitleComment, Abstract, Copyright, Acknowledgements and Colophon.

Note that AutoDoc.TitlePage behaves exactly the same as the scaffold.TitlePage parameter of the AutoDoc (4.1-1) function.

1.5 AutoDoc worksheets

AutoDoc worksheets can be used to create HTML and PDF documents using AutoDoc syntax and possibly including GAP examples and implementations without having them associated to a package. A file for a worksheet could look like this:

#! @Title My first worksheet
#! @Author Charlie Brown

#! @Chapter Some groups

#! @BeginExample
S3 := SymmetricGroup( 3 );;
S4 := SymmetricGroup( 4 );;
#! @EndExample

Now, one can create a PDF and HTML document, like a package documentation out of it. Suppose the document above is saved as worksheet.g. Then, when GAP is started in the directory of this file, the command

AutoDocWorksheet( "worksheet.g" );

will create a subdirectory called doc of the current directory in which it will create the documentation. There are several options to configure the output of the worksheet command, which are identical to the options of the AutoDoc (4.1-1) command. It is even possible to test the examples in the worksheet using the extract_examples option of the AutoDoc (4.1-1) command.

Since the worksheets do not have a PackageInfo.g to extract information, all possible tags that GAPDoc supports for the title page can be set into the document. A fully typed title page can look like this:

#! @Title My first worksheet
#! @Subtitle Some small examples
#! @Author Charlie Brown

#! @Version 0.1
#! @TitleComment Some worksheet
#! @Date 01/01/2016
#! @Address TU Kaiserslautern
#! @Abstract
#!  A worksheet showing some small examples about groups.
#! @Copyright 2016 Charlie Brown
#! @Acknowledgements Woodstock
#! @Colophon Some colophon

#! @Chapter Some groups

#! @BeginExample
S3 := SymmetricGroup( 3 );;
S4 := SymmetricGroup( 4 );;
#! @EndExample
Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/toggless.js000644 000766 000024 00000004205 14444021302 016670 0ustar00mhornstaff000000 000000 /* toggless.js Frank Lübeck */ /* this file contains two functions: mergeSideTOCHooks: this changes div.ContSect elements to the class ContSectClosed and includes a hook to toggle between ContSectClosed and ContSectOpen. openclosetoc: this function does the toggling, the rest is done by CSS */ closedTOCMarker = "▶ "; openTOCMarker = "▼ "; noTOCMarker = " "; /* merge hooks into side toc for opening/closing subsections with openclosetoc */ function mergeSideTOCHooks() { var hlist = document.getElementsByTagName("div"); for (var i = 0; i < hlist.length; i++) { if (hlist[i].className == "ContSect") { var chlds = hlist[i].childNodes; var el = document.createElement("span"); var oncl = document.createAttribute("class"); oncl.nodeValue = "toctoggle"; el.setAttributeNode(oncl); var cont; if (chlds.length > 2) { var oncl = document.createAttribute("onclick"); oncl.nodeValue = "openclosetoc(event)"; el.setAttributeNode(oncl); cont = document.createTextNode(closedTOCMarker); } else { cont = document.createTextNode(noTOCMarker); } el.appendChild(cont); hlist[i].firstChild.insertBefore(el, hlist[i].firstChild.firstChild); hlist[i].className = "ContSectClosed"; } } } function openclosetoc (event) { /* first two steps to make it work in most browsers */ var evt=window.event || event; if (!evt.target) evt.target=evt.srcElement; var markClosed = document.createTextNode(closedTOCMarker); var markOpen = document.createTextNode(openTOCMarker); var par = evt.target.parentNode.parentNode; if (par.className == "ContSectOpen") { par.className = "ContSectClosed"; evt.target.replaceChild(markClosed, evt.target.firstChild); } else if (par.className == "ContSectClosed") { par.className = "ContSectOpen"; evt.target.replaceChild(markOpen, evt.target.firstChild); } } /* adjust jscontent which is called onload */ jscontentfuncs.push(mergeSideTOCHooks); AutoDoc-2023.06.19/doc/Tutorials.xml000644 000766 000024 00000056652 14444021247 017240 0ustar00mhornstaff000000 000000 Getting started using &AutoDoc; &AutoDoc; is a &GAP; package which is meant to aid &GAP; package authors in creating and maintaining the documentation of their packages. In this capacity it builds upon the &GAPDoc; package (see https://www.gap-system.org/Packages/gapdoc.html). As such, it is not a replacement for &GAPDoc;, but rather complements it.

In this chapter we describe how to get started using &AutoDoc; for your package. First, we explain in Section how to write a new package manual from scratch.

Then we show in Section how you might benefit from &AutoDoc; even if you already have a complete manual written using &GAPDoc;.

In Section , we explain how you may use &AutoDoc; to generate a title page and the main XML file for your manual.

Finally, Section , explains what &AutoDoc; worksheets are and how to use them.

Creating a package manual from scratch Suppose your package is already up and running, but so far has no manual. Then you can rapidly generate a scaffold for a package manual using the command like this, while running &GAP; from within your package's directory (the one containing the PackageInfo.g file): LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); This first reads the PackageInfo.g file from the current directory. It extracts information about package from it (such as its name and version, see Section ). It then creates two XML files doc/NAME_OF_YOUR_PACKAGE.xml and doc/title.xml inside the package directory. Finally, it runs &GAPDoc; on them to produce a nice initial PDF and HTML version of your fresh manual.

To ensure that the &GAP; help system picks up your package manual, you should also add something like the following to your PackageInfo.g:

PackageDoc := rec( BookName := ~.PackageName, ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := ~.Subtitle, ), Congratulations, your package now has a minimal working manual. Of course it will be mostly empty for now, but it already should contain some useful information, based on the data in your PackageInfo.g. This includes your package's name, version and description as well as information about its authors. And if you ever change the package data, (e.g. because your email address changed), just re-run the above command to regenerate the two main XML files with the latest information.

Next of course you need to provide actual content (unfortunately, we were not yet able to automate that for you, more research on artificial intelligence is required). To add more content, you have several options: You could add further &GAPDoc; XML files containing extra chapters, sections and so on. Or you could use classic &GAPDoc; source comments. For details on either, please refer to , as well as Section of this manual on how to teach the command to include this extra documentation. Or you could use the special documentation facilities &AutoDoc; provides (see Section ).

You will probably want to re-run the command frequently, e.g. whenever you modified your documentation or your PackageInfo.g. To make this more convenient and reproducible, we recommend putting its invocation into a file makedoc.g in your package makedoc.g directory, with content based on the following example:

LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); QUIT; Then you can regenerate the package manual from the command line with the following command, executed from within in the package directory: gap makedoc.g
Documenting code with &AutoDoc; To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an &AutoDoc; comment of the form #! directly in front of it. For example: #! DeclareOperation( "ToricVariety", [ IsConvexObject ] ); This tiny change is already sufficient to ensure that the operation appears in the manual. In general, you will want to add further information about the operation, such as in the following example: conv. DeclareOperation( "ToricVariety", [ IsConvexObject ] ); ]]> For a thorough description of what you can do with &AutoDoc; documentation comments, please refer to chapter .

Suppose you have not been using &GAPDoc; before but instead used the process described in section to create your manual. Then the following &GAP; command will regenerate the manual and automatically include all newly documented functions, operations etc.:

LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true, autodoc := true ) ); If you are not using the scaffolding feature, e.g. because you already have an existing &GAPDoc; based manual, then you can still use &AutoDoc; documentation comments. Just make sure to first edit the main XML file of your documentation, and insert the line <#Include SYSTEM "_AutoDocMainFile.xml"> in a suitable place. This means that you can mix &AutoDoc; documentation comment freely with your existing documentation; you can even still make use of any existing &GAPDoc; documentation comments in your code. The following command should be useful for you in this case; it still scans the package code for &AutoDoc; documentation comments and the runs &GAPDoc; to produce HTML and PDF output, but does not touch your documentation XML files otherwise. LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) );
Using &AutoDoc; in an existing &GAPDoc; manual Even if you already have an existing &GAPDoc; manual, it might be interesting for you to use &AutoDoc; for two purposes:

First off, with &AutoDoc; is very convenient to regenerate your documentation.

Secondly, the scaffolding feature which generates a title page with all the metadata of your package in a uniform way is very handy. The somewhat tedious process of keeping your title page in sync with your PackageInfo.g is fully automated this way (including the correct version, release data, author information and so on).

There are various examples of packages using &AutoDoc; for only this purpose, e.g. &io; and orb.

Using &AutoDoc; on a complete &GAPDoc; manual Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your .g, .gd, and .gi files. Suppose the main XML file is named PACKAGENAME.xml and is in the /doc subdirectory of your package. Then you can rebuild your manual by executing the following two &GAP; commands from a &GAP; sessions started started in the root directory of your package:

LoadPackage( "AutoDoc" ); AutoDoc( ); In contrast, the RingsForHomalg currently uses essentially the following code in its makedoc.g file to achieve the same result LoadPackage( "GAPDoc" ); SetGapDocLaTeXOptions( "utf8" ); bib := ParseBibFiles( "doc/RingsForHomalg.bib" ); WriteBibXMLextFile( "doc/RingsForHomalgBib.xml", bib ); list := [ "../gap/RingsForHomalg.gd", "../gap/RingsForHomalg.gi", "../gap/Singular.gi", "../gap/SingularBasic.gi", "../examples/RingConstructionsExternalGAP.g", "../examples/RingConstructionsSingular.g", "../examples/RingConstructionsMAGMA.g", "../examples/RingConstructionsMacaulay2.g", "../examples/RingConstructionsSage.g", "../examples/RingConstructionsMaple.g", ]; MakeGAPDocDoc( "doc", "RingsForHomalg", list, "RingsForHomalg" ); GAPDocManualLab( "RingsForHomalg" ); Note that in particular, you do not have to worry about keeping a list of your implementation files up-to-date.

But there is more. &AutoDoc; can create .tst files from the examples in your manual to test your package. This can be achieved via

LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := true ) ); Now files PACKAGENAME01.tst, PACKAGENAME02.tst and so appear in the tst/ subdirectory of your package, and can be tested as usual using respectively . Setting different &GAPDoc; options Sometimes, the default values for the &GAPDoc; command used by &AutoDoc; may not be suitable for your manual.

Suppose your main XML file is not named PACKAGENAME.xml, but rather something else, e.g. main.xml. Then you can tell &AutoDoc; to use this file as the main XML file via

LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( main := "main" ) ) );

As explained above, by default &AutoDoc; scans all .g, .gd and .gi files it can find inside of your package root directory, and in the subdirectories gap, lib, examples and examples/doc as well. If you keep source files with documentation in other directories, you can adjust the list of directories AutoDoc scans via the scan_dirs option. The following example illustrates this by instructing &AutoDoc; to only search in the subdirectory package_sources of the packages root directory.

LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( scan_dirs := [ "package_sources" ] ) ) ); You can also specify an explicit list of files containing documentation, which will be searched in addition to any files located within the scan directories: LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( files := [ "path/to/some/hidden/file.gds" ] ) ) ); Giving such a file does not prevent the standard scan_dirs from being scanned for other files.

Next, &GAPDoc; supports the documentation to be built with relative paths. This means, links to manuals of other packages or the &GAP; library will not be absolute, but relative from your documentation. This can be particularly useful if you want to build a release tarball or move your &GAP; installation around later. Suppose you are starting &GAP; in the root path of your package as always, and the standard call of will then build the documentation in the doc subdirectory of your package. From this directory, the gap root directory has the relative path ../../... Then you can enable the relative paths by

LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) ); or, since ../../.. is the standard option for gap_root_relative_path, by LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) );
Checklist for converting an existing &GAPDoc; manual to use &AutoDoc; Here is a checklist for authors of a package &PackageName;, which already has a &GAPDoc; based manual, who wish to use &AutoDoc; to build the manual from now on. We assume that the manual is currently built by reading a file makedoc.g and that the main .xml file is named manual.xml.

The files PackageInfo.g, makedoc.g, doc/title.xml and doc/PackageName.xml (if it exists) will be altered by this procedure, so it may be wise to keep backup copies.

You should have copies of the &AutoDoc; files PackageInfo.g and makedoc.g to hand when reading these instructions.

Copy AutoDoc/makedoc.g to PackageName/makedoc.g. Edit PackageName/makedoc.g as follows. Change the header comment to match other files in your package. After LoadPackage("AutoDoc"); add LoadPackage("PackageName");. In the AutoDoc record delete autodoc := true;. In the scaffold record change the includes list to be the list of your .xml files that are contained in manual.xml. If you do not have a bibliography you may delete the bib := "bib.xml", field in the scaffold. Otherwise, edit the file name if you have a different file. If you only have a .bib file (manual.bib or bib.xml.bib say) you should rename this file PackageName.bib. In the LaTeXOptions record, which is in the gapdoc record, enter any &LaTeX; newcommands previously in manual.xml. (If there are none you may safely delete this record.) To illustrate this option, the &AutoDoc; file makedoc.g defines the command \bbZ by \newcommand{\bbZ}{\mathbb{Z}}, which may be used to produce the &LaTeX; formula f : \bbZ^2 \to \bbZ. In the entities record enter any entities previously stored in manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the &AutoDoc; file makedoc.g defines entities for the names of packages &io; and &PackageName;. Now edit PackageName/PackageInfo.g as follows. Delete any PKGVERSIONDATA chunk that may be there. One reason for converting your manual to use &AutoDoc; is to stop using entities such as PACKAGENAMEVERSION. Copy the AutoDoc record from AutoDoc/PackageInfo.g to the end of your file (just before the final "));". Replace the Copyright, Abstract and Acknowledgements fields of the TitlePage record with the corresponding material from your manual.xml. (If you do not have an abstract, then delete the Abstract field, etc.) For other introductory components, such as Colophon, consult the file gap/Magic.gd. If you are using a GitHub repository, as well as running "git add" on files makedoc.g, PackageInfo.g and doc/PackageName.bib, you should run "git rm -f" on files doc/manual.xml, and doc/title.xml. You should now be ready to run &GAP; and Read("makedoc.g"); in your package root directory.

Scaffolds Generating a title page For most (if not all) &GAP; packages, the title page of the package manual lists information such as the release date, version, names and contact details of the authors, and so on. All this data is also contained in your PackageInfo.g, and whenever you make a change to that file, there is a risk that you forget to update your manual to match. And even if you don't forget it, you of course have to spend some time to adjust the manual. &GAPDoc; can help to a degree with this via entities. Thus, you will sometimes see code like this in PackageInfo.g files: ## ## ## ## <#/GAPDoc> ]]> However, it is still easy to forget both of these versions. And it doesn't solve the problem of updating package authors addresses. Neither of these is a big issue, of course, but there have been plenty examples in the past where people forget either of these two things, and it can be slightly embarrassing. It may even require you to make a new release just to fix the issue, which in our opinion is a sad waste of your valuable time.

So instead of worrying about manually synchronising these things, you can instruct &AutoDoc; to generate a title page for your manual based on the information in your PackageInfo.g. The following commands do just that (in addition to building your manual), by generating a file called doc/title.xml.

LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := rec( MainPage := false ) ) ); Note that this only outputs doc/title.xml but does not touch any other files of your documentation. In particular, you need to explicitly include doc/title.xml from your main XML file.

However, you can also tell &AutoDoc; to maintain the main XML file for you, in which case this is automatic. In fact, this is the default if you enable scaffolding; the above example command explicitly told &AutoDoc; not to generate a main page. Generating the main XML file The following generates a main XML file for your documentation in addition to the title page. The main XML file includes the title page by default, as well as any documentation generated from &AutoDoc; documentation comments.

LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); You can instruct &AutoDoc; to include additional XML files by giving it a list of filenames, as in the following example: LoadPackage( "AutoDoc" ); AutoDoc(rec( scaffold := rec( includes := [ "somefile.xml", "anotherfile.xml" ] ) )); For more information, please consult the documentation of the function.
What data is used from PackageInfo.g? &AutoDoc; can use data from PackageInfo.g in order to generate a title page. Specifically, the following components of the package info record are taken into account: PackageName This is used to set the <Title> element of the title page. Subtitle This is used to set the <Subtitle> element of the title page. Version This is used to set the <Version> element of the title page, with the string Version prepended. Date This is used to set the <Date> element of the title page. Persons This is used to generate <Author> elements in the generated title page. PackageDoc This is a record (or a list of records) which is used to tell the &GAP; help system about the package manual. Currently &AutoDoc; extracts the value of the PackageDoc.BookName component and then passes that on to &GAPDoc; when creating the HTML, PDF and text versions of the manual. AutoDoc This is a record which can be used to control the scaffolding performed by &AutoDoc;, specifically to provide extra information for the title page. For example, you can set AutoDoc.TitlePage.Copyright to a string which will then be inserted on the generated title page. Using this method you can customize the following title page elements: TitleComment, Abstract, Copyright, Acknowledgements and Colophon.

Note that AutoDoc.TitlePage behaves exactly the same as the scaffold.TitlePage parameter of the function.

AutoDoc worksheets &AutoDoc; worksheets can be used to create HTML and PDF documents using AutoDoc syntax and possibly including &GAP; examples and implementations without having them associated to a package. A file for a worksheet could look like this: #! @Title My first worksheet #! @Author Charlie Brown #! @Chapter Some groups #! @BeginExample S3 := SymmetricGroup( 3 );; S4 := SymmetricGroup( 4 );; #! @EndExample Now, one can create a PDF and HTML document, like a package documentation out of it. Suppose the document above is saved as worksheet.g. Then, when &GAP; is started in the directory of this file, the command AutoDocWorksheet( "worksheet.g" ); will create a subdirectory called doc of the current directory in which it will create the documentation. There are several options to configure the output of the worksheet command, which are identical to the options of the command. It is even possible to test the examples in the worksheet using the extract_examples option of the command.

Since the worksheets do not have a PackageInfo.g to extract information, all possible tags that &GAPDoc; supports for the title page can be set into the document. A fully typed title page can look like this:

#! @Title My first worksheet #! @Subtitle Some small examples #! @Author Charlie Brown #! @Version 0.1 #! @TitleComment Some worksheet #! @Date 01/01/2016 #! @Address TU Kaiserslautern #! @Abstract #! A worksheet showing some small examples about groups. #! @Copyright 2016 Charlie Brown #! @Acknowledgements Woodstock #! @Colophon Some colophon #! @Chapter Some groups #! @BeginExample S3 := SymmetricGroup( 3 );; S4 := SymmetricGroup( 4 );; #! @EndExample
AutoDoc-2023.06.19/doc/chapInd_mj.html000644 000766 000024 00000017170 14444021302 017432 0ustar00mhornstaff000000 000000 GAP (AutoDoc) - Index
Goto Chapter: Top 1 2 3 4 Bib Ind

Index

@Arguments args 2.1-3
@BeginChunk name 2.2-14
@BeginCode name 2.2-15
@BeginExample 2.2-9
@BeginExampleSession 2.2-10
@BeginGroup 2.2-4
@BeginLatexOnly 2.2-16
@BeginLog 2.2-11
@BeginLogSession 2.2-12
@BeginNotLatex 2.2-17
@Chapter 2.2-1
@ChapterInfo 2.1-8
@ChapterLabel 2.2-1
@ChapterTitle 2.2-1
@Description descr 2.1-1
@DoNotReadRestOfFile 2.2-13
@InsertChunk name 2.2-14
@EndChunk 2.2-14
@EndCode 2.2-15
@EndExample 2.2-9
@EndExampleSession 2.2-10
@EndGroup 2.2-5
@EndLatexOnly 2.2-16
@EndLog 2.2-11
@EndLogSession 2.2-12
@EndNotLatex 2.2-17
@Group grpname 2.1-4
@GroupTitle 2.2-6
@InsertCode name 2.2-15
@Label label 2.1-5
@LatexOnly text 2.2-16
@Level 2.2-7
@NotLatex text 2.2-17
@ResetLevel 2.2-8
@Returns ret_val 2.1-2
@Section 2.2-2
@SectionLabel 2.2-2
@SectionTitle 2.2-2
@Subsection 2.2-3
@SubsectionLabel 2.2-3
@SubsectionTitle 2.2-3
1.3-3 1.3-3
AProperty, for IsObject 2.1-7
    testlabel 2.1-6
AutoDoc 4.1-1
AutoDocWorksheet 3.1-1
1.3-3 1.3-3 1.3-3
FirstOperation, for IsInt 2.5-1
1.3-3
makedoc.g 1.1
1.3-3
SecondOperation, for IsInt, IsGroup 2.5-1
ThirdOperation, for IsGroup, IsInt 2.5-1

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2023.06.19/doc/chooser.html000644 000766 000024 00000007456 14444021302 017046 0ustar00mhornstaff000000 000000 GAPDoc Style Chooser

Setting preferences for GAPDoc manuals

Unfold subsections in menus only by mouse clicks: no (default)     yes

Show GAP examples as in sessions with ColorPrompt(true): yes (default)     no

Display side of table of contents within chapters: right (default)     left

Main document font: Helvetica/sans serif (default)     Times/serif

Paragraph formatting: left-right justified (default)     ragged right

Apply settings to last page.

AutoDoc-2023.06.19/gap/Markdown.gd000644 000766 000024 00000000524 14444021247 016613 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later DeclareGlobalFunction( "INSERT_IN_STRING_WITH_REPLACE" ); DeclareGlobalFunction( "CONVERT_LIST_OF_STRINGS_IN_MARKDOWN_TO_GAPDOC_XML" ); AutoDoc-2023.06.19/gap/ToolFunctions.gi000644 000766 000024 00000022744 14444021247 017654 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later # Check whether the given directory exists, and if not, attempt # to create it. InstallGlobalFunction( "AUTODOC_CreateDirIfMissing", function(d) local tmp; if not IsDirectoryPath(d) then tmp := CreateDir(d); # Note: CreateDir is currently undocumented if tmp = fail then Error("Cannot create directory ", d, "\n", "Error message: ", LastSystemError().message, "\n"); return false; fi; fi; return true; end ); InstallGlobalFunction( "AUTODOC_CurrentDirectory", function(args...) local pwd, result; pwd := Filename( DirectoriesSystemPrograms(), "pwd" ); if pwd = fail then Error("failed to locate 'pwd' tool"); fi; result := ""; Process(DirectoryCurrent(), pwd, InputTextNone(), OutputTextString(result, true), []); return Chomp(result); end); InstallGlobalFunction( "AUTODOC_OutputTextFile", function( dir, filename ) local filestream; filename := Filename( dir, filename ); filestream := OutputTextFile( filename, false ); SetPrintFormattingStatus( filestream, false ); return filestream; end ); ## InstallGlobalFunction( AutoDoc_WriteDocEntry, function( filestream, list_of_records, heading, level_value ) local return_value, description, current_description, labels, i; # look for a good return value (it should be the same everywhere) for i in list_of_records do if IsBound( i!.return_value ) then if IsList( i!.return_value ) and Length( i!.return_value ) > 0 then return_value := i!.return_value; break; elif IsBool( i!.return_value ) then return_value := i!.return_value; break; fi; fi; od; if not IsBound( return_value ) then return_value := false; fi; if IsList( return_value ) and ( not IsString( return_value ) ) and return_value <> "" then return_value := JoinStringsWithSeparator( return_value, " " ); fi; # collect description (for readability not in the loop above) description := [ ]; for i in list_of_records do current_description := i!.description; if IsString( current_description ) then current_description := [ current_description ]; fi; description := Concatenation( description, current_description ); od; labels := [ ]; for i in list_of_records do if HasGroupName( i ) then Add( labels, GroupName( i ) ); fi; od; if Length( labels ) > 1 then labels := [ labels[ 1 ] ]; fi; # Write stuff out # First labels, this has no effect in the current GAPDoc, btw. AppendTo( filestream, "\n" ); # Next possibly the heading for the entry if IsString( heading ) then AppendTo( filestream, "", heading, "\n" ); fi; # Function headers for i in list_of_records do AppendTo( filestream, " <", i!.item_type, " " ); if i!.arguments <> fail and i!.item_type <> "Var" then AppendTo( filestream, "Arg=\"", i!.arguments, "\" " ); fi; AppendTo( filestream, "Name=\"", i!.name, "\" " ); if i!.tester_names <> fail and i!.tester_names <> "" then AppendTo( filestream, "Label=\"", i!.tester_names, "\"" ); fi; AppendTo( filestream, "/>\n" ); od; if return_value <> false then if IsString( return_value ) then return_value := [ return_value ]; fi; AppendTo( filestream, " " ); WriteDocumentation( return_value, filestream, level_value ); AppendTo( filestream, "\n" ); fi; AppendTo( filestream, " \n" ); WriteDocumentation( description, filestream, level_value ); AppendTo( filestream, " \n" ); AppendTo( filestream, "\n\n" ); end ); InstallGlobalFunction( AutoDoc_CreatePrintOnceFunction, function( message ) local x; x := true; return function( ) if x then Print( message, "\n" ); fi; x := false; end; end ); InstallGlobalFunction( AUTODOC_Diff, function(args...) local diff; diff := Filename( DirectoriesSystemPrograms(), "diff" ); if diff = fail then Error("failed to locate 'diff' tool"); fi; return Process(DirectoryCurrent(), diff, InputTextUser(), OutputTextUser(), args); end); # AUTODOC_TestWorkSheet is used by AutoDocs test suite to test the worksheets # feature. Its single argument should be a string, and then # `tst/worksheets/` should be a directory containing a worksheet, and # `tst/worksheets/.expected` a directory containing the output of # AutoDocWorksheet for that worksheet. # # Then AUTODOC_TestWorkSheet will again run AutoDocWorksheet, put storing the # output into `tst/worksheets/.actual`; it then runs diff on all files in # order to find any differences that may have crept in. If no differences # exist, it outputs nothing. InstallGlobalFunction( AUTODOC_TestWorkSheet, function(ws) local wsdir, sheetdir, expecteddir, actualdir, filenames, old, f, expected, actual; # check worksheets dir exists wsdir := DirectoriesPackageLibrary("AutoDoc", "tst/worksheets"); wsdir := wsdir[1]; if not IsDirectoryPath(wsdir) then Error("could not access tst/worksheets/"); fi; # check input dir exists sheetdir := Filename(wsdir, Concatenation(ws, ".sheet")); if not IsString(sheetdir) or not IsDirectoryPath(sheetdir) then Error("could not access tst/", ws, ".sheet/"); fi; sheetdir := Directory(sheetdir); # check dir with expected output expecteddir := Filename(wsdir, Concatenation(ws, ".expected")); if not IsString(expecteddir) or not IsDirectoryPath(expecteddir) then Error("could not access tst/", ws, ".expected/"); fi; expecteddir := Directory(expecteddir); # create and clear the output directory actualdir := Filename(wsdir, Concatenation(ws, ".actual")); Exec(Concatenation("rm -rf \"", actualdir, "\"")); AUTODOC_CreateDirIfMissing(actualdir); actualdir := Directory(actualdir); # Run the worksheet filenames := DirectoryContents(sheetdir); filenames := Filtered(filenames, f -> f <> "." and f <> ".."); filenames := List(filenames, f -> Filename(sheetdir, f)); old := InfoLevel(InfoGAPDoc); SetInfoLevel(InfoGAPDoc, 0); AutoDocWorksheet(filenames, rec(dir := actualdir, extract_examples := true)); SetInfoLevel(InfoGAPDoc, old); # Check the results filenames := DirectoryContents(expecteddir); filenames := Filtered(filenames, f -> f <> "." and f <> ".."); for f in filenames do expected := Filename(expecteddir, f); actual := Filename(actualdir, f); if 0 <> AUTODOC_Diff("-u", expected, actual) then Error("diff detected in file ", f); fi; od; end); BindGlobal("AUTODOC_months", MakeImmutable([ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ])); # Format a date into a human readable string; a date may consist of only # a year; or a year and a month; or a year, month and day. Dates are # formatted as "2019", resp. "February 2019" resp. "5 February 2019". # # The input can be one of the following: # - AUTODOC_FormatDate(rec), where is a record with entries year, month, day; # - AUTODOC_FormatDate(year[, month[, day]]) # In each case, the year, month or day may be given as either an # integer, or as a string representing an integer. InstallGlobalFunction( AUTODOC_FormatDate, function(arg) local date, key, val, result; if Length(arg) = 1 and IsRecord(arg[1]) then date := ShallowCopy(arg[1]); elif Length(arg) in [1..3] then date := rec(); date.year := arg[1]; if Length(arg) >= 2 then date.month := arg[2]; fi; if Length(arg) >= 3 then date.day := arg[3]; fi; fi; if not IsBound(date) then Error("Invalid arguments"); fi; # convert string values to integers for key in [ "day", "month", "year" ] do if IsBound(date.(key)) then val := date.(key); if IsString(val) and Length(val) > 0 and ForAll(val, IsDigitChar) then date.(key) := Int(val); fi; fi; od; if not IsInt(date.year) or date.year < 2000 then Error(" must be an integer >= 2000, or a string representing such an integer"); fi; result := String(date.year); if IsBound(date.month) then if not date.month in [1..12] then Error(" must be an integer in the range [1..12], or a string representing such an integer"); fi; result := Concatenation(AUTODOC_months[date.month], " ", result); if IsBound(date.day) then if not date.day in [1..31] then # TODO: also account for differing length of months Error(" must be an integer in the range [1..31], or a string representing such an integer"); fi; result := Concatenation(String(date.day), " ", result); fi; fi; return result; end); AutoDoc-2023.06.19/gap/AutoDocMainFunction.gd000644 000766 000024 00000003633 14444021247 020706 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later DeclareGlobalVariable( "AUTODOC_XML_HEADER" ); DeclareGlobalFunction( "AUTODOC_SetIfMissing" ); DeclareGlobalFunction( "AUTODOC_APPEND_STRING_ITERATIVE" ); DeclareGlobalFunction( "AUTODOC_MergeRecords" ); DeclareGlobalFunction( "AUTODOC_PROCESS_INTRO_STRINGS" ); DeclareGlobalFunction( "AutoDocScanFiles" ); ## Global option record DeclareGlobalVariable( "_AUTODOC_GLOBAL_OPTION_RECORD" ); ## ## This function creates a title file. It must be called with the package name and the path to doc files. DeclareGlobalFunction( "CreateTitlePage" ); ## ## This function creates _entities.xml, which is included by the default main page DeclareGlobalFunction( "CreateEntitiesPage" ); ## ## This function creates the main page. Do not call it out of context. DeclareGlobalFunction( "CreateMainPage" ); ## ## This function is for internal use only. ## It creates names for the default chapters and sections. DeclareGlobalFunction( "CreateDefaultChapterData" ); DeclareGlobalFunction( "ExtractTitleInfoFromPackageInfo" ); DeclareGlobalFunction( "CreateMakeTest" ); #! @Chapter AutoDoc worksheets #! @Section Worksheets #! @Description #! The intention of these function is to create stand-alone pdf and html files #! using AutoDoc without having them associated to a package. #! It uses the same optional records as the &AutoDoc; command itself, but instead of #! a package name there should be a filename or a list of filenames containing AutoDoc #! text from which the documents are created. Please see the &AutoDoc; command for more #! information about this and have a look at for a simple worksheet example. #! @Arguments list_of_filenames : options DeclareGlobalFunction( "AutoDocWorksheet" ); AutoDoc-2023.06.19/gap/Parser.gd000644 000766 000024 00000000606 14444021247 016266 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later DeclareGlobalFunction( "Scan_for_AutoDoc_Part" ); DeclareGlobalFunction( "AutoDoc_Type_Of_Item" ); ## Argument should be a filename DeclareGlobalFunction( "AutoDoc_Parser_ReadFiles" ); AutoDoc-2023.06.19/gap/Magic.gi000644 000766 000024 00000061035 14444021247 016062 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later # Given a string containing a ".", , return its suffix, # i.e. the bit after the last ".". For example, given "test.txt", # it returns "txt". BindGlobal( "AUTODOC_GetSuffix", function(str) local i; i := Length(str); while i > 0 and str[i] <> '.' do i := i - 1; od; if i = 0 then return ""; fi; return str{[i+1..Length(str)]}; end ); # Scan the given (by name) subdirs of a package dir for # files with one of the given extensions, and return the corresponding # filenames, as relative paths (relative to the package dir). # # For example, the invocation # AUTODOC_FindMatchingFiles(pkgdir, [ "gap/" ], [ "gi", "gd" ]); # might return a list looking like # [ "gap/AutoDocMainFunction.gd", "gap/AutoDocMainFunction.gi", ... ] BindGlobal( "AUTODOC_FindMatchingFiles", function (pkgdir, subdirs, extensions) local d_rel, d, tmp, files, result; result := []; for d_rel in subdirs do # Get the absolute path to the directory in side the package... d := Filename( pkgdir, d_rel ); if not IsDirectoryPath( d ) then continue; fi; d := Directory( d ); # ... but also keep the relative path (such as "gap") if d_rel = "" or d_rel = "." then d_rel := ""; else d_rel := Directory( d_rel ); fi; files := DirectoryContents( d ); Sort( files ); for tmp in files do if not AUTODOC_GetSuffix( tmp ) in extensions then continue; fi; if not IsReadableFile( Filename( d, tmp ) ) then continue; fi; if d_rel = "" then Add( result, tmp ); else Add( result, Filename( d_rel, tmp ) ); fi; od; od; return result; end ); # InstallGlobalFunction( AutoDoc, function( arg ) local pkgname, pkginfo, pkgdir, opt, scaffold, gapdoc, maketest, extract_examples, autodoc, i, doc_dir, doc_dir_rel, tmp, key, val, file, pkgdirstr, docdirstr, title_page, tree, is_worksheet, position_document_class, args; if Length( arg ) >= 3 then Error( "too many arguments" ); fi; # check whether the last argument is an options record if Length( arg ) > 0 and IsRecord( arg[Length(arg)] ) then opt := Remove( arg ); else opt := rec(); fi; # check the first argument if Length(arg) = 0 then pkgdir := DirectoryCurrent( ); elif IsString( arg[1] ) then pkgname := Remove( arg, 1 ); elif IsDirectory( arg[1] ) then pkgdir := Remove( arg, 1 ); fi; # if there are any arguments left, at least one was of unsupported type if Length(arg) > 0 then Error( "wrong arguments" ); fi; if IsBound( pkgdir ) then is_worksheet := false; file := Filename( pkgdir, "PackageInfo.g" ); if not IsExistingFile( file ) then Error( "no package name given and no PackageInfo.g file found" ); elif not IsReadableFile( file ) then Error( "cannot read PackageInfo.g" ); fi; Unbind( GAPInfo.PackageInfoCurrent ); Read( file ); if not IsBound( GAPInfo.PackageInfoCurrent ) then Error( "reading PackageInfo.g failed" ); fi; pkginfo := GAPInfo.PackageInfoCurrent; if IsRecord( pkginfo.PackageDoc ) then pkginfo.PackageDoc:= [ pkginfo.PackageDoc ]; fi; pkgname := pkginfo.PackageName; elif pkgname = "AutoDocWorksheet" then # For internal use only -- for details, refer to the AutoDocWorksheet() function. is_worksheet := true; pkginfo := rec( ); pkgdir := DirectoryCurrent( ); else is_worksheet := false; pkginfo := PackageInfo( pkgname ); if IsEmpty( pkginfo ) then Error( "Could not find package ", pkgname ); elif Length( pkginfo ) > 1 then Info( InfoWarning, 1, "multiple versions of package ", pkgname, " are present, using the first one" ); fi; pkginfo := pkginfo[ 1 ]; pkgdir := Directory( pkginfo.InstallationPath ); fi; # # Check for user supplied options. If present, they take # precedence over any defaults as well as the opt record. # for key in [ "dir", "scaffold", "autodoc", "gapdoc", "maketest", "extract_examples" ] do val := ValueOption( key ); if val <> fail then opt.(key) := val; fi; od; # # Setup the output directory # if not IsBound( opt.dir ) then doc_dir := "doc"; elif IsString( opt.dir ) or IsDirectory( opt.dir ) then doc_dir := opt.dir; else Error( "opt.dir must be a string containing a path, or a directory object" ); fi; if IsString( doc_dir ) then # Record the relative version of the path # FIXME: this assumes that doc_dir contains a relative path in the first place... doc_dir_rel := Directory( doc_dir ); # We intentionally do not use # DirectoriesPackageLibrary( pkgname, "doc" ) # because it returns an empty list if the subdirectory is missing. # But we want to handle that case by creating the directory. doc_dir := Filename( pkgdir, doc_dir ); doc_dir := Directory( doc_dir ); else # In this case, if doc_dir happens to lie below pkgdir, we want the # doc_dir_rel to be the difference; if not we avoid binding doc_dir_rel # and leave MakeGAPDocDoc to muddle through with absolute paths. pkgdirstr := Filename( pkgdir, "" ); docdirstr := Filename( doc_dir, "" ); if StartsWith( docdirstr, pkgdirstr ) then doc_dir_rel := Directory( docdirstr{[(Length(pkgdirstr)+1)..Length(docdirstr)]} ); fi; fi; # Ensure the output directory exists, create it if necessary AUTODOC_CreateDirIfMissing(Filename(doc_dir, "")); # Let the developer know where we are generating the documentation. # This helps diagnose problems where multiple instances of a package # are visible to GAP and the wrong one is used for generating the # documentation. Info( InfoGAPDoc, 1, "Generating documentation in ", doc_dir, "\n" ); # # Extract scaffolding settings, which can be controlled via # opt.scaffold or pkginfo.AutoDoc. The former has precedence. # if not IsBound(opt.scaffold) then # Default: enable scaffolding if and only if pkginfo.AutoDoc is present if IsBound( pkginfo.AutoDoc ) then scaffold := rec( ); fi; elif IsRecord(opt.scaffold) then scaffold := opt.scaffold; elif IsBool(opt.scaffold) then if opt.scaffold = true then scaffold := rec(); fi; else Error("opt.scaffold must be a bool or a record"); fi; # Merge pkginfo.AutoDoc into scaffold if IsBound(scaffold) and IsBound( pkginfo.AutoDoc ) then for key in RecNames( pkginfo.AutoDoc ) do if IsBound( scaffold.(key) ) then Print("WARNING: ", key, " specified in both PackageInfo.AutoDoc and opt.scaffold\n"); else scaffold.(key) := pkginfo.AutoDoc.(key); fi; od; fi; if IsBound( scaffold ) then AUTODOC_SetIfMissing( scaffold, "TitlePage", rec() ); AUTODOC_SetIfMissing( scaffold, "MainPage", true ); fi; # # Extract AutoDoc settings # if not IsBound(opt.autodoc) and not is_worksheet then # Enable AutoDoc support if the package depends on AutoDoc. tmp := Concatenation( pkginfo.Dependencies.NeededOtherPackages, pkginfo.Dependencies.SuggestedOtherPackages ); ## Empty entries are allowed in Dependencies tmp := Filtered( tmp, i -> i <> [ ] ); if ForAny( tmp, x -> LowercaseString(x[1]) = "autodoc" ) then autodoc := rec(); fi; elif IsRecord(opt.autodoc) then autodoc := opt.autodoc; elif IsBool(opt.autodoc) and opt.autodoc = true then autodoc := rec(); fi; if IsBound(autodoc) then if not IsBound( autodoc.files ) then autodoc.files := [ ]; elif not IsList( autodoc.files ) then Error("autodoc.files must be a list"); elif Length(autodoc.files) >0 and IsString( autodoc.files ) then Error("autodoc.files must be a list of strings, not a string"); fi; if not is_worksheet then if not IsBound( autodoc.scan_dirs ) then autodoc.scan_dirs := [ ".", "gap", "lib", "examples", "examples/doc" ]; fi; Append( autodoc.files, AUTODOC_FindMatchingFiles(pkgdir, autodoc.scan_dirs, [ "g", "gi", "gd", "autodoc" ]) ); autodoc.files := DuplicateFreeList( autodoc.files ); fi; # Make sure all of the files exist, making the file names absolute if # necessary for i in [ 1 .. Length( autodoc.files ) ] do if IsExistingFile( autodoc.files[ i ] ) then continue; fi; if IsExistingFile( Filename( pkgdir, autodoc.files[ i ] ) ) then autodoc.files[ i ] := Filename( pkgdir, autodoc.files[ i ] ); continue; fi; Error( autodoc.files[ i ], " does not specify an existing file either as an absolute path or relative to the package directory" ); od; if not IsBound( autodoc.level ) then autodoc.level := 0; fi; fi; # # Extract GAPDoc settings # if not IsBound( opt.gapdoc ) then # Enable GAPDoc support by default gapdoc := rec(); elif IsRecord( opt.gapdoc ) then gapdoc := opt.gapdoc; elif IsBool( opt.gapdoc ) and opt.gapdoc = true then gapdoc := rec(); fi; if IsBound( gapdoc ) then AUTODOC_SetIfMissing( gapdoc, "main", pkgname ); if IsBound( pkginfo.PackageDoc ) and not IsEmpty( pkginfo.PackageDoc ) then if Length( pkginfo.PackageDoc ) > 1 then Print("WARNING: Package contains multiple books, only using the first one\n"); fi; gapdoc.bookname := pkginfo.PackageDoc[1].BookName; gapdoc.SixFile := pkginfo.PackageDoc[1].SixFile; elif not is_worksheet then # Default: book name = package name gapdoc.bookname := pkgname; gapdoc.SixFile := "doc/manual.six"; Print("\n"); Print("WARNING: PackageInfo.g is missing a PackageDoc entry!\n"); Print("Without this, your package manual will not be recognized by the GAP help system.\n"); Print("You can correct this by adding the following to your PackageInfo.g:\n"); Print("PackageDoc := rec(\n"); Print(" BookName := ~.PackageName,\n"); Print(" ArchiveURLSubset := [\"doc\"],\n"); Print(" HTMLStart := \"doc/chap0.html\",\n"); Print(" PDFFile := \"doc/manual.pdf\",\n"); Print(" SixFile := \"doc/manual.six\",\n"); Print(" LongTitle := ~.Subtitle,\n"); Print("),\n"); Print("\n"); fi; if not IsBound( gapdoc.files ) then gapdoc.files := []; elif not IsList( gapdoc.files ) then Error("gapdoc.files must be a list"); elif not ForAll( gapdoc.files, IsString ) then Error("gapdoc.files must be a list of strings, not a string"); fi; if not is_worksheet then if not IsBound( gapdoc.scan_dirs ) then gapdoc.scan_dirs := [ ".", "gap", "lib", "examples", "examples/doc" ]; fi; Append( gapdoc.files, AUTODOC_FindMatchingFiles(pkgdir, gapdoc.scan_dirs, [ "g", "gi", "gd" ]) ); fi; # Attempt to weed out duplicates as they may confuse GAPDoc (this # will not work if there are any non-normalized paths in the list). gapdoc.files := Set( gapdoc.files ); # If possible, convert the file paths in gapdoc.files, which are # relative to the package directory, to paths which are relative to # the doc directory. if IsBound( doc_dir_rel ) then # For this, we assume that doc_dir_rel is normalized (e.g. # it does not contains '//') and relative. # FIXME: this is an ugly hack, can't we do something better? tmp := Number( Filename( doc_dir_rel, "" ), x -> x = '/' ); tmp := Concatenation( ListWithIdenticalEntries(tmp, "../") ); gapdoc.files := List( gapdoc.files, f -> Concatenation( tmp, f ) ); else # Here presumably the doc_dir was given by an absolute path that # does not lie below the package dir. In that case, we can't make # the gapdoc.files relative to the doc dir, but rather we have no # choice but to make them absolute, which MakeGAPDocDoc can handle, # even if perhaps less gracefully/portably. gapdoc.files := List( gapdoc.files, f -> Filename( pkgdir, f ) ); fi; fi; # read tree # FIXME: shouldn't tree be declared inside of an 'if IsBound(autodoc)' section? tree := DocumentationTree( ); if IsBound( autodoc ) then if IsBound( autodoc.section_intros ) then AUTODOC_PROCESS_INTRO_STRINGS( autodoc.section_intros, tree ); fi; AutoDocScanFiles( autodoc.files, pkgname, tree ); fi; if is_worksheet then # FIXME: We use scaffold and autodoc here without checking whether # they are bound. Does that mean worksheets always use them? if IsBound( scaffold.TitlePage.Title ) then pkgname := scaffold.TitlePage.Title; elif IsBound( tree!.TitlePage.Title ) then pkgname := tree!.TitlePage.Title; elif IsBound( autodoc.files ) and Length( autodoc.files ) > 0 then tmp := autodoc.files[ 1 ]; # Remove everything before the last '/' tmp := SplitString(tmp, "/"); tmp := tmp[Length(tmp)]; # Remove everything after the first '.' tmp := SplitString(tmp, "."); tmp := tmp[1]; pkgname := tmp; else Error( "could not figure out a title." ); fi; if not IsString( pkgname ) then pkgname := JoinStringsWithSeparator( pkgname, " " ); fi; gapdoc.main := ReplacedString( pkgname, " ", "_" ); gapdoc.bookname := ReplacedString( pkgname, " ", "_" ); fi; # # Generate scaffold # if IsBound( scaffold ) then ## Syntax is [ "class", [ "options" ] ] if IsBound( scaffold.document_class ) then position_document_class := PositionSublist( GAPDoc2LaTeXProcs.Head, "documentclass" ); if IsString( scaffold.document_class ) then scaffold.document_class := [ scaffold.document_class ]; fi; if position_document_class = fail then Error( "something is wrong with the LaTeX header" ); fi; GAPDoc2LaTeXProcs.Head := Concatenation( GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "{", position_document_class ) ]}, scaffold.document_class[ 1 ], GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "}", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); if Length( scaffold.document_class ) = 2 then GAPDoc2LaTeXProcs.Head := Concatenation( GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "[", position_document_class ) ]}, scaffold.document_class[ 2 ], GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "]", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); fi; fi; if IsBound( scaffold.latex_header_file ) then GAPDoc2LaTeXProcs.Head := StringFile( scaffold.latex_header_file ); fi; # check for legacy gapdoc_latex_options if IsBound( scaffold.gapdoc_latex_options ) then Info( InfoWarning, 1, TextAttr.1, "WARNING: Please replace the DEPRECATED option ", "by ", TextAttr.reset ); if not IsBound( gapdoc.LaTeXOptions ) then gapdoc.LaTeXOptions := scaffold.gapdoc_latex_options; fi; fi; AUTODOC_SetIfMissing( scaffold, "includes", [ ] ); if IsBound( autodoc ) then # If scaffold.includes is already set, then we add # AutoDocMainFile.xml to it, but *only* if it not already # there. This way, package authors can control where # it is put in their includes list. if not _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile in scaffold.includes then Add( scaffold.includes, _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile ); fi; fi; if IsBound( scaffold.bib ) and IsBool( scaffold.bib ) then if scaffold.bib = true then scaffold.bib := Concatenation( pkgname, ".bib" ); else Unbind( scaffold.bib ); fi; elif not IsBound( scaffold.bib ) then # If there is a doc/PKG.bib file, assume that we want to reference it in the scaffold. tmp := Concatenation( pkgname, ".bib" ); if IsReadableFile( Filename( doc_dir, tmp ) ) then scaffold.bib := tmp; fi; fi; AUTODOC_SetIfMissing( scaffold, "index", true ); if IsBound( gapdoc ) then if AUTODOC_GetSuffix( gapdoc.main ) = "xml" then scaffold.main_xml_file := gapdoc.main; else scaffold.main_xml_file := Concatenation( gapdoc.main, ".xml" ); fi; fi; if IsBound( scaffold.TitlePage ) and scaffold.TitlePage <> false then title_page := ShallowCopy( scaffold.TitlePage ); AUTODOC_MergeRecords( title_page, tree!.TitlePage ); if not is_worksheet then AUTODOC_MergeRecords( title_page, ExtractTitleInfoFromPackageInfo( pkginfo ) ); fi; # Worksheets get date as a list if is_worksheet then title_page!.Date := Concatenation( title_page!.Date ); fi; CreateTitlePage( doc_dir, title_page ); fi; CreateEntitiesPage( gapdoc.bookname, doc_dir, scaffold ); if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then CreateMainPage( gapdoc.bookname, doc_dir, scaffold ); fi; fi; # # Write AutoDoc XML files # if IsBound( autodoc ) then WriteDocumentation( tree, doc_dir, autodoc.level ); if IsBound( gapdoc ) then if IsBound( doc_dir_rel ) then Add( gapdoc.files, "_Chunks.xml" ); else Add( gapdoc.files, Filename( doc_dir, "_Chunks.xml" ) ); fi; fi; fi; # # Run GAPDoc # if IsBound( gapdoc ) then AUTODOC_SetIfMissing(gapdoc, "LaTeXOptions", rec() ); if not IsRecord( gapdoc.LaTeXOptions ) then Error("gapdoc.LaTeXOptions must be a record"); fi; for key in RecNames( gapdoc.LaTeXOptions ) do if not IsString( gapdoc.LaTeXOptions.( key ) ) and IsList( gapdoc.LaTeXOptions.( key ) ) and LowercaseString( gapdoc.LaTeXOptions.( key )[ 1 ] ) = "file" then gapdoc.LaTeXOptions.( key ) := StringFile( gapdoc.LaTeXOptions.( key )[ 2 ] ); fi; od; # Ask GAPDoc to use UTF-8 as input encoding for LaTeX, as the XML files # of the documentation are also in UTF-8 encoding, and may contain characters # not contained in the default Latin 1 encoding. AUTODOC_SetIfMissing( gapdoc.LaTeXOptions, "InputEncoding", "utf8" ); SetGapDocLaTeXOptions( gapdoc.LaTeXOptions ); ## HACK: If there is an empty index, MakeGAPDocDoc throws an error when creating the pdf. ## this addition prevents this by fake adding the index to the page number log. See issue 106. ## FIXME: Once an empty index is allowed in GapDoc, this should be removed. GAPDoc2LaTeXProcs.Tail := Concatenation( "\\immediate\\write\\pagenrlog{[\"Ind\", 0, 0], \\arabic{page},}\n", GAPDoc2LaTeXProcs.Tail ); # Default parameters for MakeGAPDocDoc args := [ doc_dir, gapdoc.main, gapdoc.files, gapdoc.bookname, "MathJax" ]; # Don't try to generate PDFs if pdflatex is not available if Filename( DirectoriesSystemPrograms(), "pdflatex" ) = fail then Add(args, "nopdf" ); fi; # The global option "relativePath" can be set to ensure the manual # is built in such a way that all references to the GAP reference manual # are using relative file paths. This is mainly useful when building # a package manual for use in a distribution tarball. tmp := ValueOption( "relativePath" ); if IsBound( gapdoc.gap_root_relative_path ) and tmp = fail then ## the option overrides the settings in the call. tmp := gapdoc.gap_root_relative_path; fi; if tmp = true then Add( args, "../../.." ); elif IsString( tmp ) then Add( args, tmp ); fi; # don't build PDF docs if the environment variable NOPDF is set if IsBound( GAPInfo.SystemEnvironment.NOPDF ) then Add( args, "nopdf" ); fi; # Finally, invoke GAPDoc CallFuncList( MakeGAPDocDoc, args ); # NOTE: We cannot just write CopyHTMLStyleFiles(doc_dir) here, as # CopyHTMLStyleFiles its argument directly to Directory(), leading # to an error in all GAP versions up to and including 4.8.6. This # will be fixed with GAP 4.9, where Directory() is made idempotent. CopyHTMLStyleFiles( Filename( doc_dir, "" ) ); # The following (undocumented) API is there for compatibility # with old-style gapmacro.tex based package manuals. It # produces a manual.lab file which those packages can use if # they wish to link to things in the manual we are currently # generating. This can probably be removed eventually, but for # now, doing it does not hurt. # FIXME: It seems that this command does not work if pdflatex # is not present. Maybe we should remove it. if IsBound( gapdoc.SixFile ) then file := Filename(pkgdir, gapdoc.SixFile); if file = fail or not IsReadableFile(file) then Error("could not open `", file, "' for package `", pkgname, "'.\n"); fi; GAPDocManualLabFromSixFile( gapdoc.bookname, file ); fi; fi; # # Handle maketest (deprecated; consider using extract_examples instead) # if IsBound( opt.maketest ) then if IsRecord( opt.maketest ) then maketest := opt.maketest; elif opt.maketest = true then maketest := rec( ); fi; fi; if IsBound( maketest ) then AUTODOC_SetIfMissing( maketest, "filename", "maketest.g" ); AUTODOC_SetIfMissing( maketest, "commands", [ ] ); CreateMakeTest( pkgdir, doc_dir, gapdoc.main, gapdoc.files, maketest ); fi; # # Handle extract_examples # if IsBound( opt.extract_examples ) then if IsRecord( opt.extract_examples ) then extract_examples := opt.extract_examples; elif opt.extract_examples = true then extract_examples := rec( ); fi; fi; if IsBound( extract_examples ) then if is_worksheet then # HACK: not even sure this is really what we want for worksheets, but # it is useful for our "dogfood" test suite pkgdir := doc_dir; fi; if not IsBound( extract_examples.units ) then extract_examples.units := "Chapter"; fi; if not IsBound( extract_examples.skip_empty_in_numbering ) then extract_examples.skip_empty_in_numbering := true; fi; AUTODOC_ExtractMyManualExamples( pkgname, pkgdir, doc_dir, gapdoc.main, gapdoc.files, extract_examples ); fi; return true; end ); AutoDoc-2023.06.19/gap/DocumentationTree.gd000644 000766 000024 00000006134 14444021247 020465 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ###################################### ## ## Tools ## ###################################### DeclareGlobalFunction( "AUTODOC_TREE_NODE_NAME_ITERATOR" ); DeclareGlobalFunction( "AUTODOC_LABEL_OF_CONTEXT" ); DeclareGlobalFunction( "AUTODOC_INSTALL_TREE_SETTERS" ); ###################################### ## ## Categories ## ###################################### DeclareCategory( "IsTreeForDocumentation", IsObject ); DeclareCategory( "IsTreeForDocumentationNode", IsObject ); ###################################### ## ## Attributes ## ###################################### DeclareOperation( "IsEmptyNode", [ IsTreeForDocumentationNode ] ); DeclareOperation( "IsEmptyNode", [ IsString ] ); DeclareAttribute( "Label", IsTreeForDocumentationNode ); DeclareAttribute( "ChapterInfo", IsTreeForDocumentationNode ); DeclareAttribute( "GroupName", IsTreeForDocumentationNode ); ###################################### ## ## Constructors ## ###################################### DeclareOperation( "DocumentationTree", [ ] ); DeclareOperation( "StructurePartInTree", [ IsTreeForDocumentation, IsList ] ); DeclareOperation( "ChapterInTree", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "SectionInTree", [ IsTreeForDocumentation, IsString, IsString ] ); DeclareOperation( "SubsectionInTree", [ IsTreeForDocumentation, IsString, IsString, IsString ] ); DeclareOperation( "DocumentationExample", [ IsTreeForDocumentation ] ); DeclareOperation( "DocumentationChunk", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "DocumentationManItem", [ IsTreeForDocumentation ] ); DeclareOperation( "SetManItemToDescription", [ IsTreeForDocumentationNode ] ); DeclareOperation( "SetManItemToReturnValue", [ IsTreeForDocumentationNode ] ); DeclareOperation( "DocumentationGroup", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "DocumentationGroup", [ IsTreeForDocumentation, IsString, IsList ] ); DeclareOperation( "Add", [ IsTreeForDocumentation, IsTreeForDocumentationNode ] ); DeclareOperation( "Add", [ IsTreeForDocumentationNode, IsTreeForDocumentationNode ] ); DeclareOperation( "Add", [ IsTreeForDocumentation, IsTreeForDocumentationNode, IsList ] ); DeclareOperation( "Add", [ IsTreeForDocumentation, IsTreeForDocumentationNode, IsString ] ); DeclareOperation( "Add", [ IsTreeForDocumentationNode, IsString ] ); DeclareOperation( "MergeGroupEntries", [ IsTreeForDocumentationNode, IsTreeForDocumentationNode ] ); DeclareOperation( "Add", [ IsTreeForDocumentation, IsString ] ); ####################################### ## ## Write methods ## ####################################### DeclareOperation( "WriteDocumentation", [ IsTreeForDocumentation, IsDirectory, IsInt ] ); DeclareOperation( "WriteDocumentation", [ IsTreeForDocumentationNode, IsStream, IsInt ] ); DeclareOperation( "WriteDocumentation", [ IsList, IsStream, IsInt ] ); DeclareOperation( "WriteDocumentation", [ IsTreeForDocumentationNode, IsStream, IsDirectory, IsInt ] ); AutoDoc-2023.06.19/gap/ToolFunctions.gd000644 000766 000024 00000001147 14444021247 017641 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later DeclareGlobalFunction( "AUTODOC_CreateDirIfMissing" ); DeclareGlobalFunction( "AUTODOC_CurrentDirectory" ); DeclareGlobalFunction( "AUTODOC_OutputTextFile" ); DeclareGlobalFunction( "AutoDoc_WriteDocEntry" ); DeclareGlobalFunction( "AutoDoc_CreatePrintOnceFunction" ); DeclareGlobalFunction( "AUTODOC_Diff" ); DeclareGlobalFunction( "AUTODOC_TestWorkSheet" ); DeclareGlobalFunction( "AUTODOC_FormatDate" ); AutoDoc-2023.06.19/gap/Markdown.gi000644 000766 000024 00000016201 14444021247 016617 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ## InstallGlobalFunction( INSERT_IN_STRING_WITH_REPLACE, function( string, new_string, position, nr_letters_to_be_replaced ) return Concatenation( string{[ 1 .. position - 1 ]}, new_string, string{[ position + nr_letters_to_be_replaced .. Length( string ) ]} ); end ); ## InstallGlobalFunction( CONVERT_LIST_OF_STRINGS_IN_MARKDOWN_TO_GAPDOC_XML, function( string_list ) local i, current_list, current_string, max_line_length, current_position, already_in_list, command_list_with_translation, beginning, commands, position_of_command, insert, beginning_whitespaces, temp, string_list_temp, skipped, already_inserted_paragraph, in_list, in_item; ## Check for paragraphs by turning an empty string into

already_inserted_paragraph := false; for i in [ 1 .. Length( string_list ) ] do if NormalizedWhitespace( string_list[ i ] ) = "" then if already_inserted_paragraph = false then string_list[ i ] := "

"; already_inserted_paragraph := true; fi; else already_inserted_paragraph := false; fi; i := i + 1; od; ## We need to find lists. Lists are indicated by a beginning ## *, -, or +. Lists can be nested. Save list as list of strings, ## and at the same time, concatenate all the other strings ## FIXME: @Max: where are my regular expressions? ## Do this in several iterations max_line_length := Maximum( List( string_list, Length ) ); current_position := 1; while current_position < max_line_length do already_in_list := false; i := 1; skipped := false; ## maybe make the first line marked by definition? while i <= Length( string_list ) do if PositionSublist( string_list[ i ], " fail then skipped := true; fi; if PositionSublist( string_list[ i ], "]]>" ) <> fail then skipped := false; i := i + 1; continue; fi; if skipped = true then i := i + 1; continue; fi; if PositionSublist( string_list[ i ], "* " ) = current_position or PositionSublist( string_list[ i ], "+ " ) = current_position or PositionSublist( string_list[ i ], "- " ) = current_position then if not ForAll( [ 1 .. current_position - 1 ], j -> string_list[ i ][ j ] = ' ' ) then i := i + 1; continue; fi; if already_in_list = false then Add( string_list, "", i ); Add( string_list, "", i ); i := i + 2; string_list[ i ] := string_list[ i ]{[ current_position + 2 .. Length( string_list[ i ] ) ]}; already_in_list := true; else Add( string_list, "", i ); Add( string_list, "", i ); i := i + 2; string_list[ i ] := string_list[ i ]{[ current_position + 2 .. Length( string_list[ i ] ) ]}; fi; ## find out if line has to be marked ## THIS is buggy. Discuss this ## FIXME: This causes strange problems with GAPDoc. # if PositionSublist( string_list[ i ], "**" ) = 1 then # string_list[ i ] := string_list[ i ]{[ 3 .. Length( string_list[ i ] ) ]}; # temp := string_list[ i ]; # string_list[ i ] := string_list[ i - 1 ]; # string_list[ i - 1 ] := temp; # Add( string_list, "", i - 1 ); # Add( string_list, "", i + 1 ); # i := i + 2; # fi; elif already_in_list = true and PositionSublist( string_list[ i ], " " ) > current_position then already_in_list := false; Add( string_list, "", i ); Add( string_list, "", i ); i := i + 2; fi; i := i + 1; od; if already_in_list = true then Add( string_list, "" ); Add( string_list, "" ); fi; current_position := current_position + 1; od; # Remove

if in List but not in item in_list := 0; in_item := 0; for current_position in [ 1 .. Length( string_list ) ] do if PositionSublist( string_list[ current_position ], "" ) <> fail then in_list := in_list + 1; fi; if PositionSublist( string_list[ current_position ], "" ) <> fail then in_list := in_list - 1; fi; if PositionSublist( string_list[ current_position ], "" ) <> fail then in_item := in_item + 1; fi; if PositionSublist( string_list[ current_position ], "" ) <> fail then in_item := in_item - 1; fi; if in_item < in_list and string_list[ current_position ] = "

" then string_list[ current_position ] := ""; fi; od; ## Find commands command_list_with_translation := [ [ "$$", "Display" ], [ "$", "Math" ], [ "`", "Code" ], [ "**", "Emph" ], [ "__", "Emph" ] ]; ## special handling for \$ for i in [ 1 .. Length( string_list ) ] do string_list[ i ] := ReplacedString( string_list[ i ], "\\$", "$" ); od; for commands in command_list_with_translation do beginning := true; skipped := false; for i in [ 1 .. Length( string_list ) ] do if PositionSublist( string_list[ i ], " fail then skipped := true; fi; if PositionSublist( string_list[ i ], "]]>" ) <> fail then skipped := false; fi; if skipped = true then continue; fi; while PositionSublist( string_list[ i ], commands[ 1 ] ) <> fail do position_of_command := PositionSublist( string_list[ i ], commands[ 1 ] ); if beginning = true then insert := Concatenation( "<", commands[ 2 ], ">" ); else insert := Concatenation( "" ); fi; string_list[ i ] := INSERT_IN_STRING_WITH_REPLACE( string_list[ i ], insert, position_of_command, Length( commands[ 1 ] ) ); beginning := not beginning; od; od; if beginning = false then Error( "did you forget some ", commands[ 1 ] ); fi; od; return string_list; end ); AutoDoc-2023.06.19/gap/AutoDocMainFunction.gi000644 000766 000024 00000044235 14444021247 020716 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ## InstallValue( AUTODOC_XML_HEADER, Concatenation( "\n\n", "\n" ) ); InstallValue( _AUTODOC_GLOBAL_OPTION_RECORD, rec( AutoDocMainFile := "_AutoDocMainFile.xml" ) ); InstallGlobalFunction( AUTODOC_SetIfMissing, function( record, name, val ) if not IsBound( record.(name) ) then record.(name) := val; fi; end ); ## InstallGlobalFunction( AUTODOC_APPEND_STRING_ITERATIVE, function( arg ) local string, i; string := arg[ 1 ]; for i in [ 2 .. Length( arg ) ] do Append( string, arg[ i ] ); od; Append( string, "\n" ); end ); ## ## Given two records, this adds all key/values pairs of the ## second record to the first record, unless the first record already ## has an entry for that key. InstallGlobalFunction( AUTODOC_MergeRecords, function( dst, src ) local key; for key in RecNames( src ) do AUTODOC_SetIfMissing( dst, key, src.( key ) ); od; end ); ## InstallGlobalFunction( CreateDefaultChapterData, function( pkgname ) local chapter_name, default_chapter_record, list_of_types, i; if not IsString( pkgname ) then Error( "CreateDefaultChapterData must be called with a possible package name\n" ); fi; chapter_name := Concatenation( pkgname, "_automatic_generated_documentation" ); default_chapter_record := rec(); list_of_types := [ "categories", "methods", "attributes", "properties", "global_functions", "global_variables", "info_classes" ]; for i in list_of_types do default_chapter_record.(i) := [ chapter_name, Concatenation( chapter_name, "_of_", i ) ]; od; return default_chapter_record; end ); ## InstallGlobalFunction( CreateEntitiesPage, function( book_name, dir, opt ) local filestream, i, ent, val, entities; if IsString(dir) then dir := Directory(dir); fi; if not IsBound( opt.entities ) then entities := rec(); elif IsList( opt.entities ) then entities := rec(); for i in opt.entities do if IsString( i ) then ent := i; val := Concatenation("", ent, ""); else ent := i[2]; val := Concatenation("<", i[1], ">", ent, ""); fi; entities.(ent) := val; od; elif IsRecord( opt.entities ) then entities := opt.entities; else Error("CreateEntitiesPage: must be a list or a record"); fi; # add book_name unconditionally to the list of entities if not IsBound(entities.(book_name)) then entities.(book_name) := Concatenation( "", book_name, "" ); fi; # open the target XML file filestream := AUTODOC_OutputTextFile( dir, "_entities.xml" ); # output all entities for ent in RecNames(entities) do val := String(entities.(ent)); # escape single quotes, if any val := ReplacedString( val, "'", "\\\'" ); # convert spaces in entity name to underscores ent := ReplacedString( ent, " ", "_" ); AppendTo( filestream, "\n" ); od; CloseStream( filestream ); end ); ## InstallGlobalFunction( CreateMainPage, function( book_name, dir, opt ) local filestream, i; if IsString(dir) then dir := Directory(dir); fi; # open the target XML file filestream := AUTODOC_OutputTextFile( dir, opt.main_xml_file ); # output the initial file header AppendTo( filestream, AUTODOC_XML_HEADER ); AppendTo( filestream, "\n"); AppendTo( filestream, "]\n>\n" ); # now start the actual book AppendTo( filestream, "\n" ); AppendTo( filestream, "<#Include SYSTEM \"title.xml\">\n" ); if not IsBound( opt.table_of_contents ) or opt.table_of_contents <> false then AppendTo( filestream, "\n" ); fi; AppendTo( filestream, "\n" ); if IsBound( opt.includes ) then for i in opt.includes do AppendTo( filestream, "<#Include SYSTEM \"", i, "\">\n" ); od; else AppendTo( filestream, "<#Include SYSTEM \"", _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile, "\">\n" ); fi; AppendTo( filestream, "\n" ); if IsBound( opt.appendix ) then for i in opt.appendix do AppendTo( filestream, "<#Include SYSTEM \"", i, "\">\n" ); od; fi; if IsBound( opt.bib ) and opt.bib <> false then AppendTo( filestream, "\n" ); fi; if IsBound( opt.index ) and opt.index = true then AppendTo( filestream, "\n" ); fi; AppendTo( filestream, "\n" ); CloseStream( filestream ); return true; end ); ## InstallGlobalFunction( ExtractTitleInfoFromPackageInfo, function( pkginfo ) local title_rec, i, tmp_list, j, author_rec, author_string; if IsBound( pkginfo.AutoDoc ) and IsBound( pkginfo.AutoDoc.TitlePage ) then title_rec := ShallowCopy( pkginfo.AutoDoc.TitlePage ); else title_rec := rec( ); fi; AUTODOC_SetIfMissing( title_rec, "Title", pkginfo.PackageName ); AUTODOC_SetIfMissing( title_rec, "Subtitle", ReplacedString( pkginfo.Subtitle, "GAP", "&GAP;" ) ); AUTODOC_SetIfMissing( title_rec, "Version", pkginfo.Version ); ## Sanitize author info if not IsBound( title_rec.Author ) then title_rec.Author := [ ]; i := 1; for author_rec in pkginfo.Persons do if not author_rec.IsAuthor then continue; fi; author_string := ""; AUTODOC_APPEND_STRING_ITERATIVE( author_string, author_rec.FirstNames, " ", author_rec.LastName, "
" ); if IsBound( author_rec.PostalAddress ) then tmp_list := SplitString( StripBeginEnd( author_rec.PostalAddress, "\n\r" ), "\n" ); AUTODOC_APPEND_STRING_ITERATIVE( author_string, "

" ); for j in tmp_list do AUTODOC_APPEND_STRING_ITERATIVE( author_string, j, "
" ); od; AUTODOC_APPEND_STRING_ITERATIVE( author_string, "
" ); fi; if IsBound( author_rec.Email ) then AUTODOC_APPEND_STRING_ITERATIVE( author_string, "", author_rec.Email, "" ); fi; if IsBound( author_rec.WWWHome ) then AUTODOC_APPEND_STRING_ITERATIVE( author_string, "", author_rec.WWWHome, "" ); fi; title_rec.Author[ i ] := author_string; i := i + 1; od; fi; AUTODOC_SetIfMissing( title_rec, "Date", pkginfo.Date ); return title_rec; end ); ## ## This creates a titlepage out of an argument record. ## Please make sure that every entry in the record ## has the name of its tag, even title etc. ## Please note that entities will be treated ## separately. InstallGlobalFunction( CreateTitlePage, function( dir, argument_rec ) local indent, tag, names, filestream, entity_list, OutWithTag, Out, i; filestream := AUTODOC_OutputTextFile( dir, "title.xml" ); indent := 0; Out := function(arg) local s; s := ListWithIdenticalEntries( indent * 2, ' '); Append( s, Concatenation( arg ) ); AppendTo( filestream, s ); end; OutWithTag := function( tag, content ) local lines, s, l; if not IsList( content ) then Error( "can only print string or list of strings" ); fi; if IsString( content ) then content := [ content ]; fi; s := ListWithIdenticalEntries( indent * 2, ' '); AppendTo( filestream, s, "<", tag, ">\n" ); for l in content do AppendTo( filestream, s, " ", l, "\n" ); od; AppendTo( filestream, s, "\n" ); end; Out( AUTODOC_XML_HEADER ); Out( "\n" ); indent := indent + 1; for i in [ "Title", "Subtitle", "Version", "TitleComment" ] do if IsBound( argument_rec.( i ) ) then OutWithTag( i, argument_rec.( i ) ); fi; od; if IsBound( argument_rec.Author ) then for i in argument_rec.Author do OutWithTag( "Author", i ); od; fi; if IsBound( argument_rec.Date ) then # try to parse the date in format DD/MM/YYYY (we also accept single # digit day or month, which is formally not allowed in PackageInfo.g, # but happens in a few legacy packages) argument_rec.Date := Chomp( argument_rec.Date ); # remove trailing newlines, if present i := SplitString( argument_rec.Date, "/" ); if Length( argument_rec.Date ) in [8..10] and Length( i ) = 3 then i := List(i, Int); OutWithTag( "Date", AUTODOC_FormatDate(i[3], i[2], i[1]) ); else # try to parse the date in ISO8601 format YYYY-MM-DD (here we are strict) i := SplitString( argument_rec.Date, "-" ); if Length( argument_rec.Date ) = 10 and Length( i ) = 3 then i := List(i, Int); OutWithTag( "Date", AUTODOC_FormatDate(i[1], i[2], i[3]) ); else Print("Warning: could not parse package date '", argument_rec.Date, "'\n"); OutWithTag( "Date", argument_rec.Date ); fi; fi; fi; for i in [ "Address", "Abstract", "Copyright", "Acknowledgements", "Colophon" ] do if IsBound( argument_rec.( i ) ) then OutWithTag( i, StripBeginEnd( argument_rec.( i ), "\n\r" ) ); fi; od; Out( "" ); CloseStream( filestream ); end ); InstallGlobalFunction( AUTODOC_PROCESS_INTRO_STRINGS, function( introduction_list, tree ) local intro, intro_string, i; for intro in introduction_list do if Length( intro ) = 2 then intro_string := intro[ 2 ]; if IsString( intro_string ) then intro_string := [ intro_string ]; fi; for i in intro_string do Add( ChapterInTree( tree, ReplacedString( intro[ 1 ], " ", "_" ) ), i ); od; elif Length( intro ) = 3 then intro_string := intro[ 3 ]; if IsString( intro_string ) then intro_string := [ intro_string ]; fi; for i in intro_string do Add( SectionInTree( tree, ReplacedString( intro[ 1 ], " ", "_" ), ReplacedString( intro[ 2 ], " ", "_" ) ), i ); od; else Error( "wrong format of introduction string list\n" ); fi; od; return tree; end ); ## ## Optional argument is PackageName, which creates a ## Default chapter record. This is not available for ## worksheets. InstallGlobalFunction( AutoDocScanFiles, function( files_to_scan, pkgname, tree ) local default_chapter_record; default_chapter_record := CreateDefaultChapterData( pkgname ); AutoDoc_Parser_ReadFiles( files_to_scan, tree, default_chapter_record ); return tree; end ); ## InstallGlobalFunction( AutoDocWorksheet, function( arg ) local autodoc_rec, scaffold_rec; if Length( arg ) = 1 then arg[ 2 ] := rec( ); fi; scaffold_rec := ValueOption( "scaffold" ); if scaffold_rec = fail then scaffold_rec := rec( ); fi; AUTODOC_SetIfMissing( scaffold_rec, "index", false ); if Length( arg ) = 2 then autodoc_rec := ValueOption( "autodoc" ); if autodoc_rec = fail then autodoc_rec := rec( ); fi; if IsString( arg[ 1 ] ) then arg[ 1 ] := [ arg[ 1 ] ]; fi; if IsBound( autodoc_rec.files ) then Append( autodoc_rec.files, arg[ 1 ] ); else autodoc_rec.files := arg[ 1 ]; fi; AutoDoc( "AutoDocWorksheet", arg[ 2 ] : autodoc := autodoc_rec, scaffold := scaffold_rec ); fi; if Length( arg ) = 0 then AutoDoc( "AutoDocWorksheet" : scaffold := scaffold_rec ); fi; end ); InstallGlobalFunction( CreateMakeTest, function( pkgdir, doc_dir, main, files_to_scan, argument_rec ) local filename, filestream, i; if IsBound( argument_rec.name ) then filename := argument_rec.name; else filename := "maketest.g"; fi; filestream := AUTODOC_OutputTextFile( pkgdir, filename ); AppendTo( filestream, "## This file is automatically generated by AutoDoc.\n" ); AppendTo( filestream, "## Changes will be discarded by the next call of the AutoDoc method.\n\n\n" ); if IsBound( argument_rec.commands ) and IsList( argument_rec.commands ) then if IsString( argument_rec.commands ) and argument_rec.commands <> [ ] then argument_rec.commands := [ argument_rec.commands ]; fi; for i in argument_rec.commands do AppendTo( filestream, i ); AppendTo( filestream, "\n\n" ); od; fi; AppendTo( filestream, "AUTODOC_file_scan_list := ", files_to_scan, ";\n\n" ); AppendTo( filestream, "LoadPackage( \"GAPDoc\" );\n\n" ); if not EndsWith(main, ".xml") then main := Concatenation( main, ".xml" ); fi; AppendTo( filestream, "example_tree := ExtractExamples( ", doc_dir, ", ", "\"", main, "\", ", "AUTODOC_file_scan_list, 500 );\n\n" ); AppendTo( filestream, "RunExamples( example_tree, rec( compareFunction := \"uptowhitespace\" ) );\n\n" ); AppendTo( filestream, "QUIT;\n" ); CloseStream( filestream ); end ); # The following function is based on code by Alexander Konovalov BindGlobal("AUTODOC_ExtractMyManualExamples", function( pkgname, pkgdir, docdir, main, files, opt ) local tst, i, s, basename, name, output, ch, a, location, pos, comment, pkgdirString, nonempty_units_found, number_of_digits, lpkgname, tstdir; Print("Extracting manual examples for ", pkgname, " package ...\n" ); lpkgname := LowercaseString(pkgname); lpkgname := ReplacedString(lpkgname, " ", "_"); if not EndsWith(main, ".xml") then main := Concatenation( main, ".xml" ); fi; tst:=ExtractExamples( docdir, main, files, opt.units ); Print(Length(tst), " ", LowercaseString( opt.units ), "s detected\n"); pkgdirString := Filename(pkgdir, ""); # ensure the 'tst' directory exists tstdir := Filename(pkgdir, "tst"); AUTODOC_CreateDirIfMissing(tstdir); tstdir := Directory(tstdir); # first delete all old extracted tests in case chapter numbering etc. changed for s in DirectoryContents(tstdir) do # check prefix and suffix... if StartsWith(s, lpkgname) and EndsWith(s, ".tst") # ... and between them, there should be only digits (at least 2)... and Length(s) - Length(lpkgname) - 4 >= 2 and ForAll(s{[1 + Length(lpkgname) .. Length(s) - 4]}, IsDigitChar) then RemoveFile(Filename(tstdir, s)); fi; od; # nonempty_units_found := 0; number_of_digits := Length( String( Length( tst ) ) ); if number_of_digits = 1 then number_of_digits := 2; fi; for i in [ 1 .. Length(tst) ] do Print( opt.units, " ", i, " : \c" ); if Length( tst[i] ) = 0 then Print("no examples \n" ); continue; fi; nonempty_units_found := nonempty_units_found + 1; if opt.skip_empty_in_numbering then s := String( nonempty_units_found ); else s := String( i ); fi; # pad s to number_of_digits s := Concatenation( ListWithIdenticalEntries( number_of_digits - Length( s ), '0' ), s ); basename := Concatenation( lpkgname, s, ".tst" ); name := Filename( tstdir, basename ); output := OutputTextFile( name, false ); # to empty the file first SetPrintFormattingStatus( output, false ); # to avoid line breaks ch := tst[i]; AppendTo(output, "# ", pkgname, ", ", LowercaseString( opt.units ), " ", i, "\n"); AppendTo(output, """# # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been generated by AutoDoc. It contains examples extracted from # the package documentation. Each example is preceded by a comment which gives # the name of a GAPDoc XML file and a line range from which the example were # taken. Note that the XML file in turn may have been generated by AutoDoc # from some other input. # """); AppendTo(output, "gap> START_TEST(\"", basename, "\");\n\n"); for a in ch do location := a[2][1]; if StartsWith(location, pkgdirString) then comment := location{[ Length(pkgdirString)+1 .. Length(location) ]}; else pos := PositionSublist(location, LowercaseString(pkgname)); if pos <> fail then comment := location{[ pos+Length(pkgname)+1 .. Length(location) ]}; else pos := PositionSublist(location,"./"); if pos <> fail then comment := location{[ pos+2 .. Length(location) ]}; else Error("oops"); fi; fi; fi; AppendTo(output, "# ", comment, ":", a[2][2], "-", a[2][3]); if not StartsWith(a[1], "\n") then AppendTo(output, "\n"); fi; if not EndsWith(a[1], "\n") then AppendTo(output, a[1], "\n\n"); else AppendTo(output, a[1], "\n"); fi; od; AppendTo(output, "#\n"); AppendTo(output, "gap> STOP_TEST(\"", basename, "\", 1);\n"); CloseStream( output ); Print("extracted ", Length(ch), " examples\n"); od; end); AutoDoc-2023.06.19/gap/DocumentationTree.gi000644 000766 000024 00000050454 14444021247 020476 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ## BindGlobal( "AUTODOC_IdentifierLetters", "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" ); DeclareRepresentation( "IsTreeForDocumentationRep", IsAttributeStoringRep and IsTreeForDocumentation, [ ] ); BindGlobal( "TheFamilyOfDocumentationTrees", NewFamily( "TheFamilyOfDocumentationTrees" ) ); BindGlobal( "TheTypeOfDocumentationTrees", NewType( TheFamilyOfDocumentationTrees, IsTreeForDocumentationRep ) ); ## Metatype, specify later DeclareRepresentation( "IsTreeForDocumentationNodeRep", IsAttributeStoringRep and IsTreeForDocumentationNode, [ ] ); BindGlobal( "TheFamilyOfDocumentationTreeNodes", NewFamily( "TheFamilyOfDocumentationTreeNodes" ) ); BindGlobal( "TheTypeOfDocumentationTreeNodes", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeRep ) ); ## Chapter node DeclareRepresentation( "IsTreeForDocumentationNodeForChapterRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForChapter", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForChapterRep ) ); ## Section node DeclareRepresentation( "IsTreeForDocumentationNodeForSectionRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForSection", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForSectionRep ) ); ## Subsection node DeclareRepresentation( "IsTreeForDocumentationNodeForSubsectionRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForSubsection", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForSubsectionRep ) ); ## Text node DeclareRepresentation( "IsTreeForDocumentationNodeForTextRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForText", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForTextRep ) ); ## ManItem node DeclareRepresentation( "IsTreeForDocumentationNodeForManItemRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForManItem", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForManItemRep ) ); ## Group Node DeclareRepresentation( "IsTreeForDocumentationNodeForGroupRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeNodesForGroup", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationNodeForGroupRep ) ); ## DeclareRepresentation DeclareRepresentation( "IsTreeForDocumentationChunkNodeRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeChunkNodes", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationChunkNodeRep ) ); ## DeclareRepresentation DeclareRepresentation( "IsTreeForDocumentationExampleNodeRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeExampleNodes", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationExampleNodeRep ) ); ################################### ## ## Tools ## ################################### ## InstallGlobalFunction( AUTODOC_TREE_NODE_NAME_ITERATOR, function( tree ) local curr_val; curr_val := tree!.node_name_iterator; tree!.node_name_iterator := curr_val + 1; return curr_val; end ); ## InstallGlobalFunction( AUTODOC_LABEL_OF_CONTEXT, function( context ) local label; if not IsList( context ) then Error( "wrong type of context" ); fi; if IsString( context ) then label := context; elif Length( context ) = 1 then label := Concatenation( "Chapter_", context[ 1 ] ); elif Length( context ) = 2 then label := Concatenation( "Chapter_", context[ 1 ], "_Section_", context[ 2 ] ); elif Length( context ) = 3 then label := Concatenation( "Chapter_", context[ 1 ], "_Section_", context[ 2 ], "_Subsection_", context[ 3 ] ); else Error( "wrong type of context" ); fi; label := Filtered(label, x -> x in AUTODOC_IdentifierLetters); return label; end ); ################################### ## ## Constructors ## ################################### ## InstallMethod( DocumentationTree, [ ], function( ) local tree; tree := rec( content := [ ], # a list of nodes nodes_by_label := rec( ), node_name_iterator := 0, current_level := 0, TitlePage := rec( ), chunks := rec( ), ); ObjectifyWithAttributes( tree, TheTypeOfDocumentationTrees ); return tree; end ); ## create a chapter, section or subsection InstallMethod( StructurePartInTree, [ IsTreeForDocumentation, IsList ], function( tree, context ) local label, parent, new_node, type; if IsEmpty( context ) then return tree; fi; # if the part already exist, use that label := AUTODOC_LABEL_OF_CONTEXT( context ); if IsBound( tree!.nodes_by_label.( label ) ) then return tree!.nodes_by_label.( label ); fi; parent := StructurePartInTree( tree, context{[1..Length(context)-1]} ); new_node := rec( content := [ ], level := tree!.current_level, name := context[ Length( context ) ], chapter_info := context ); if Length( context ) = 1 then type := TheTypeOfDocumentationTreeNodesForChapter; elif Length( context ) = 2 then type := TheTypeOfDocumentationTreeNodesForSection; elif Length( context ) = 3 then type := TheTypeOfDocumentationTreeNodesForSubsection; fi; ObjectifyWithAttributes( new_node, type, Label, label ); tree!.nodes_by_label.( label ) := new_node; Add( parent!.content, new_node ); return new_node; end ); ## InstallMethod( DocumentationExample, [ IsTreeForDocumentation ], function( tree ) local node, label; node := rec( content := [ ], level := tree!.current_level ); label := Concatenation( "Example_", String( AUTODOC_TREE_NODE_NAME_ITERATOR( tree ) ) ); ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeExampleNodes, Label, label ); tree!.nodes_by_label.( label ) := node; return node; end ); ## InstallMethod( DocumentationChunk, [ IsTreeForDocumentation, IsString ], function( tree, name ) local node; if IsBound( tree!.chunks.( name ) ) then return tree!.chunks.( name ); fi; node := rec( content := [ ], level := tree!.current_level ); ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeChunkNodes, Label, name ); tree!.chunks.( name ) := node; return node; end ); ## InstallMethod( DocumentationManItem, [ IsTreeForDocumentation ], function( tree ) local node, name; node := rec( description := [ ], return_value := [ ], level := tree!.current_level ); ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeNodesForManItem ); name := Concatenation( "ManItem_", String( AUTODOC_TREE_NODE_NAME_ITERATOR( tree ) ) ); tree!.nodes_by_label.( name ) := node; node!.content := node!.description; return node; end ); ## InstallMethod( SetManItemToDescription, [ IsTreeForDocumentationNodeForManItemRep ], function( node ) node!.content := node!.description; end ); ## InstallMethod( SetManItemToReturnValue, [ IsTreeForDocumentationNodeForManItemRep ], function( node ) node!.content := node!.return_value; end ); ## InstallMethod( DocumentationGroup, [ IsTreeForDocumentation, IsString ], function( tree, group_name ) local group, name; name := Concatenation( "GROUP_", group_name ); if IsBound( tree!.nodes_by_label.( name ) ) then return tree!.nodes_by_label.( name ); fi; group := rec( content := [ ], level := tree!.current_level ); ObjectifyWithAttributes( group, TheTypeOfDocumentationTreeNodesForGroup, Label, name ); tree!.nodes_by_label.( name ) := group; group!.is_added := false; return group; end ); ## InstallMethod( DocumentationGroup, [ IsTreeForDocumentation, IsString, IsList ], function( tree, group_name, context ) local name, group; name := Concatenation( "GROUP_", group_name ); if IsBound( tree!.nodes_by_label.( name ) ) then return tree!.nodes_by_label.( name ); fi; context := AUTODOC_LABEL_OF_CONTEXT( context ); group := DocumentationGroup( tree, group_name ); Add( tree!.nodes_by_label.( context ), group ); group!.is_added := true; return group; end ); ## InstallMethod( Add, [ IsTreeForDocumentationNode, IsTreeForDocumentationNode ], function( parent_node, node ) Add( parent_node!.content, node ); end ); ## InstallMethod( Add, [ IsTreeForDocumentationNode, IsString ], function( parent_node, string ) Add( parent_node!.content, string ); end ); ## InstallMethod( Add, [ IsTreeForDocumentation, IsTreeForDocumentationNodeForManItemRep and HasChapterInfo ], function( tree, node ) local chapter_info, section; chapter_info := ChapterInfo( node ); section := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); Add( section, node ); end ); ## InstallMethod( Add, [ IsTreeForDocumentation, IsTreeForDocumentationNodeForManItemRep and HasGroupName ], function( tree, node ) local group; group := DocumentationGroup( tree, GroupName( node ) ); Add( group, node ); end ); ## InstallMethod( Add, [ IsTreeForDocumentation, IsTreeForDocumentationNodeForManItemRep and HasGroupName and HasChapterInfo ], function( tree, node ) local chapter_info, group; chapter_info := ChapterInfo( node ); group := DocumentationGroup( tree, GroupName( node ), chapter_info ); Add( group, node ); end ); ## InstallMethod( Add, [ IsTreeForDocumentation, IsTreeForDocumentationNode, IsList ], function( tree, node, context ) local label, context_node; label := AUTODOC_LABEL_OF_CONTEXT( context ); context_node := tree!.nodes_by_label.(label); Add( context_node, node ); end ); ## InstallMethod( IsEmptyNode, [ IsTreeForDocumentationNode ], function( node ) if IsBound( node!.content ) then return ForAll( node!.content, IsEmptyNode ); fi; return false; end ); ## InstallMethod( IsEmptyNode, [ IsString ], function( node ) return node = ""; end ); ## InstallMethod( IsEmptyNode, [ IsTreeForDocumentationNodeForManItemRep ], function( node ) return false; end ); #################################### ## ## Add functions ## #################################### ## InstallMethod( ChapterInTree, [ IsTreeForDocumentation, IsString ], function( tree, name ) return StructurePartInTree( tree, [ name ] ); end ); ## InstallMethod( SectionInTree, [ IsTreeForDocumentation, IsString, IsString ], function( tree, chapter_name, section_name ) return StructurePartInTree( tree, [ chapter_name, section_name ] ); end ); ## InstallMethod( SubsectionInTree, [ IsTreeForDocumentation, IsString, IsString, IsString ], function( tree, chapter_name, section_name, subsection_name ) return StructurePartInTree( tree, [ chapter_name, section_name, subsection_name ] ); end ); ############################################# ## ## Write functions ## ############################################# BindGlobal( "WriteChunks", function( tree, path_to_xmlfiles, level_value ) local chunks_stream, filename, chunk_names, current_chunk_name, current_chunk; filename := "_Chunks.xml"; chunks_stream := AUTODOC_OutputTextFile( path_to_xmlfiles, filename ); chunk_names := RecNames( tree!.chunks ); for current_chunk_name in chunk_names do current_chunk := tree!.chunks.( current_chunk_name ); AppendTo( chunks_stream, "<#GAPDoc Label=\"", current_chunk_name, "\">\n" ); if IsBound( current_chunk!.content ) then WriteDocumentation( current_chunk!.content, chunks_stream, level_value ); fi; AppendTo( chunks_stream, "\n<#/GAPDoc>\n" ); od; CloseStream( chunks_stream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentation, IsDirectory, IsInt ], function( tree, path_to_xmlfiles, level_value ) local stream, i; stream := AUTODOC_OutputTextFile( path_to_xmlfiles, _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile ); AppendTo( stream, AUTODOC_XML_HEADER ); for i in tree!.content do if not IsTreeForDocumentationNodeForChapterRep( i ) then Error( "this should never happen" ); fi; ## FIXME: If there is anything else than a chapter, this will break! WriteDocumentation( i, stream, path_to_xmlfiles, level_value ); od; WriteChunks( tree, path_to_xmlfiles, level_value ); # Workaround for issue #65 if IsEmpty( tree!.content ) then AppendTo( stream, " \n" ); fi; CloseStream( stream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForChapterRep, IsStream, IsDirectory, IsInt ], function( node, stream, path_to_xmlfiles, level_value ) local filename, chapter_stream, label, replaced_name, additional_label; if node!.level > level_value then return; fi; if ForAll( node!.content, IsEmptyNode ) then return; fi; label := Label( node ); if IsBound( node!.additional_label ) then additional_label := node!.additional_label; else additional_label := label; fi; if IsBound( node!.title_string ) then replaced_name := NormalizedWhitespace( node!.title_string ); else replaced_name := ReplacedString( node!.name, "_", " " ); fi; # Remove any characters outside of A-Za-z0-9 and -, +, _ from the filename. # See issues #77 and #78 filename := Filtered( additional_label, x -> x in AUTODOC_IdentifierLetters); filename := Concatenation( "_", filename, ".xml" ); chapter_stream := AUTODOC_OutputTextFile( path_to_xmlfiles, filename ); AppendTo( stream, "<#Include SYSTEM \"", filename, "\">\n" ); AppendTo( chapter_stream, AUTODOC_XML_HEADER ); AppendTo( chapter_stream, "\n" ); AppendTo( chapter_stream, Concatenation( [ "", replaced_name, "\n\n" ] ) ); WriteDocumentation( node!.content, chapter_stream, level_value ); AppendTo( chapter_stream, "\n\n" ); CloseStream( chapter_stream ); end ); ## InstallMethod( WriteDocumentation, [ IsList, IsStream, IsInt ], function( node_list, filestream, level_value ) local current_string_list, i, last_position; i := 1; current_string_list := [ ]; for i in [ 1 .. Length( node_list ) ] do if IsString( node_list[ i ] ) then Add( current_string_list, ShallowCopy( node_list[ i ] ) ); else if current_string_list <> [ ] then current_string_list := CONVERT_LIST_OF_STRINGS_IN_MARKDOWN_TO_GAPDOC_XML( current_string_list ); Perform( current_string_list, function( i ) WriteDocumentation( i, filestream, level_value ); end ); current_string_list := [ ]; fi; WriteDocumentation( node_list[ i ], filestream, level_value ); AppendTo( filestream, "\n" ); fi; od; if current_string_list <> [ ] then current_string_list := CONVERT_LIST_OF_STRINGS_IN_MARKDOWN_TO_GAPDOC_XML( current_string_list ); Perform( current_string_list, function( i ) WriteDocumentation( i, filestream, level_value ); end ); fi; end ); ## InstallMethod( WriteDocumentation, [ IsString, IsStream, IsInt ], function( text, filestream, level_value ) ## In case the list is empty, do nothing. ## Once the empty string = empty list bug is fixed, ## this could be removed. text := Chomp( text ); if NormalizedWhitespace( text ) = "" then return; fi; AppendTo( filestream, text, "\n" ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForSectionRep, IsStream, IsInt ], function( node, filestream, level_value ) local replaced_name, label, additional_label; if node!.level > level_value then return; fi; if ForAll( node!.content, IsEmptyNode ) then return; fi; if IsBound( node!.additional_label ) then label := node!.additional_label; else label := Label( node );; fi; if IsBound( node!.title_string ) then replaced_name := NormalizedWhitespace( node!.title_string ); else replaced_name := ReplacedString( node!.name, "_", " " ); fi; AppendTo( filestream, "
\n" ); AppendTo( filestream, Concatenation( [ "", replaced_name, "\n\n" ] ) ); WriteDocumentation( node!.content, filestream, level_value ); AppendTo( filestream, "
\n\n" ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForSubsectionRep, IsStream, IsInt ], function( node, filestream, level_value ) local replaced_name, label, additional_label; if node!.level > level_value then return; fi; if ForAll( node!.content, IsEmptyNode ) then return; fi; if IsBound( node!.additional_label ) then label := node!.additional_label; else label := Label( node ); fi; if IsBound( node!.title_string ) then replaced_name := NormalizedWhitespace( node!.title_string ); else replaced_name := ReplacedString( node!.name, "_", " " ); fi; AppendTo( filestream, "\n" ); AppendTo( filestream, Concatenation( [ "", replaced_name, "\n\n" ] ) ); WriteDocumentation( node!.content, filestream, level_value ); AppendTo( filestream, "\n\n" ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForManItemRep, IsStream, IsInt ], function( node, filestream, level_value ) if node!.level > level_value then return; fi; AutoDoc_WriteDocEntry( filestream, [ node ], fail, level_value ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForGroupRep, IsStream, IsInt ], function( node, filestream, level_value ) local heading; if node!.level > level_value then return; fi; heading := fail; if IsBound( node!.title_string ) then heading := node!.title_string; fi; AutoDoc_WriteDocEntry( filestream, node!.content, heading, level_value ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationChunkNodeRep, IsStream, IsInt ], function( node, filestream, level_value ) if node!.level > level_value then return; fi; WriteDocumentation( Concatenation( "<#Include Label=\"", Label( node ), "\">" ), filestream, level_value ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationExampleNodeRep, IsStream, IsInt ], function( node, filestream, level_value ) local contents, i, tested, inserted_string; if node!.level > level_value then return; fi; contents := node!.content; tested := node!.is_tested_example; if tested = true then inserted_string := "Example"; elif tested = false then inserted_string := "Log"; else Error( "This should not happen!" ); fi; AppendTo( filestream, "<", inserted_string, ">. i := ReplacedString(i, "]]>", "]]]]>"); AppendTo( filestream, i, "\n" ); od; AppendTo( filestream, "]]>\n\n" ); end ); AutoDoc-2023.06.19/gap/Magic.gd000644 000766 000024 00000045736 14444021247 016067 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later #! @Chapter AutoDoc #! @Section The AutoDoc() function #! @Description #! This is the main function of the &AutoDoc; package. It can perform #! any combination of the following tasks: #! #! #! It can (re)generate a scaffold for your package manual. #! That is, it can produce two XML files in &GAPDoc; format to be used as part #! of your manual: First, a file named doc/PACKAGENAME.xml #! (with your package's name substituted) which is used as #! main XML file for the package manual, i.e. this file sets the #! XML doctype and defines various XML entities, includes #! other XML files (both those generated by &AutoDoc; as well #! as additional files created by other means), tells &GAPDoc; #! to generate a table of contents and an index, and more. #! Secondly, it creates a file doc/title.xml containing a title #! page for your documentation, with information about your package #! (name, description, version), its authors and more, based #! on the data in your PackageInfo.g. #! #! #! It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; #! tags and the Autodoc command. #! This will #! produce further XML files to be used as part of the package manual. #! #! #! It can use &GAPDoc; to generate PDF, text and HTML (with #! MathJaX enabled) documentation from the &GAPDoc; XML files it #! generated as well as additional such files provided by you. For #! this, it invokes #! to convert the XML sources, and it also instructs &GAPDoc; to copy #! supplementary files (such as CSS style files) into your doc directory #! (see ). #! #! #! For more information and some examples, please refer to Chapter . #!

#! The parameters have the following meanings: #! #! #! packageOrDirectory #! #! The purpose of this parameter is twofold: to determine the package #! directory in which &AutoDoc; will operate, and to find the metadata #! concerning the package being documented. The parameter is either a #! string, an IsDirectory object, or omitted. #! If it is a string, &AutoDoc; interprets it as the name of a #! package, uses the metadata of the first package known to &GAP; #! with that name, and uses the InstallationPath specified in that #! metadata as the package directory. If packageOrDirectory is #! an IsDirectory object, this is used as package directory; #! if the argument is omitted, then the current directory is used. #! In the last two cases, the specified directory must contain a #! PackageInfo.g file, and &AutoDoc; extracts all needed metadata #! from that. The IsDirectory form is for example useful if you #! have multiple versions of the package around and want to make sure the #! documentation of the correct version is built. #!

#! Note that when using AutoDocWorksheet (see #! ), there is #! no parameter corresponding to packageOrDirectory and so the #! package directory is always the current directory, and #! there is no metadata. #! #! #! #! optrec #! #! optrec can be a record with some additional options. #! The following are currently supported: #! #! dir #! #! This should either be a string, in which case it must be a path #! relative to the specified package directory, or a #! Directory() object. (Thus, the only way to designate an #! absolute directory is with a Directory() object.) This #! option specifies where the package documentation #! (e.g. the &GAPDoc; XML or the manual PDF, etc.) files are stored #! and/or will be generated. #!
#! Default value: "doc/". #!
#! scaffold #! #! This controls whether and how to generate scaffold XML files #! for the package documentation. #!

#! The value should be either true, false or a #! record. If it is a record or true (the latter is #! equivalent to specifying an empty record), then this feature is #! enabled. It is also enabled if opt.scaffold is missing but the #! package's info record in PackageInfo.g has an AutoDoc entry. #! In all other cases (in particular if opt.scaffold is #! false), scaffolding is disabled. #!

#! If scaffolding is enabled, and PackageInfo.AutoDoc exists, then it is #! assumed to be a record, and its contents are used as default values for #! the scaffold settings. #!

#! #! If opt.scaffold is a record, it may contain the following entries. #! #! #! #! includes #! #! A list of XML files to be included in the body of the main XML file. #! If you specify this list and also are using &AutoDoc; to document #! your operations with &AutoDoc; comments, #! you can add _AutoDocMainFile.xml to this list #! to control at which point the documentation produced by &AutoDoc; #! is inserted. If you do not do this, it will be added after the last #! of your own XML files. #! #! #! index #! #! By default, the scaffold creates an index. If you do not want an index, #! set this to false. #! #! #! appendix #! #! This entry is similar to opt.scaffold.includes but is used #! to specify files to include after the main body of the manual, #! i.e. typically appendices. #! #! #! bib #! #! The name of a bibliography file, in BibTeX or XML format. #! If this key is not set, but there is a file doc/PACKAGENAME.bib #! then it is assumed that you want to use this as your bibliography. #! #! #! entities #! #! A record whose keys are taken as entity names, set to the corresponding #! (string) values. For example, if you pass the record SomePackage, #!

SomePackage", #! RELEASEYEAR := "2015" )]]> #! then the following entity definitions are added to the XML preamble: #! SomePackage'> #! ]]> #! This allows you to write &SomePackage; and &RELEASEYEAR; #! in your documentation, which will be replaced by respective values specified #! in the entities definition. #! #! #! TitlePage #! #! A record whose entries are used to embellish the generated title page #! for the package manual with extra information, such as a copyright #! statement or acknowledgments. To this end, the names of the record #! components are used as XML element names, and the values of the #! components are outputted as content of these XML elements. For #! example, you could pass the following record to set a custom #! acknowledgements text: #! #! For a list of valid entries in the title page, please refer to the #! &GAPDoc; manual, specifically section . #! #! MainPage #! #! If scaffolding is enabled, by default a main XML file is generated (this #! is the file which contains the XML doctype and more). If you do not #! want this (e.g. because you have a handwritten main XML file), but #! still want &AutoDoc; to generate a title page for you, you can set this #! option to false #! #! document_class #! #! Sets the document class of the resulting PDF. The value can either be a string #! which has to be the name of the new document class, a list containing this string, or #! a list of two strings. Then the first one has to be the document class name, the second one #! the option string ( contained in [ ] ) in &LaTeX;. #! #! latex_header_file #! #! Replaces the standard header from &GAPDoc; completely with the header in this &LaTeX; file. #! Please be careful here, and look at &GAPDoc;'s latexheader.tex file for an example. #! #! #! #! #! #! #! autodoc #! #! This controls whether and how to generate additional XML documentation files #! by scanning for &AutoDoc; documentation comments. #!

#! The value should be either true, false or a #! record. If it is a record or true (the latter is #! equivalent to specifying an empty record), then this feature is #! enabled. It is also enabled if opt.autodoc is missing but the #! package depends (directly) on the &AutoDoc; package. #! In all other cases (in particular if opt.autodoc is #! false), this feature is disabled. #!

#! #! If opt.autodoc is a record, it may contain the following entries. #! #! #! #! files #! #! A list of files (given by paths relative to the package directory) #! to be scanned for &AutoDoc; documentation comments. #! Usually it is more convenient to use autodoc.scan_dirs, see below. #! #! #! scan_dirs #! #! A list of subdirectories of the package directory (given as relative paths) #! which &AutoDoc; then scans for .gi, .gd, .g, and .autodoc files; all of these files #! are then scanned for &AutoDoc; documentation comments. #!
#! Default value: [ ".", "gap", "lib", "examples", "examples/doc" ]. #!
#! #! level #! #! This defines the level of the created documentation. The default value is 0. #! When parts of the manual are declared with a higher value #! they will not be printed into the manual. #! #! #### TODO: Document section_intros later on. #### However, note that thanks to the new AutoDoc comment syntax, the only remaining #### use for this seems to be the ability to specify the order of chapters and #### sections. #### section_intros #### #### TODO. #### #! #!
#! #! #! #! gapdoc #! #! This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text #! files from your various XML files. #!

#! The value should be either true, false or a #! record. If it is a record or true (the latter is #! equivalent to specifying an empty record), then this feature is #! enabled. It is also enabled if opt.gapdoc is missing. #! In all other cases (in particular if opt.gapdoc is #! false), this feature is disabled. #!

#! #! If opt.gapdoc is a record, it may contain the following entries. #! #! #! #! #### Note: 'main' is strictly speaking also used for the scaffold. #### However, if one uses the scaffolding mechanism, then it is not #### really necessary to specify a custom name for the main XML file. #### Thus, the purpose of this parameter is to cater for packages #### that have existing documentation using a different XML name, #### and which do not wish to use scaffolding. #### #### This explains why we only allow specifying gapdoc.main. #### The scaffolding code will still honor it, though, just in case. #! main #! #! The name of the main XML file of the package manual. #! This exists primarily to support packages with existing manual #! which use a filename here which differs from the default. #! In particular, specifying this is unnecessary when using scaffolding. #!
#! Default value: PACKAGENAME.xml. #!
#! #! files #! #! A list of files (given by paths relative to the package directory) #! to be scanned for &GAPDoc; documentation comments. #! Usually it is more convenient to use gapdoc.scan_dirs, see below. #! #! #! scan_dirs #! #! A list of subdirectories of the package directory (given as relative paths) #! which &AutoDoc; then scans for .gi, .gd and .g files; all of these files #! are then scanned for &GAPDoc; documentation comments. #!
#! Default value: [ ".", "gap", "lib", "examples", "examples/doc" ]. #!
#! #! LaTeXOptions #! #! Must be a record with entries which can be understood by #! . Each entry can be a #! string, which will be given to &GAPDoc; directly, or a list containing of #! two entries: The first one must be the string "file", the second one a #! filename. This file will be read and then its content is passed to &GAPDoc; #! as option with the name of the entry. #! #! #! gap_root_relative_path #! #! Either a boolean, or a string containing a relative path. #! By default (if this option is not set, or is set to false), #! references in the generated documentation referring to external documentation #! (such as the &GAP; manual) are encoded using absolute paths. #! This is fine as long as the documentation stays on only a single #! computer, but is problematic when preparing documentation that should be #! used on multiple computers, e.g., when creating a distribution archive of #! a &GAP; package.
#! Thus, if a relative path is provided via this option (or if it is set to true, #! in which case the relative path ../../.. is used), then &AutoDoc; #! and &GAPDoc; attempt to replace all absolute paths in references to &GAP; #! manuals by paths based on this relative path.

#! #! On a technical level, &AutoDoc; passes the relative path to the #! gaproot parameter of

#! #! #! #! #! extract_examples #! #! Either true or a record. #! If set to true, then all manual examples are extracted and placed #! into files tst/PACKAGENAME01.tst, tst/PACKAGENAME02.tst, ... #! and so on, with one file for each chapter. For chapters with no examples, #! no file is created.

#! As a record, the entry can have the following entries itself, to specify some options. #! #! units #! #! This controls how examples are grouped into files. Recognized values are #! "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value, #! one file is created for each chapter, each section, each subsection or each example. #! For all other values only a single file is created. #! #! On a technical level, &AutoDoc; passes the value to the #! units parameter of . #! #! skip_empty_in_numbering #! #! If set to true (the default), the generated files use #! filenames with strictly sequential numbering; that means that #! if chapter 1 (or whatever units are being used) contains no #! examples but chapter 2 does, then the examples for chapter 2 #! are put into the file tst/PACKAGENAME01.tst. If this #! option is set to false, then the chapter numbers are #! used to generate the filenames; so the examples for chapter 2 #! would be put into the file tst/PACKAGENAME02.tst. #! #! #! #! maketest #! #! This option is deprecated. Please use extract_examples instead. #!

#! Either true or a record. When it is true, #! a simple maketest.g file is created in the main package directory, #! which can be used to test the examples from the manual. As a record, #! the entry can have the following entries itself, to specify some options. #! #! filename #! #! Sets the name of the test file. #! #! commands #! #! A list of strings, each one a command, which #! will be executed at the beginning of the test file. #! #! #! #! #! #! #! #! #! @Returns nothing #! @Arguments [packageOrDirectory], [optrec] DeclareGlobalFunction( "AutoDoc" ); #! @Section Examples #! #! Some basic examples for using AutoDoc were already shown in #! Chapter . AutoDoc-2023.06.19/gap/Parser.gi000644 000766 000024 00000121174 14444021247 016277 0ustar00mhornstaff000000 000000 # AutoDoc: Generate documentation from GAP source code # # Copyright of AutoDoc belongs to its developers. # Please refer to the COPYRIGHT file for details. # # SPDX-License-Identifier: GPL-2.0-or-later ## InstallGlobalFunction( Scan_for_AutoDoc_Part, function( line, plain_text_mode ) local position, whitespace_position, command, argument; #! @DONT_SCAN_NEXT_LINE position := PositionSublist( line, "#!" ); if position = fail and plain_text_mode = false then return [ false, line ]; fi; if plain_text_mode <> true then line := StripBeginEnd( line{[ position + 2 .. Length( line ) ]}, " " ); fi; ## Scan for a command position := PositionSublist( line, "@" ); if position = fail then return [ "STRING", line ]; fi; whitespace_position := PositionSublist( line, " " ); if whitespace_position = fail then command := line{[ position .. Length( line ) ]}; argument := ""; else command := line{[ position .. whitespace_position - 1 ]}; argument := line{[ whitespace_position + 1 .. Length( line ) ]}; fi; return [ command, argument ]; end ); ## Scans a string for after appeared. ## This is necessary to scan the filter list for method declarations ## that contain \[\]. BindGlobal( "AUTODOC_PositionElementIfNotAfter", function( list, element, element_not_before_element ) local current_pos; if not IsList( list ) then Error( " must be a list" ); fi; if Length( list ) > 0 and list[ 1 ] = element then return 1; fi; for current_pos in [ 2 .. Length( list ) ] do if list[ current_pos ] = element and list[ current_pos - 1 ] <> element_not_before_element then return current_pos; fi; od; return fail; end ); BindGlobal( "AutoDoc_PrintWarningForConstructor", AutoDoc_CreatePrintOnceFunction( "Installed GAPDoc version does not support constructors" ) ); ## InstallGlobalFunction( AutoDoc_Type_Of_Item, function( current_item, type, default_chapter_data ) local item_rec, entries, has_filters, ret_val; item_rec := current_item; if PositionSublist( type, "DeclareCategoryCollections") <> fail then entries := [ "Filt", "categories" ]; ret_val := "true or false"; has_filters := "No"; if not IsBound( item_rec!.arguments ) then item_rec!.arguments := "obj"; fi; item_rec!.coll_suffix := true; elif PositionSublist( type, "DeclareCategory" ) <> fail then entries := [ "Filt", "categories" ]; ret_val := "true or false"; has_filters := 1; elif PositionSublist( type, "DeclareRepresentation" ) <> fail then entries := [ "Filt", "categories" ]; ret_val := "true or false"; has_filters := 1; elif PositionSublist( type, "DeclareAttribute" ) <> fail then entries := [ "Attr", "attributes" ]; has_filters := 1; elif PositionSublist( type, "DeclareProperty" ) <> fail then entries := [ "Prop", "properties" ]; ret_val := "true or false"; has_filters := 1; elif PositionSublist( type, "DeclareOperation" ) <> fail then entries := [ "Oper", "methods" ]; has_filters := "List"; elif PositionSublist( type, "DeclareConstructor" ) <> fail then if IsPackageMarkedForLoading( "GAPDoc", ">=1.6.1" ) then entries := [ "Constr", "methods" ]; else AutoDoc_PrintWarningForConstructor(); entries := [ "Oper", "methods" ]; fi; has_filters := "List"; elif PositionSublist( type, "DeclareGlobalFunction" ) <> fail then entries := [ "Func", "global_functions" ]; has_filters := "No"; if not IsBound( item_rec!.arguments ) then item_rec!.arguments := "arg"; fi; elif PositionSublist( type, "DeclareGlobalVariable" ) <> fail then entries := [ "Var", "global_variables" ]; has_filters := "No"; item_rec!.arguments := fail; item_rec!.return_value := false; elif PositionSublist( type, "DeclareGlobalName" ) <> fail then entries := [ "Var", "global_variables" ]; has_filters := "No"; item_rec!.arguments := fail; item_rec!.return_value := false; elif PositionSublist( type, "DeclareFilter" ) <> fail then entries := [ "Filt", "properties" ]; has_filters := "No"; item_rec!.arguments := fail; item_rec!.return_value := false; elif PositionSublist( type, "DeclareInfoClass" ) <> fail then entries := [ "InfoClass", "info_classes" ]; has_filters := "No"; item_rec!.arguments := fail; item_rec!.return_value := false; elif PositionSublist( type, "KeyDependentOperation" ) <> fail then entries := [ "Oper", "methods" ]; has_filters := 2; else return fail; fi; item_rec!.item_type := entries[ 1 ]; if not IsBound( item_rec!.chapter_info ) or item_rec!.chapter_info = [ ] then item_rec!.chapter_info := default_chapter_data.( entries[ 2 ] ); fi; if IsBound( ret_val ) and ( item_rec!.return_value = [ ] or item_rec!.return_value = false ) then item_rec!.return_value := [ ret_val ]; fi; return has_filters; end ); ## InstallGlobalFunction( AutoDoc_Parser_ReadFiles, function( filename_list, tree, default_chapter_data ) local current_item, flush_and_recover, chapter_info, current_string_list, Scan_for_Declaration_part, flush_and_prepare_for_item, current_line, filestream, level_scope, scope_group, read_example, command_function_record, autodoc_read_line, current_command, was_declaration, filename, system_scope, groupnumber, rest_of_file_skipped, context_stack, new_man_item, add_man_item, Reset, read_code, title_item, title_item_list, plain_text_mode, current_line_unedited, deprecated, ReadLineWithLineCount, Normalized_ReadLine, line_number, ErrorWithPos, create_title_item_function, current_line_positition_for_filter, read_session_example; groupnumber := 0; level_scope := 0; autodoc_read_line := false; context_stack := [ ]; chapter_info := [ ]; line_number := 0; ReadLineWithLineCount := function( stream ) line_number := line_number + 1; return ReadLine( stream ); end; Normalized_ReadLine := function( stream ) local string; string := ReadLineWithLineCount( stream ); if string = fail then return fail; fi; NormalizeWhitespace( string ); return string; end; ErrorWithPos := function(arg) local list; list := Concatenation(arg, [ ",\n", "at ", filename, ":", line_number]); CallFuncList(Error, list); end; new_man_item := function( ) local man_item; if IsBound( current_item ) and IsTreeForDocumentationNodeForManItemRep( current_item ) then return current_item; fi; # implicitly end any subsection if IsBound( chapter_info[ 3 ] ) then Unbind( chapter_info[ 3 ] ); current_item := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); fi; if IsBound( current_item ) then Add( context_stack, current_item ); fi; man_item := DocumentationManItem( tree ); if IsBound( scope_group ) then SetGroupName( man_item, scope_group ); fi; man_item!.chapter_info := ShallowCopy( chapter_info ); man_item!.tester_names := fail; return man_item; end; add_man_item := function( ) local man_item; man_item := current_item; if context_stack <> [ ] then current_item := Remove( context_stack ); else Unbind( current_item ); fi; if IsBound( man_item!.chapter_info ) then SetChapterInfo( man_item, man_item!.chapter_info ); fi; if Length( ChapterInfo( man_item ) ) <> 2 then ErrorWithPos( "declarations must be documented within a section" ); fi; Add( tree, man_item ); end; Reset := function( ) chapter_info := [ ]; context_stack := [ ]; Unbind( current_item ); plain_text_mode := false; end; Scan_for_Declaration_part := function() local declare_position, current_type, filter_string, has_filters, position_parenthesis, nr_of_attr_loops, i; ## fail is bigger than every integer declare_position := Minimum( [ PositionSublist( current_line, "Declare" ), PositionSublist( current_line, "KeyDependentOperation" ) ] ); if declare_position <> fail then current_item := new_man_item(); current_line := current_line{[ declare_position .. Length( current_line ) ]}; position_parenthesis := PositionSublist( current_line, "(" ); if position_parenthesis = fail then ErrorWithPos( "Something went wrong" ); fi; current_type := current_line{ [ 1 .. position_parenthesis - 1 ] }; has_filters := AutoDoc_Type_Of_Item( current_item, current_type, default_chapter_data ); if has_filters = fail then ErrorWithPos( "Unrecognized scan type" ); return false; fi; current_line := current_line{ [ position_parenthesis + 1 .. Length( current_line ) ] }; ## Now the funny part begins: ## try fetching the name: ## Assuming the name is in the same line as its while PositionSublist( current_line, "," ) = fail and PositionSublist( current_line, ");" ) = fail do current_line := Normalized_ReadLine( filestream ); od; current_line := StripBeginEnd( current_line, " " ); current_item!.name := current_line{ [ 1 .. Minimum( [ PositionSublist( current_line, "," ), PositionSublist( current_line, ");" ) ] ) - 1 ] }; current_item!.name := StripBeginEnd( ReplacedString( current_item!.name, "\"", "" ), " " ); # Deal with DeclareCategoryCollections: this has some special # rules on how the name of a new category is derived from the # string given to it. Since the code for that is not available in # a separate GAP function, we have to replicate this logic here. # To understand what's going on, please refer to the # DeclareCategoryCollections documentation and implementation. if IsBound(current_item!.coll_suffix) then if EndsWith(current_item!.name, "Collection") then current_item!.name := current_item!.name{[1..Length(current_item!.name)-6]}; fi; if EndsWith(current_item!.name, "Coll") then current_item!.coll_suffix := "Coll"; else current_item!.coll_suffix := "Collection"; fi; current_item!.name := Concatenation(current_item!.name, current_item!.coll_suffix); fi; current_line := current_line{ [ Minimum( [ PositionSublist( current_line, "," ), PositionSublist( current_line, ");" ) ] ) + 1 .. Length( current_line ) ] }; filter_string := "for "; ## FIXME: The next two if's can be merged at some point if IsInt( has_filters ) then for i in [ 1 .. has_filters ] do ## We now search for the filters. A filter is either followed by a ',', if there is more than one, ## or by ');' if it is the only or last one. So we search for the next delimiter. while PositionSublist( current_line, "," ) = fail and PositionSublist( current_line, ");" ) = fail do Append( filter_string, StripBeginEnd( current_line, " " ) ); current_line := ReadLineWithLineCount( filestream ); NormalizeWhitespace( current_line ); od; current_line_positition_for_filter := Minimum( [ PositionSublist( current_line, "," ), PositionSublist( current_line, ");" ) ] ) - 1; Append( filter_string, StripBeginEnd( current_line{ [ 1 .. current_line_positition_for_filter ] }, " " ) ); current_line := current_line{[ current_line_positition_for_filter + 1 .. Length( current_line ) ]}; if current_line[ 1 ] = ',' then current_line := current_line{[ 2 .. Length( current_line ) ]}; elif current_line[ 1 ] = ')' then current_line := current_line{[ 3 .. Length( current_line ) ]}; fi; ## FIXME: Refactor this whole if IsInt( has_filters ) case! if has_filters - i > 0 then Append( filter_string, ", " ); fi; od; elif has_filters = "List" then while AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ) = fail do current_line := ReadLineWithLineCount( filestream ); NormalizeWhitespace( current_line ); od; current_line := current_line{ [ AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ) + 1 .. Length( current_line ) ] }; while AUTODOC_PositionElementIfNotAfter( current_line, ']', '\\' ) = fail do Append( filter_string, StripBeginEnd( current_line, " " ) ); current_line := ReadLineWithLineCount( filestream ); NormalizeWhitespace( current_line ); od; Append( filter_string, StripBeginEnd( current_line{[ 1 .. AUTODOC_PositionElementIfNotAfter( current_line, ']', '\\' ) - 1 ]}, " " ) ); else filter_string := false; fi; if IsString( filter_string ) then filter_string := ReplacedString( filter_string, "\"", "" ); fi; if filter_string <> false then if current_item!.tester_names = fail and StripBeginEnd( filter_string, " " ) <> "for" then current_item!.tester_names := filter_string; fi; if StripBeginEnd( filter_string, " " ) = "for" then has_filters := "empty_argument_list"; fi; ##Adjust arguments if not IsBound( current_item!.arguments ) then if IsInt( has_filters ) then if has_filters = 1 then current_item!.arguments := "arg"; else current_item!.arguments := JoinStringsWithSeparator( List( [ 1 .. has_filters ], i -> Concatenation( "arg", String( i ) ) ), "," ); fi; elif has_filters = "List" then current_item!.arguments := List( [ 1 .. Length( SplitString( filter_string, "," ) ) ], i -> Concatenation( "arg", String( i ) ) ); if Length( current_item!.arguments ) = 1 then current_item!.arguments := "arg"; else current_item!.arguments := JoinStringsWithSeparator( current_item!.arguments, "," ); fi; elif has_filters = "empty_argument_list" then current_item!.arguments := ""; fi; fi; fi; add_man_item(); return true; fi; declare_position := Minimum( [ PositionSublist( current_line, "InstallMethod" ), PositionSublist( current_line, "InstallOtherMethod" ) ] ); ## Fail is larger than every integer. if declare_position <> fail then current_item := new_man_item(); current_item!.item_type := "Oper"; ##Find name position_parenthesis := PositionSublist( current_line, "(" ); current_line := current_line{ [ position_parenthesis + 1 .. Length( current_line ) ] }; ## find next colon current_item!.name := ""; while PositionSublist( current_line, "," ) = fail do Append( current_item!.name, current_line ); current_line := Normalized_ReadLine( filestream ); od; position_parenthesis := PositionSublist( current_line, "," ); Append( current_item!.name, current_line{[ 1 .. position_parenthesis - 1 ]} ); NormalizeWhitespace( current_item!.name ); current_item!.name := StripBeginEnd( current_item!.name, " " ); while AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ) = fail do current_line := Normalized_ReadLine( filestream ); od; position_parenthesis := AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ); current_line := current_line{[ position_parenthesis + 1 .. Length( current_line ) ]}; filter_string := "for "; while PositionSublist( current_line, "]" ) = fail do Append( filter_string, current_line ); od; position_parenthesis := AUTODOC_PositionElementIfNotAfter( current_line, ']', '\\' ); Append( filter_string, current_line{[ 1 .. position_parenthesis - 1 ]} ); current_line := current_line{[ position_parenthesis + 1 .. Length( current_line )]}; NormalizeWhitespace( filter_string ); if IsString( filter_string ) then filter_string := ReplacedString( filter_string, "\"", "" ); fi; if current_item!.tester_names = fail then current_item!.tester_names := filter_string; fi; ##Maybe find some argument names if not IsBound( current_item!.arguments ) then while PositionSublist( current_line, "function(" ) = fail and PositionSublist( current_line, ");" ) = fail do current_line := Normalized_ReadLine( filestream ); od; position_parenthesis := PositionSublist( current_line, "function(" ); if position_parenthesis <> fail then current_line := current_line{[ position_parenthesis + 9 .. Length( current_line ) ]}; filter_string := ""; while PositionSublist( current_line, ")" ) = fail do; current_line := StripBeginEnd( current_line, " " ); Append( filter_string, current_line ); current_line := Normalized_ReadLine( current_line ); od; position_parenthesis := PositionSublist( current_line, ")" ); Append( filter_string, current_line{[ 1 .. position_parenthesis - 1 ]} ); NormalizeWhitespace( filter_string ); filter_string := StripBeginEnd( filter_string, " " ); current_item!.arguments := filter_string; fi; fi; if not IsBound( current_item!.arguments ) then current_item!.arguments := Length( SplitString( current_item!.tester_names, "," ) ); current_item!.arguments := JoinStringsWithSeparator( List( [ 1 .. current_item!.arguments ], i -> Concatenation( "arg", String( i ) ) ), "," ); fi; add_man_item(); return true; fi; return false; end; read_code := function( ) local code, temp_curr_line, comment_pos, before_comment; code := [ "

fail then before_comment := NormalizedWhitespace( temp_curr_line{ [ 1 .. comment_pos - 1 ] } ); if before_comment = "" then temp_curr_line := temp_curr_line{[ comment_pos + 2 .. Length( temp_curr_line ) ]}; fi; fi; fi; if PositionSublist( temp_curr_line, "@EndCode" ) <> fail then break; fi; Add( code, temp_curr_line ); od; Add( code, "]]>\n" ); return code; end; read_example := function( is_tested_example ) local temp_string_list, temp_curr_line, temp_pos_comment, is_following_line, item_temp, example_node; example_node := DocumentationExample( tree ); example_node!.is_tested_example := is_tested_example; temp_string_list := example_node!.content; is_following_line := false; while true do temp_curr_line := Chomp( ReadLineWithLineCount( filestream ) ); if PositionSublist( temp_curr_line, "@EndExample" ) <> fail or PositionSublist( temp_curr_line, "@EndLog" ) <> fail then break; fi; ##if is comment, simply remove comments. #! @DONT_SCAN_NEXT_LINE temp_pos_comment := PositionSublist( temp_curr_line, "#!" ); if temp_pos_comment <> fail then temp_curr_line := temp_curr_line{[ temp_pos_comment + 3 .. Length( temp_curr_line ) ]}; Add( temp_string_list, temp_curr_line ); is_following_line := false; continue; else if is_following_line then temp_curr_line := Concatenation( "> ", temp_curr_line ); if PositionSublist( temp_curr_line, ";" ) <> fail then is_following_line := false; fi; else if temp_curr_line = "" then continue; fi; temp_curr_line := Concatenation( "gap> ", temp_curr_line ); is_following_line := PositionSublist( temp_curr_line, ";" ) = fail; fi; Add( temp_string_list, temp_curr_line ); continue; fi; od; return example_node; end; read_session_example := function( is_tested_example, plain_text_mode ) local temp_string_list, temp_curr_line, temp_pos_comment, is_following_line, item_temp, example_node, incorporate_this_line; example_node := DocumentationExample( tree ); example_node!.is_tested_example := is_tested_example; temp_string_list := example_node!.content; while true do temp_curr_line := Chomp( ReadLineWithLineCount( filestream ) ); if PositionSublist( temp_curr_line, "@EndExampleSession" ) <> fail or PositionSublist( temp_curr_line, "@EndLogSession" ) <> fail then break; fi; incorporate_this_line := plain_text_mode; if not plain_text_mode then #! @DONT_SCAN_NEXT_LINE temp_pos_comment := PositionSublist( temp_curr_line, "#!" ); if temp_pos_comment <> fail then incorporate_this_line := true; temp_curr_line := temp_curr_line{[ temp_pos_comment + 2 .. Length( temp_curr_line ) ]}; if Length( temp_curr_line ) >= 1 and temp_curr_line[ 1 ] = ' ' then Remove( temp_curr_line, 1 ); fi; fi; fi; if incorporate_this_line then Add( temp_string_list, temp_curr_line ); fi; od; return example_node; end; deprecated := function(name, f) return function(args...) Info(InfoWarning, 1, TextAttr.1, "WARNING: ----------------------------------------------------------------------------", TextAttr.reset); Info(InfoWarning, 1, TextAttr.1, "WARNING: ", name, " is deprecated; please refer to the AutoDoc manual for details", TextAttr.reset); Info(InfoWarning, 1, TextAttr.1, "WARNING: ----------------------------------------------------------------------------", TextAttr.reset); f(); end; end; command_function_record := rec( ## HACK: Needed for AutoDoc parser to be scanned safely. ## The lines where the AutoDoc comments are ## searched cause problems otherwise. @DONT_SCAN_NEXT_LINE := function() ReadLineWithLineCount( filestream ); end, @DoNotReadRestOfFile := function() Reset(); rest_of_file_skipped := true; end, @BeginAutoDoc := deprecated("@BeginAutoDoc", function() autodoc_read_line := fail; end), @AutoDoc := ~.@BeginAutoDoc, @EndAutoDoc := deprecated("@EndAutoDoc", function() autodoc_read_line := false; end), @Chapter := function() local scope_chapter; scope_chapter := ReplacedString( current_command[ 2 ], " ", "_" ); current_item := ChapterInTree( tree, scope_chapter ); chapter_info[ 1 ] := scope_chapter; end, @ChapterLabel := function() local scope_chapter, label_name; if not IsBound( chapter_info[ 1 ] ) then ErrorWithPos( "found @ChapterLabel with no active chapter" ); fi; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); scope_chapter := ChapterInTree( tree, chapter_info[ 1 ] ); scope_chapter!.additional_label := Concatenation( "Chapter_", label_name ); end, @ChapterTitle := function() local scope_chapter; if not IsBound( chapter_info[ 1 ] ) then ErrorWithPos( "found @ChapterTitle with no active chapter" ); fi; scope_chapter := ChapterInTree( tree, chapter_info[ 1 ] ); scope_chapter!.title_string := current_command[ 2 ]; end, @Section := function() local scope_section; if not IsBound( chapter_info[ 1 ] ) then ErrorWithPos( "found @Section with no active chapter" ); fi; scope_section := ReplacedString( current_command[ 2 ], " ", "_" ); current_item := SectionInTree( tree, chapter_info[ 1 ], scope_section ); Unbind( chapter_info[ 3 ] ); chapter_info[ 2 ] := scope_section; end, @SectionLabel := function() local scope_section, label_name; if not IsBound( chapter_info[ 2 ] ) then ErrorWithPos( "found @SectionLabel with no active section" ); fi; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); scope_section := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); scope_section!.additional_label := Concatenation( "Section_", label_name ); end, @SectionTitle := function() local scope_section; if not IsBound( chapter_info[ 2 ] ) then ErrorWithPos( "found @SectionTitle with no active section" ); fi; scope_section := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); scope_section!.title_string := current_command[ 2 ]; end, @EndSection := deprecated("@EndSection", function() if not IsBound( chapter_info[ 2 ] ) then ErrorWithPos( "found @EndSection with no active section" ); fi; Unbind( chapter_info[ 2 ] ); Unbind( chapter_info[ 3 ] ); current_item := ChapterInTree( tree, chapter_info[ 1 ] ); end), @Subsection := function() local scope_subsection; if not IsBound( chapter_info[ 1 ] ) or not IsBound( chapter_info[ 2 ] ) then ErrorWithPos( "found @Subsection with no active section" ); fi; scope_subsection := ReplacedString( current_command[ 2 ], " ", "_" ); current_item := SubsectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ], scope_subsection ); chapter_info[ 3 ] := scope_subsection; end, @SubsectionLabel := function() local scope_subsection, label_name; if not IsBound( chapter_info[ 3 ] ) then ErrorWithPos( "found @SubsectionLabel with no active subsection" ); fi; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); scope_subsection := SubsectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ], chapter_info[ 3 ] ); scope_subsection!.additional_label := Concatenation( "Subsection_", label_name ); end, @SubsectionTitle := function() local scope_subsection; if not IsBound( chapter_info[ 3 ] ) then ErrorWithPos( "found @SubsectionTitle with no active subsection" ); fi; scope_subsection := SubsectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ], chapter_info[ 3 ] ); scope_subsection!.title_string := current_command[ 2 ]; end, @EndSubsection := deprecated("@EndSubsection", function() if not IsBound( chapter_info[ 3 ] ) then ErrorWithPos( "found @EndSubsection with no active subsection" ); fi; Unbind( chapter_info[ 3 ] ); current_item := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); end), @BeginGroup := function() local grp; if current_command[ 2 ] = "" then groupnumber := groupnumber + 1; current_command[ 2 ] := Concatenation( "AutoDoc_generated_group", String( groupnumber ) ); fi; scope_group := ReplacedString( current_command[ 2 ], " ", "_" ); end, @EndGroup := function() Unbind( scope_group ); end, @Description := function() current_item := new_man_item(); SetManItemToDescription( current_item ); NormalizeWhitespace( current_command[ 2 ] ); if current_command[ 2 ] <> "" then Add( current_item, current_command[ 2 ] ); fi; end, @Returns := function() current_item := new_man_item(); SetManItemToReturnValue( current_item ); if current_command[ 2 ] <> "" then Add( current_item, current_command[ 2 ] ); fi; end, @Arguments := function() current_item := new_man_item(); current_item!.arguments := current_command[ 2 ]; end, @Label := function() current_item := new_man_item(); current_item!.tester_names := current_command[ 2 ]; end, @Group := function() local group_name; current_item := new_man_item(); group_name := ReplacedString( current_command[ 2 ], " ", "_" ); SetGroupName( current_item, group_name ); end, @GroupTitle := function() local group_name, chap_info, group_obj; current_item := new_man_item(); if not HasGroupName( current_item ) then ErrorWithPos( "found @GroupTitle with no Group set" ); fi; group_name := GroupName( current_item ); chap_info := fail; if HasChapterInfo( current_item ) then chap_info := ChapterInfo( current_item ); elif IsBound( current_item!.chapter_info ) then chap_info := current_item!.chapter_info; fi; if chap_info = fail or Length( chap_info ) = 0 then chap_info := chapter_info; fi; if Length( chap_info ) <> 2 then ErrorWithPos( "can only set @GroupTitle within a Chapter and Section."); fi; group_obj := DocumentationGroup( tree, group_name, chap_info ); group_obj!.title_string := current_command[ 2 ]; end, @ChapterInfo := function() local current_chapter_info; current_item := new_man_item(); current_chapter_info := SplitString( current_command[ 2 ], "," ); current_chapter_info := List( current_chapter_info, i -> ReplacedString( StripBeginEnd( i, " " ), " ", "_" ) ); SetChapterInfo( current_item, current_chapter_info ); end, @BREAK := function() ErrorWithPos( current_command[ 2 ] ); end, @SetLevel := function() level_scope := Int( current_command[ 2 ] ); end, @ResetLevel := function() level_scope := 0; end, @Level := function() current_item!.level := Int( current_command[ 2 ] ); end, @InsertChunk := function() local label_name; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); Add( current_item, DocumentationChunk( tree, label_name ) ); end, @BeginChunk := function() local label_name; if IsBound( current_item ) then Add( context_stack, current_item ); fi; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); current_item := DocumentationChunk( tree, label_name ); end, @Chunk := ~.@BeginChunk, @EndChunk := function() if autodoc_read_line = true then autodoc_read_line := false; fi; if context_stack <> [ ] then current_item := Remove( context_stack ); else Unbind( current_item ); fi; end, @InsertSystem := deprecated("@InsertSystem", ~.@InsertChunk), @System := deprecated("@System", ~.@BeginChunk), @BeginSystem := ~.@System, @EndSystem := deprecated("@EndSystem", ~.@EndChunk), @BeginCode := function() local label_name, tmp_system; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); tmp_system := DocumentationChunk( tree, label_name ); Append( tmp_system!.content, read_code() ); end, @Code := ~.@BeginCode, @InsertCode := ~.@InsertChunk, @BeginExample := function() local example_node; example_node := read_example( true ); Add( current_item, example_node ); end, @Example := ~.@BeginExample, @BeginLog := function() local example_node; example_node := read_example( false ); Add( current_item, example_node ); end, @Log := ~.@BeginLog, STRING := function() local comment_pos; if not IsBound( current_item ) then return; fi; comment_pos := PositionSublist( current_line_unedited, "#!" ); if comment_pos <> fail then current_line_unedited := current_line_unedited{[ comment_pos + 2 .. Length( current_line_unedited ) ]}; fi; Add( current_item, current_line_unedited ); end, @BeginLatexOnly := function() Add( current_item, " "" then Add( current_item, current_command[ 2 ] ); fi; end, @EndLatexOnly := function() if autodoc_read_line = true then autodoc_read_line := false; fi; Add( current_item, "]]>" ); end, @LatexOnly := function() Add( current_item, "" ); end, @BeginNotLatex := function() Add( current_item, " "" then Add( current_item, current_command[ 2 ] ); fi; end, @EndNotLatex := function() if autodoc_read_line = true then autodoc_read_line := false; fi; Add( current_item, "]]>" ); end, @NotLatex := function() Add( current_item, "" ); end, @Dependency := function() if not IsBound( tree!.worksheet_dependencies ) then tree!.worksheet_dependencies := [ ]; fi; NormalizeWhitespace( current_command[ 2 ] ); Add( tree!.worksheet_dependencies, SplitString( current_command[ 2 ], " " ) ); end, @BeginAutoDocPlainText := deprecated("@BeginAutoDocPlainText", function() plain_text_mode := true; end), @AutoDocPlainText := ~.@BeginAutoDocPlainText, @EndAutoDocPlainText := deprecated("@EndAutoDocPlainText", function() plain_text_mode := false; end), @ExampleSession := function() local example_node; example_node := read_session_example( true, plain_text_mode ); Add( current_item, example_node ); end, @BeginExampleSession := ~.@ExampleSession, @LogSession := function() local example_node; example_node := read_session_example( false, plain_text_mode ); Add( current_item, example_node ); end, @BeginLogSession := ~.@LogSession ); ## The following commands are specific for worksheets. They do not have a packageinfo, ## and no place to extract those infos. So these commands are needed to make insert the ## information directly into the document. title_item_list := [ "Title", "Subtitle", "Version", "TitleComment", "Author", "Date", "Address", "Abstract", "Copyright", "Acknowledgements", "Colophon" ]; create_title_item_function := function( name ) return function() if not IsBound( tree!.TitlePage.( name ) ) then tree!.TitlePage.( name ) := [ ]; fi; current_item := tree!.TitlePage.( name ); Add( current_item, current_command[ 2 ] ); end; end; ## Note that we need to create these functions in the helper function ## create_title_item_function to ensure that the variable is bound properly. ## Without this intermediate helper, the wrong closure is taken, ## and later, when the function is executed, the value for will be the last ## value had, i.e., the last entry of . for title_item in title_item_list do command_function_record.( Concatenation( "@", title_item ) ) := create_title_item_function( title_item ); od; rest_of_file_skipped := false; ##Now read the files. for filename in filename_list do Reset(); ## FIXME: Is this dangerous? if PositionSublist( filename, ".autodoc" ) <> fail then plain_text_mode := true; fi; filestream := InputTextFile( filename ); if filestream = fail then Error( "could not open ", filename ); fi; line_number := 0; while true do if rest_of_file_skipped = true then rest_of_file_skipped := false; break; fi; current_line := ReadLineWithLineCount( filestream ); if current_line = fail then break; fi; current_line_unedited := ShallowCopy( current_line ); NormalizeWhitespace( current_line ); current_command := Scan_for_AutoDoc_Part( current_line, plain_text_mode ); if current_command[ 1 ] <> false then if autodoc_read_line <> fail then autodoc_read_line := true; fi; if not IsBound( command_function_record.(current_command[ 1 ]) ) then ErrorWithPos("unknown AutoDoc command ", current_command[ 1 ]); fi; command_function_record.(current_command[ 1 ])(); continue; fi; current_line := current_command[ 2 ]; if autodoc_read_line = true or autodoc_read_line = fail then was_declaration := Scan_for_Declaration_part( ); if not was_declaration and autodoc_read_line <> fail then autodoc_read_line := false; fi; fi; od; CloseStream( filestream ); od; end );