AutoDoc-2026.05.03/0000755000000000000000000000000015175510000010367 5ustar00AutoDoc-2026.05.03/.mailmap0000644000000000000000000000013015175510000012002 0ustar00Sebastian Gutsche AutoDoc-2026.05.03/AGENTS.md0000644000000000000000000001035515175510000011676 0ustar00# AGENTS.md This repository contains the GAP package `AutoDoc`. ## AI disclosure Any use of AI tools for preparing code, documentation, tests, commit messages, pull requests, issue comments, or reviews for this repository must be disclosed. Include a brief note saying which AI tool was used and what kind of assistance it provided. Add the AI tool as a Git co-author on all commits created by that tool (e.g. via an `Co-authored-by: ` line). ## Repository layout - `PackageInfo.g`: package metadata, including the current version and manual settings. - `Makefile`: convenience targets for building docs, regenerating fixtures, and running the test suite. - `makedoc.g`: entry point for rebuilding the manual. - `regen_tests.g`: entry point for regenerating test data. - `tst/`: package test suite. Run `tst/testall.g` for the full suite, or a single `.tst` file for one test. - `tst/AutoDocTest/`: minimal GAP package used as a package-context AutoDoc testbed, with its own `Makefile` for common doc and test commands. - `README.md`: top-level package overview. ## Common commands Run all commands from the repository root. ### Build the manual ```sh make doc ``` ### Build the HTML manual only ```sh make html ``` ### Run all tests ```sh make check ``` ### Run one test ```sh gap -q --packagedirs . tst/misc.tst ``` Replace `tst/misc.tst` with any other test file in `tst/` as needed. ### Regenerate the tests ```sh make regen ``` ### Work with `tst/AutoDocTest` Run these commands from inside `tst/AutoDocTest`: ```sh make doc make html make check ``` ## Tests All new features and bug fixes should be accompanied by tests. We have the following test locations: - worksheets `tst/worksheets/*.sheet` which serve as integration tests - some existing fixtures come in pairs, one using XML and one using an `.autodoc` file; if editing one side of an existing `paired-*` fixture (e.g. `paired-examples.sheet`) then usually its partner (here: `paired-examples-autoplain.sheet`) should receive a matching change, unless this is impossible for fundamental reasons (e.g. a feature only exists in one format but not the other), - worksheet tests compare expected output files byte-for-byte, so changes to worksheet input usually also require updating `tst/worksheets/.expected/`, - the manual of the `tst/AutoDocTest` package, including its sources in `tst/AutoDocTest/doc/` as well as the GAP program files with AutoDoc comments inside `tst/AutoDocTest/gap`, also can be used to test features, especially features that don't work well in a worksheet or for other reasons require the context of an actual package. - unit tests in `tst/*.tst` files (often in `tst/misc.tst`, but additional files can be added if needed / sensible) In general prefer integration tests that modify one of the worksheets or package manuals for end-to-end behavior. Regenerate expected output with `make regen` when appropriate. If specifically unit tests are needed for individual functions, these can and should go into a `.tst` file. Temporary test files created from a `.tst` file are acceptable when that is the most direct way to exercise unit-level parser or helper behavior. ## Commit messages and pull requests When writing commit messages, use the title format `component: Brief summary` The title line should not exceed 60 characters. In the body, give a brief prose summary of the purpose of the change. Do not specifically call out added tests, comments, documentation, and similar supporting edits unless that is the main purpose of the change. Do not include the test plan unless it differs from the instructions in this file. If the change fixes one or more issues, add `Fixes #...` at the end of the commit message body, not in the title. Don't write lines into the commit message that are wider than 70 characters. Pull requests should follow the same style: a short summary up top, concise prose describing the change, issue references when applicable, and an explicit AI-disclosure note if AI tools were used. ## Changelog This project keeps a changelog in `CHANGES.md`. Typically new features and bug fixes should get a terse entry there. Changes which only refactor things, change formatting, clean up stuff etc. usually do not have to be mentioned. AutoDoc-2026.05.03/CHANGES.md0000644000000000000000000003643315175510000011772 0ustar00This file describes changes in the AutoDoc package. ## 2026.05.03 - Make `AutoDoc()` infer the package directory from `INPUT_FILENAME()` when called from a `makedoc.g` file outside the package root - Deprecate calling `AutoDoc()` with a package name - Deprecate using GAP global options to pass settings to `AutoDoc()`, suggest using option records instead ## 2026.03.18 - Fix running the test suite via `TestPackage("AutoDoc")` when the current working directory is not the package root ## 2026.03.17 + **Breaking changes** - Remove the nonfunctional `@Level`, `@ResetLevel`, and undocumented alias `@SetLevel` commands. They never affected generated output as documented. Since nobody ever reported issues with them, and since no distributed packages uses them, they probably are simply not in use anywhere. Hence the removal instead of trying to fix this. - Only document the first declaration immediately following an AutoDoc source comment block; later consecutive declarations now require their own `#!` comment block - When documenting an `InstallMethod`, we now use the item type `Meth` instead of `Oper` + **New Features** - Add `nopdf` as a global option, and document the existing `NOPDF` environment variable and `relativePath` global option - Add a sub-option `subdir` for `extract_examples` to place generated `.tst` files in a subdirectory such as `tst/generated` - Add Markdown-style headings `#`/`##`/`###` as aliases for `@Chapter`/`@Section`/`@Subsection` in `.autodoc` files and doc comments - Add `@Appendix` for generating appendix XML from `.autodoc` input - Add support for documenting `DeclareSynonym` and `DeclareSynonymAttr` declarations - Add `@ItemType` to override the type of a declaration, which is especially useful for `DeclareSynonym` or `DeclareGlobalName` - Add fenced code blocks using triple backticks or tildes in Markdown-like text; `@listing`, `@example`, and `@log` info strings select the corresponding GAPDoc element - Add `@Index` command for generating index entries - Allow overriding the LaTeX bibliography style via `scaffold.bibstyle` - In Markdown-like inline backtick code spans, emit `...` for GAP keywords (as returned by `ALL_KEYWORDS()`), otherwise as before `...` - Allow XML-style comments in `.autodoc` files - Scan `autodoc.scan_dirs` and `gapdoc.scan_dirs` recursively so nested source directories are picked up automatically + **Other Changes** - Scaffold-generated package manual main files now default to `_main.xml` instead of `PACKAGENAME.xml`; packages that need a different name can continue to set `gapdoc.main` - Don't insert extra newlines after author names for the PDF title pages (this was a workaround for a GAPDoc issue; hopefully a future GAPDoc release will fix this properly; for details, see ) - Improve `DeclareGlobalName` handling: document it as a variable by default, but switch to a function when `@Arguments` or `@Returns` provides function-style documentation - Ignore trailing blank lines after single-line worksheet title-page commands such as `@Title`, `@Subtitle`, `@Version`, `@Author`, and `@Date`, and trim trailing blank lines from generated title-page content so they no longer leak into filenames or empty author entries - Relax filtering for auto-generated chapter and section labels and chapter XML filenames, preserving more punctuation while still stripping characters that are known to cause trouble - Strip XML-special characters from generated chapter, section, and subsection labels so entity names in headings no longer produce invalid XML - Greatly improve the package manual. - Convert the hand-written manual chapters from XML to `.autodoc` - Fix an unexpected and confusing error when mixing explicit `@Chapter`/`@Section` markup in one file with auto-generated chapter/section placement in another - Fix `InstallMethod` in first line of GAP source file leading to an error - Fix multiline `InstallMethod` parsing for filter lists and multiline `function(...)` argument lists - Make AutoDoc command parsing more robust in plain-text mode when `@Command` does not start at column 1 - Normalize parsed `InstallMethod` names by stripping surrounding quotes, matching `Declare...` handling - Document `InstallMethod` support in declaration comments - Fix legacy list-style `scaffold.entities` handling so it receives the standard default entities and works end-to-end again - Convert Markdown-style math in chapter, section, and subsection headings to the corresponding GAPDoc math markup - Loosen requirements on `@Date` command: this used to allow free form, but in recent versions was restricted to dates of the form YYYY-MM-DD or DD/MM/YYYY; now we again allow any text, but text in those specific formats is still parsed and formatted (e.g. 2026-03-08 as 8 March 2026) - Require `@BeginExample`, `@BeginLog`, `@BeginExampleSession`, and `@BeginLogSession` blocks to use their matching `@End...` markers - Improve parser robustness by reporting clear EOF errors for unterminated declaration headers and filter lists - Make tests work when the package directory is read-only by writing generated test output to temporary directories - Remove `@DONT_SCAN_NEXT_LINE` parser hack and only treat `#!` as an AutoDoc marker at the start of a line (ignoring leading whitespace) - Warn if a chunk is defined (via `@BeginChunk`/`@BeginCode`) but never inserted (via `@InsertChunk`/`@InsertCode`) - Warn if a chunk is inserted (via `@InsertChunk`/`@InsertCode`) but never defined (via `@BeginChunk`/`@BeginCode`) - Expand package-manual fixture coverage for `AutoDoc()` invocation variants and `extract_examples` settings ## 2025.12.19 - Don't replace empty lines in `@BeginCode` blocks by `

` - Fix XML header in generated files (it had a syntax error, which somehow also slips by GAPDoc; so it caused no problems in practice, but the resulting XML was strictly speaking invalid) - Predefine entities `VERSION`, `RELEASEYEAR`, `RELEASEDATE` - Allow specifying scaffold settings *simultaneously* in `PackageInfo.g` and `makedoc.g`; the records are merged, with values from `makedoc.g` taken precedence if e.g. the same entity is defined in both places ## 2025.10.16 - Make handling `Date` in `PackageInfo.g` more strict (previously some malformed variants were accepted to deal with very old packages, but by now all packages are compliant) - Remove a bunch of features that were deprecated since 2019: - `AutoDoc` option `scaffold.gapdoc_latex_options` has been replaced by `gapdoc.LaTeXOptions` - `AutoDoc` option `maketest` has been superseded by `extract_examples` - Various AutoDoc commands were removed (see the manual for replacements) - `@EndSection`, `@EndSubsection` - `@AutoDoc`, `@BeginAutoDoc`, `@EndAutoDoc` - `@System`, `@BeginSystem`, `@EndSystem`, `@InsertSystem` - `@AutoDocPlainText`, `@BeginAutoDocPlainText`, `@EndAutoDocPlainText` ## 2025.05.09 - Add `InfoAutoDoc` info class for messages - Various janitorial changes ## 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-2026.05.03/COPYRIGHT0000644000000000000000000000225315175510000011664 0ustar00AutoDoc: 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-2026 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-2026.05.03/LICENSE0000644000000000000000000003646315175510000011410 0ustar00The 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-2026.05.03/Makefile0000644000000000000000000000103115175510000012022 0ustar00.PHONY: run doc html clean check regen GAP ?= gap GAP_ARGS = -q --quitonbreak --packagedirs "$(abspath .);" # run GAP and load the package run: $(GAP) --packagedirs "$(abspath .);" -c 'LoadPackage("AutoDoc");' doc: $(GAP) $(GAP_ARGS) makedoc.g -c 'QUIT;' html: NOPDF=1 $(GAP) $(GAP_ARGS) makedoc.g -c 'QUIT;' clean: cd doc && rm -f *.{aux,bbl,blg,brf,css,dvi,html,idx,ilg,ind,js,lab,log,out,pdf,pnr,ps,six,tex,toc,txt,xml.bib} _*.xml title.xml check: $(GAP) $(GAP_ARGS) tst/testall.g regen: $(GAP) $(GAP_ARGS) regen_tests.g AutoDoc-2026.05.03/PackageInfo.g0000644000000000000000000001103615175510000012707 0ustar00# 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 := "2026.05.03", 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", GitHubUsername := "fingolfin", 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.11", NeededOtherPackages := [ [ "GAPDoc", ">= 1.6.3" ] ], SuggestedOtherPackages := [ ], ExternalConditions := [], ), AvailabilityTest := ReturnTrue, TestFile := "tst/testall.g", Keywords := [ "Automatic documentation, GAP, GAPDoc" ], AutoDoc := rec( entities := rec( io := "io", PackageName := "PackageName", ), TitlePage := rec( Copyright := Concatenation( "©right; 2012-2026 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-2026.05.03/README.md0000644000000000000000000000252215175510000011647 0ustar00[![CI](https://github.com/gap-packages/AutoDoc/actions/workflows/CI.yml/badge.svg)](https://github.com/gap-packages/AutoDoc/actions/workflows/CI.yml) [![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-2026.05.03/TODO0000644000000000000000000000256215175510000011064 0ustar00 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-2026.05.03/doc/0000755000000000000000000000000015175510000011134 5ustar00AutoDoc-2026.05.03/doc/Comments.autodoc0000644000000000000000000007624415175510000014316 0ustar00@Chapter Comments @ChapterTitle &AutoDoc; documentation comments You can document declarations of global functions and variables, operations, attributes etc. by inserting &AutoDoc; comments into your sources before these declarations. 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: ```@listing #! DeclareOperation( "AnOperation", [ IsList ] ); ``` This will produce a manual entry for the operation AnOperation. For declaration documentation, the associated declaration must appear immediately after the &AutoDoc; comment block. In particular, do not insert other code (such as if false then or assignments) between the comment block and the Declare... statement. This also works for InstallMethod and InstallOtherMethod. In that case, &AutoDoc; uses the installed method's name and filter list to create a manual entry for the implemented item. Inside of &AutoDoc; comments, &AutoDoc; commands starting with @ can be used to control the output &AutoDoc; produces. Any comment line that does not start with an &AutoDoc; command is treated as regular documentation text and may contain (almost) arbitrary &GAPDoc; XML markup, such as ``, ``, ``, and similar tags. This lets you use the normal &GAPDoc; formatting toolbox directly inside &AutoDoc; comments. For example: ```@listing #! @Description #! See for setup details. #! The argument obj must satisfy IsObject. ``` As explained in chapter , you can combine &AutoDoc; comments with hand-written XML and classic &GAPDoc; comments. For practical setup and migration workflows, see chapter . @Section 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: @Subsection @Description descr @SubsectionLabel @Description @Index "@Description" @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. @Subsection @Returns ret_val @SubsectionLabel @Returns @Index "@Returns" @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. @Subsection @Arguments args @SubsectionLabel @Arguments @Index "@Arguments" @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. For DeclareGlobalName, using @Arguments or @Returns also makes &AutoDoc; document the item as a function. This is useful because DeclareGlobalName itself does not reveal whether the name denotes a function or a variable. @Subsection @ItemType kind @SubsectionLabel @ItemType @Index "@ItemType" @ItemType kind Overrides the kind of manual item created for the following declaration or installed method. The supported values are Attr, Cat, Coll, Constr, Fam, Filt, Func, InfoClass, Meth, Oper, Prop, Repr, and Var. The values Cat, Coll, and Repr are &AutoDoc;-specific aliases. They emit Filt entries with the corresponding &GAPDoc; filter type. This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as DeclareAttribute or DeclareProperty, &AutoDoc; already knows the intended type from the declaration itself. It is useful for DeclareGlobalName, because that declaration can refer to either a function or a variable. &AutoDoc; defaults such entries to Var, but switches to Func as soon as @Arguments or @Returns indicates function-style documentation. You can still use @ItemType to override this explicitly. It is useful for DeclareSynonym, because that declaration can document a function synonym or one of several filter-like synonyms. Use @ItemType Filt, Cat, Coll, or Repr to control which kind of filter entry should be emitted. For example: ```@listing #! @ItemType Repr DeclareSynonym( "IsSomethingRep", IsComponentObjectRep ); ``` This makes &AutoDoc; emit a <Filt Type="Representation" .../> manual entry. @Subsection @Group grpname @SubsectionLabel @Group @Index "@Group" @Group grpname Adds the following method to a group with the given name. See section for more information about groups. @Subsection @Label label @SubsectionLabel @Label @Index "@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. ```@listing #! @Label testlabel DeclareProperty( "AProperty", IsObject ); ``` leads to this: ```@listing true or false ``` while ```@listing #! DeclareProperty( "AProperty", IsObject ); ``` leads to this: ```@listing true or false ``` @Subsection @ChapterInfo chapter, section @SubsectionLabel @ChapterInfo @Index "@ChapterInfo" `@ChapterInfo` 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: ```@listing #! @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 ); ``` @Section 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. @Subsection @Chapter name @SubsectionLabel @Chapter @Index "@Chapter" `@Chapter` @Index "@ChapterLabel" `@ChapterLabel` @Index "@ChapterTitle" `@ChapterTitle` 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: ```@listing #! @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., ```@listing #! @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. @Subsection @Appendix name @SubsectionLabel @Appendix @Index "@Appendix" `@Appendix` This is analogous to @Chapter, but generates `Appendix` elements instead of `Chapter` elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in `scaffold.appendix`. Example: ```@listing @Appendix Supplementary material @Section Additional tables ``` @Subsection @Section name @SubsectionLabel @Section @Index "@Section" `@Section` @Index "@SectionLabel" `@SectionLabel` @Index "@SectionTitle" `@SectionTitle` Sets an active section like @Chapter sets an active chapter. The section automatically ends with the next @Section or @Chapter command. ```@listing #! @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. @Subsection @Subsection name @SubsectionLabel @Subsection @Index "@Subsection" `@Subsection` @Index "@SubsectionLabel" `@SubsectionLabel` @Index "@SubsectionTitle" `@SubsectionTitle` 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. ```@listing #! @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. @Subsection @BeginGroup [grpname] @SubsectionLabel @BeginGroup @Index "@BeginGroup" `@BeginGroup` 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. @Subsection @EndGroup @SubsectionLabel @EndGroup @Index "@EndGroup" `@EndGroup` Ends the current group. ```@listing #! @BeginGroup MyGroup #! DeclareAttribute( "GroupedAttribute", IsList ); DeclareOperation( "NonGroupedOperation", [ IsObject ] ); #! DeclareOperation( "GroupedOperation", [ IsList, IsRubbish ] ); #! @EndGroup ``` @Subsection @GroupTitle title @SubsectionLabel @GroupTitle @Index "@GroupTitle" `@GroupTitle` 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. @Subsection @BeginExample and @EndExample @SubsectionLabel @BeginExample @Index "@BeginExample" `@BeginExample` @Index "@EndExample" `@EndExample` @BeginExample marks the start of an example to be put into the manual. It differs from &GAPDoc;'s `` (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: ```@listing #! @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. If you enable extract_examples := true when calling , these examples can also be turned into .tst files (see Section ). @Subsection @BeginExampleSession and @EndExampleSession @SubsectionLabel @BeginExampleSession @Index "@BeginExampleSession" `@BeginExampleSession` @Index "@EndExampleSession" `@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 ). To illustrate this command, consider this input: ```@listing #! @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. @Subsection @BeginLog and @EndLog @SubsectionLabel @BeginLog @Index "@BeginLog" `@BeginLog` @Index "@EndLog" `@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. @Subsection @BeginLogSession and @EndLogSession @SubsectionLabel @BeginLogSession @Index "@BeginLogSession" `@BeginLogSession` @Index "@EndLogSession" `@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 ). The &AutoDoc; command @LogSession is an alias of @BeginLogSession. @Subsection @DoNotReadRestOfFile @SubsectionLabel @DoNotReadRestOfFile @Index "@DoNotReadRestOfFile" `@DoNotReadRestOfFile` Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files. ```@listing #! This will appear in the manual #! @DoNotReadRestOfFile #! This will not appear in the manual. ``` @Subsection @BeginChunk name, @EndChunk, and @InsertChunk name @SubsectionLabel @BeginChunk @Index "@BeginChunk" @BeginChunk name @Index "@EndChunk" `@EndChunk` @Index "@EndChunk" @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. ```@listing #! @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: ```@listing #! @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: ```@listing #! @InsertChunk Example_Symmetric_Group ``` @Subsection @BeginCode name, @EndCode, and @InsertCode name @SubsectionLabel @BeginCode @Index "@BeginCode" @BeginCode name @Index "@EndCode" `@EndCode` @Index "@InsertCode" @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. ```@listing #! @BeginCode Increment i := i + 1; #! @EndCode #! @InsertCode Increment ## Code is inserted here. ``` @Subsection @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly @SubsectionLabel @LatexOnly @Index "@LatexOnly" @LatexOnly text @Index "@BeginLatexOnly" `@BeginLatexOnly` @Index "@EndLatexOnly" `@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. ```@listing #! @BeginLatexOnly #! \include{picture.tex} #! @EndLatexOnly #! @LatexOnly \include{picture.tex} ``` @Subsection @NotLatex text, @BeginNotLatex, and @EndNotLatex @SubsectionLabel @NotLatex @Index "@NotLatex" @NotLatex text @Index "@BeginNotLatex" `@BeginNotLatex` @Index "@EndNotLatex" `@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. ```@listing #! @BeginNotLatex #! For further information see the PDF version of this manual. #! @EndNotLatex #! @NotLatex For further information see the PDF version of this manual. ``` @Subsection @Index key [entry text] @SubsectionLabel @Index @Index "@Index" @Index key [entry text] Adds an index entry to the current documentation text. The command @Index key entry text generates `entry text`. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. @Index "my key" entry text. The entry text is processed like normal documentation text, so markdown-like inline code such as `true` is supported. @Section Title page commands @SectionLabel TitlepageCommands The following commands can be used to add corresponding parts to the title page of a document generated by &AutoDoc;. @Title @Subtitle @Version @TitleComment @Author @Date @Address @Abstract @Copyright @Acknowledgements @Colophon Many of these values can (and for package manuals typically should) be extracted from PackageInfo.g. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful for worksheets created with , since worksheets do not have a PackageInfo.g file from which this information could be extracted. @Section Plain text files @SectionLabel PlainText 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 or one of their subdirectories, are treated as standalone &AutoDoc; input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material. Conceptually, a .autodoc file uses the same parser as &AutoDoc; comments, but without the comment marker. In a .autodoc file, lines do not need to start with #! and in fact usually should not. This makes .autodoc files one convenient way to replace hand-written XML chapters when you prefer &AutoDoc;'s command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and &AutoDoc; itself still uses that style in files such as gap/Magic.gd. For the surrounding workflow, see Chapter . The most important difference from declaration comments is that a plain text file does not document a declaration by adjacency. There is no following Declare... or InstallMethod statement for &AutoDoc; to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration. In practice, this gives the following rule of thumb. Use source comments beginning with #! to document declarations. This is the mode for @Description, @Returns, @Arguments, @Label, @Group, and @ChapterInfo. Use either .autodoc files or source comments for standalone manual structure and prose. Commands such as @Chapter, @Section, @Subsection, grouping commands, examples and logs, chunks and code insertion, @Index, title-page commands, Markdown-style headings, fenced code blocks, and ordinary &GAPDoc; XML markup work in both styles. As a concrete example, the following file can serve as a complete chapter written in .autodoc format. ```@listing @Chapter Test @Section First Section @Subsection First Subsection This text belongs directly to the manual chapter. It can use XML tags such as arg or . @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession @Index "Worksheet Autoplain" Plain worksheet index entry with `true` ``` This is essentially the style used in the worksheet fixture tst/worksheets/autoplain.sheet/plain.autodoc. The same structural commands can also be used inside source comments, for example: ```@listing #! @Chapter Reference #! @Section The AutoDoc() function #! Some introductory text for this section. ``` This source-comment style is still fully supported and is used in gap/Magic.gd. The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include _AutoDocMainFile.xml from the main XML file as described in Chapter , and add one or more .autodoc files via autodoc.files or autodoc.scan_dirs. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged. One caveat is worth keeping in mind. If you want a standalone .autodoc file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue #60 in the AutoDoc issue tracker. So, while .autodoc files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient. @Section Grouping @SectionLabel Groups 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 ```@listing #! @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: ```@listing A family of operations First sentence. Second sentence. Third sentence. ``` @Section Markdown-like formatting of text in &AutoDoc; @SectionLabel MarkdownExtension &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. @Subsection Lists @SubsectionLabel MarkdownExtensionList 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: ```@listing #! 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. @Subsection Math modes @SubsectionLabel MarkdownExtensionMath 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;. ```@listing #! 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. @Subsection Emphasize @SubsectionLabel MarkdownExtensionEmph 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: ```@listing #! **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. @Subsection Inline code @SubsectionLabel MarkdownExtensionInlineCode 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: ```@listing #! Call function `foobar()` at the start. ``` This produces the following output:
Call function foobar() at the start. @Subsection Fenced code blocks @SubsectionLabel MarkdownExtensionFencedCode One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values @listing, @example, and @log select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate `

`. Example: ````@listing #! ```@listing #! if x = 2 then #! Print("1 + 1 = 2 holds, all is good\n"); #! fi; #! ``` #! ~~~@example #! gap> [ 1 .. 3 ] ^ 2; #! [ 1, 4, 9 ] #! ~~~ #! ```@log #! #I some log message #! ``` ```` This produces the following output:
```@listing if x = 2 then Print("1 + 1 = 2 holds, all is good\n"); fi; ``` ~~~@example gap> [ 1 .. 3 ] ^ 2; [ 1, 4, 9 ] ~~~ ```@log #I some log message ``` @Section Deprecated commands @SectionLabel Deprecated The following commands used to be supported, but are not supported anymore. @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 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-2026.05.03/doc/Overview.autodoc0000644000000000000000000000432015175510000014321 0ustar00@Chapter Overview @ChapterTitle What &AutoDoc; offers &AutoDoc; helps you create and maintain package manuals for &GAP;. It is built on top of &GAPDoc; and generates the XML input that &GAPDoc; consumes. So &AutoDoc; complements &GAPDoc; instead of replacing it. The package is designed for a mix and match workflow: you can adopt only the parts that help you today, and add more over time. @Section Core features @SectionLabel Overview:Features - Build package manuals via one reproducible command, usually gap makedoc.g. - Generate and maintain a title page from metadata in PackageInfo.g. - Generate and maintain a main XML file that includes your chapters. - Extract manual examples into .tst files via extract_examples := true. - Document declarations directly in source files via &AutoDoc; comments beginning with #!. - Organize chapter and section text either in source comments or in standalone .autodoc files. - Combine &AutoDoc; comments, classic &GAPDoc; source comments, and hand-written XML chapters in one manual. @Section Adopting &AutoDoc; incrementally @SectionLabel Overview:MixAndMatch You do not have to switch everything at once. Typical adoption paths include: - Use only to rebuild an existing &GAPDoc; manual. - Enable only title-page generation, while keeping your custom main XML. - Keep your existing title page but use generated entities such as &VERSION;, &RELEASEYEAR;, and &RELEASEDATE;. - Add &AutoDoc; comments only for new code, and leave old documentation as-is. - Keep existing XML chapters, or gradually add source comments and .autodoc files where they fit your preferred workflow. - Later, gradually move chapters or source documentation to your preferred style. This flexibility is central: &AutoDoc; should make your current setup better, without forcing a full rewrite first. @Section Where to continue @SectionLabel Overview:WhereNext For practical setup and migration workflows, continue with chapter . For the command reference of documentation comments, including standalone .autodoc files, see chapter . AutoDoc-2026.05.03/doc/Tutorials.autodoc0000644000000000000000000006364315175510000014516 0ustar00@Chapter Tutorials @ChapterTitle Getting started using &AutoDoc; This chapter gives practical workflows for adding &AutoDoc; to a package. For a high-level feature overview and adoption strategy, see chapter . @Section Choose your workflow @SectionLabel Tut:ChooseWorkflow You can use &AutoDoc; in several ways, and it is fine to combine them: - Start a new package manual from scratch (Section ). - Integrate &AutoDoc; into an existing &GAPDoc; manual (Section ). - Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged. This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful. @Section Creating a package manual from scratch @SectionLabel Tut: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: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); ``` When called from a file such as makedoc.g, &AutoDoc; uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the PackageInfo.g file from that package directory. It extracts information about the package from it (such as its name and version, see Section ). It then creates two XML files doc/_main.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: ```@listing 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 @Index "makedoc.g" makedoc.g directory, with content based on the following example: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); QUIT; ``` Then you can regenerate the package manual from the command line with the following command: ```@listing gap makedoc.g ``` If you also want regression tests from your manual examples, enable extract_examples := true; this is explained in Section . @Section Documenting code with &AutoDoc; @SectionLabel Tut:AdvancedAutoDoc &AutoDoc; supports several equally supported ways to organize your manual text. You can put chapter and section material directly into #! comments inside .g, .gd, or .gi files, you can put it into standalone .autodoc files, and you can mix either style with existing &GAPDoc; XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter , especially Section . 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: ```@listing #! 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: Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the Declare... statement. ```@listing #! @Arguments conv #! @Returns a toric variety #! @Description #! Creates a toric variety out #! of the convex object conv. DeclareOperation( "ToricVariety", [ IsConvexObject ] ); ``` In these comment lines, you can freely use normal &GAPDoc; XML markup (with the usual exceptions for lines starting with @, which are interpreted as &AutoDoc; commands). So, for instance, tags like ``, ``, ``, ``, etc. can be written directly in #! comment text. For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using #! @Chapter, #! @Section, and related commands, while others prefer standalone .autodoc files. In an .autodoc file you write the same commands without the #! prefix, and you list the file in autodoc.files or place it in a directory scanned via autodoc.scan_dirs. AutoDoc itself still uses the source-comment style in places, for example in gap/Magic.gd. One caveat applies if you decide to keep prose in a standalone .autodoc file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue #60 in the AutoDoc issue tracker. 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.: ```@listing 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 and standalone .autodoc files. Just make sure to first edit the main XML file of your documentation, and insert the line ```@listing <#Include SYSTEM "_AutoDocMainFile.xml"> ``` in a suitable place. This means that you can mix &AutoDoc; documentation comments and .autodoc files 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 then runs &GAPDoc; to produce HTML and PDF output, but does not touch your documentation XML files otherwise. ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); ``` @Section Using &AutoDoc; in an existing &GAPDoc; manual @SectionLabel Tut:IntegrateExisting Even if you already have an existing &GAPDoc; manual, it might be interesting for you to use &AutoDoc; for two purposes: First, with &AutoDoc; it 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 this purpose only, e.g. &io; and orb. In particular, this setup works well if you want to keep your existing manual structure and only adopt selected &AutoDoc; features first; for example automatic title-page data and predefined entities such as &VERSION;, &RELEASEYEAR; and &RELEASEDATE; (see Section ). @Subsection Using &AutoDoc; on a complete &GAPDoc; manual @SubsectionLabel Tut:IntegrateExisting:EverythingThere 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; session started in the root directory of your package: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( ); ``` 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 ```@listing 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 . If you prefer to keep generated tests in a separate location, set extract_examples.subdir to a path relative to the package root: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) ); ``` This writes the extracted examples into tst/generated/ instead. @Subsection Setting different &GAPDoc; options @SubsectionLabel Tut:IntegrateExisting:GapDocOptions 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 ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( main := "main" ) ) ); ``` &AutoDoc; can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option autodoc.scan_dirs controls where it looks for source comments beginning with #! and for standalone .autodoc files. By default, it scans the package root directory and the subdirectories gap, lib, examples and examples/doc; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust autodoc.scan_dirs. The following example instructs &AutoDoc; to only search in the subdirectory package_sources of the package's root directory for those files. ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( scan_dirs := [ "package_sources" ] ) ) ); ``` The separate option gapdoc.scan_dirs serves a different purpose: it controls where &GAPDoc; comments are searched for. 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: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) ); ``` 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 ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) ); ``` or, since ../../.. is the standard option for gap_root_relative_path, by ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) ); ``` The same behavior is also available via the global option `relativePath`. This is particularly convenient in a short makedoc.g script, and it overrides `gapdoc.gap_root_relative_path` if both are given. Since this is a GAP global option, you can also set it outside the eventual call and let it propagate through nested calls; see for more information about GAP's global options system: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : relativePath := "../../.." ); ``` If you pass `relativePath := true`, then &AutoDoc; uses the default relative path ../../... For example, if your makedoc.g reads the manual via , then the following command sets both `relativePath` and `nopdf` to `true` for that nested call: ```@listing Read( "makedoc.g" : nopdf, relativePath ); ``` Finally, if you only want HTML and text output, you can suppress PDF generation with the global option `nopdf`: ```@listing LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : nopdf ); ``` This is useful if `pdflatex` is unavailable, or when you want a faster documentation rebuild while editing. You can also request the same behavior from the shell by setting the environment variable `NOPDF` before invoking makedoc.g. For example: ```@listing NOPDF=1 gap makedoc.g ``` If `NOPDF` is set, &AutoDoc; skips PDF generation even if no `nopdf` option is given in the GAP code. @Subsection Checklist for converting an existing &GAPDoc; manual to use &AutoDoc; @SubsectionLabel Tut:Checklist 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/_main.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;. @Index "Scaffold record in makedoc.g" In the scaffold record change the includes list to be the list of your .xml files that are contained in manual.xml. @Index "Bibliography field in makedoc.g" 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. @Index "LaTeXOptions record in makedoc.g" 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. However, note that this only works in the PDF version of the file. 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 "));". @Index "Copyright field in PackageInfo.g" @Index "Abstract field in PackageInfo.g" @Index "Acknowledgements field in PackageInfo.g" 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.) @Index "Entities record in makedoc.g" In the entities record enter any entities previously stored in your manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the &AutoDoc; file PackageInfo.g defines entities for the names of packages &io; and &PackageName;. 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. @Section Scaffolds @SectionLabel Tut:Scaffolds @Subsection Generating a title page @SubsectionLabel Tut:Scaffolds:Title 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: ```@listing 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. ```@listing 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. @Subsection Generating the main XML file @SubsectionLabel Tut:Scaffolds:Main 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. ```@listing 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: ```@listing LoadPackage( "AutoDoc" ); AutoDoc(rec( scaffold := rec( includes := [ "somefile.xml", "anotherfile.xml" ] ) )); ``` For more information, please consult the documentation of the function. @Subsection What data is used from PackageInfo.g? @SubsectionLabel Tut:PackageInfo &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. </Item> <Mark>Subtitle</Mark><Item> This is used to set the `<Subtitle>` element of the title page. </Item> <Mark>Version</Mark><Item> This is used to set the `<Version>` element of the title page, with the string <Q>Version </Q> prepended. </Item> <Mark>Date</Mark><Item> This is used to set the `<Date>` element of the title page. </Item> <Mark>Persons</Mark><Item> This is used to generate `<Author>` elements in the generated title page. </Item> <Mark>PackageDoc</Mark><Item> 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 <C>PackageDoc.BookName</C> component and then passes that on to &GAPDoc; when creating the HTML, PDF and text versions of the manual. </Item> <Mark>AutoDoc</Mark><Item> This record controls extra settings used by &AutoDoc; while generating the manual. In particular, <C>PkgInfo.AutoDoc.TitlePage</C> lets you add or override title-page elements coming from package metadata. Typical fields you may set there include <C>TitleComment</C>, <C>Abstract</C>, <C>Copyright</C>, <C>Acknowledgements</C> and <C>Colophon</C>. For example, in <F>PackageInfo.g</F>: ```@listing SetPackageInfo( rec( ... AutoDoc := rec( TitlePage := rec( Copyright := "(C) 2026 Jane Doe", Acknowledgements := "Funded by Example Grant 1234." ) ) ) ); ``` This inserts `<Copyright>` and `<Acknowledgements>` blocks into the generated <F>title.xml</F>. <C>PkgInfo.AutoDoc.TitlePage</C> has exactly the same meaning as <C>scaffold.TitlePage</C> in <Ref Func="AutoDoc"/>. The function documentation for <C>scaffold.TitlePage</C> points back to this subsection. </Item> </List> @Subsection Entities from <F>PackageInfo.g</F> and scaffold options @SubsectionLabel Tut:PackageInfo:Entities Besides title-page fields, you can define custom entities in <C>AutoDoc.entities</C> inside <F>PackageInfo.g</F>. They are written to <F>doc/_entities.xml</F>, so they can be used both by generated main files and by hand-written main XML files. In addition, &AutoDoc; predefines the entities <C>VERSION</C>, <C>RELEASEYEAR</C> and <C>RELEASEDATE</C>, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with <F>PackageInfo.g</F>. You can specify scaffold-related settings in <F>PackageInfo.g</F> and in your <F>makedoc.g</F> call at the same time; both records are merged, and values from <F>makedoc.g</F> take precedence when both define the same key. @Section Worksheets @SectionLabel Tut:WorksheetsPointer For stand-alone documents that are not tied to a package, use <Ref Func="AutoDocWorksheet"/>. Its documentation and examples are in Section <Ref Sect="Section_AutoDocWorksheet"/> of chapter <Ref Chap="AutoDoc"/>. ���������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_AutoDocMainFile.xml���������������������������������������������������������0000644�0000000�0000000�00000000404�15175510000�014756� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <#Include SYSTEM "_Chapter_Overview.xml"> <#Include SYSTEM "_Chapter_Tutorials.xml"> <#Include SYSTEM "_Chapter_Comments.xml"> <#Include SYSTEM "_Chapter_Reference.xml"> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_Chapter_Comments.xml��������������������������������������������������������0000644�0000000�0000000�00000105672�15175510000�015263� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <Chapter Label="Chapter_Comments"> <Heading>&AutoDoc; documentation comments</Heading> <P/> You can document declarations of global functions and variables, operations, attributes etc. by inserting <E>&AutoDoc;</E> comments into your sources before these declarations. An &AutoDoc; comment always starts with <C>#!</C>. This is also the smallest possible &AutoDoc; command. If you want your declaration documented, just write <C>#!</C> at the line before the documentation. For example: <P/> <Listing><![CDATA[ #! DeclareOperation( "AnOperation", [ IsList ] ); ]]></Listing> <P/> This will produce a manual entry for the operation <C>AnOperation</C>. <P/> For declaration documentation, the associated declaration must appear immediately after the &AutoDoc; comment block. In particular, do not insert other code (such as <C>if false then</C> or assignments) between the comment block and the <C>Declare...</C> statement. <P/> This also works for <C>InstallMethod</C> and <C>InstallOtherMethod</C>. In that case, &AutoDoc; uses the installed method's name and filter list to create a manual entry for the implemented item. <P/> Inside of &AutoDoc; comments, <E>&AutoDoc; commands</E> starting with <C>@</C> can be used to control the output &AutoDoc; produces. Any comment line that does <E>not</E> start with an &AutoDoc; command is treated as regular documentation text and may contain (almost) arbitrary &GAPDoc; XML markup, such as <Code><Ref></Code>, <Code><A></Code>, <Code><List></Code>, and similar tags. This lets you use the normal &GAPDoc; formatting toolbox directly inside &AutoDoc; comments. <P/> For example: <Listing><![CDATA[ #! @Description #! See <Ref Chap="Chapter_Tutorials"/> for setup details. #! The argument <A>obj</A> must satisfy <K>IsObject</K>. ]]></Listing> <P/> As explained in chapter <Ref Chap="Chapter_Overview"/>, you can combine &AutoDoc; comments with hand-written XML and classic &GAPDoc; comments. For practical setup and migration workflows, see chapter <Ref Chap="Chapter_Tutorials"/>. <P/> <Section Label="Chapter_Comments_Section_Documenting_declarations"> <Heading>Documenting declarations</Heading> <P/> In the bare form above, the manual entry for <C>AnOperation</C> 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: <P/> <Subsection Label="Subsection_@Description"> <Heading><C>@Description <A>descr</A></C></Heading> <P/> <Index Key="@Description"><C>@Description <A>descr</A></C></Index> 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. <P/> </Subsection> <Subsection Label="Subsection_@Returns"> <Heading><C>@Returns <A>ret val</A></C></Heading> <P/> <Index Key="@Returns"><C>@Returns <A>ret_val</A></C></Index> The string <A>ret_val</A> is added to the documentation, with the text <Q>Returns: </Q> 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. <P/> </Subsection> <Subsection Label="Subsection_@Arguments"> <Heading><C>@Arguments <A>args</A></C></Heading> <P/> <Index Key="@Arguments"><C>@Arguments <A>args</A></C></Index> The string <A>args</A> 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 <Q>grp[, elm]</Q> or <Q>xx[y[z] ]</Q>. If &GAP; options are used, this can be followed by a colon : and one or more assignments, like <Q>n[, r]: tries := 100</Q>. <P/> For <C>DeclareGlobalName</C>, using <C>@Arguments</C> or <C>@Returns</C> also makes &AutoDoc; document the item as a function. This is useful because <C>DeclareGlobalName</C> itself does not reveal whether the name denotes a function or a variable. <P/> </Subsection> <Subsection Label="Subsection_@ItemType"> <Heading><C>@ItemType <A>kind</A></C></Heading> <P/> <Index Key="@ItemType"><C>@ItemType <A>kind</A></C></Index> Overrides the kind of manual item created for the following declaration or installed method. The supported values are <C>Attr</C>, <C>Cat</C>, <C>Coll</C>, <C>Constr</C>, <C>Fam</C>, <C>Filt</C>, <C>Func</C>, <C>InfoClass</C>, <C>Meth</C>, <C>Oper</C>, <C>Prop</C>, <C>Repr</C>, and <C>Var</C>. <P/> The values <C>Cat</C>, <C>Coll</C>, and <C>Repr</C> are &AutoDoc;-specific aliases. They emit <C>Filt</C> entries with the corresponding &GAPDoc; filter type. <P/> This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as <C>DeclareAttribute</C> or <C>DeclareProperty</C>, &AutoDoc; already knows the intended type from the declaration itself. <P/> It is useful for <C>DeclareGlobalName</C>, because that declaration can refer to either a function or a variable. &AutoDoc; defaults such entries to <C>Var</C>, but switches to <C>Func</C> as soon as <C>@Arguments</C> or <C>@Returns</C> indicates function-style documentation. You can still use <C>@ItemType</C> to override this explicitly. <P/> It is useful for <C>DeclareSynonym</C>, because that declaration can document a function synonym or one of several filter-like synonyms. Use <C>@ItemType Filt</C>, <C>Cat</C>, <C>Coll</C>, or <C>Repr</C> to control which kind of filter entry should be emitted. <P/> For example: <P/> <Listing><![CDATA[ #! @ItemType Repr DeclareSynonym( "IsSomethingRep", IsComponentObjectRep ); ]]></Listing> <P/> This makes &AutoDoc; emit a <C><Filt Type="Representation" .../></C> manual entry. <P/> </Subsection> <Subsection Label="Subsection_@Group"> <Heading><C>@Group <A>grpname</A></C></Heading> <P/> <Index Key="@Group"><C>@Group <A>grpname</A></C></Index> Adds the following method to a group with the given name. See section <Ref Sect="Section_Groups"/> for more information about groups. <P/> </Subsection> <Subsection Label="Subsection_@Label"> <Heading><C>@Label <A>label</A></C></Heading> <P/> <Index Key="@Label"><C>@Label <A>label</A></C></Index> Adds label to the function as label. <P/> If this is not specified, then for declarations that involve a list of input filters (as is the case for <C>DeclareOperation</C>, <C>DeclareAttribute</C>, etc.), a default label is generated from this filter list. <Listing><![CDATA[ #! @Label testlabel DeclareProperty( "AProperty", IsObject ); ]]></Listing> leads to this: <Listing><![CDATA[ <ManSection> <Prop Arg="arg" Name="AProperty" Label="testlabel"/> <Returns> <K>true</K> or <K>false</K> </Returns> <Description> </Description> </ManSection> ]]></Listing> while <Listing><![CDATA[ #! DeclareProperty( "AProperty", IsObject ); ]]></Listing> leads to this: <Listing><![CDATA[ <ManSection> <Prop Arg="arg" Name="AProperty" Label="for IsObject"/> <Returns> <K>true</K> or <K>false</K> </Returns> <Description> </Description> </ManSection> ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@ChapterInfo"> <Heading><C>@ChapterInfo <A>chapter</A>, <A>section</A></C></Heading> <P/> <Index Key="@ChapterInfo"><Code>@ChapterInfo</Code></Index> Adds the entry to the given chapter and section. Here, <A>chapter</A> and <A>section</A> are the respective titles. As an example, a full &AutoDoc; comment with all options could look like this: <P/> <Listing><![CDATA[ #! @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 ); ]]></Listing> <P/> </Subsection> </Section> <Section Label="Chapter_Comments_Section_Other_documentation_comments"> <Heading>Other documentation comments</Heading> <P/> 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. <P/> <Subsection Label="Subsection_@Chapter"> <Heading><C>@Chapter <A>name</A></C></Heading> <P/> <Index Key="@Chapter"><Code>@Chapter</Code></Index> <Index Key="@ChapterLabel"><Code>@ChapterLabel</Code></Index> <Index Key="@ChapterTitle"><Code>@ChapterTitle</Code></Index> Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their &AutoDoc; comment via <C>@ChapterInfo</C> 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 <C>@Description</C>, will be added to the chapter as regular text. Additionally, the chapters label will be set to <C>Chapter_</C><A>name</A>. <P/> Example: <P/> <Listing><![CDATA[ #! @Chapter My chapter #! This is my chapter. #! I document my stuff in it. ]]></Listing> <P/> The <C>@ChapterLabel</C> <A>label</A> command can be used to set the label of the chapter to <C>Chapter_</C><A>label</A> instead of <C>Chapter_</C><A>name</A>. <P/> Additionally, the chapter will be stored as <C>_Chapter_</C><A>label</A><C>.xml</C>. <P/> The <C>@ChapterTitle</C> <A>title</A> command can be used to set a heading for the chapter that is different from <A>name</A>. Note that the title does not affect the label. <P/> If you use all three commands, i.e., <Listing><![CDATA[ #! @Chapter name #! @ChapterLabel label #! @ChapterTitle title ]]></Listing> <C>title</C> is used for the headline, <C>label</C> for cross-referencing, and <C>name</C> for setting the same chapter as active chapter again. <P/> </Subsection> <Subsection Label="Subsection_@Appendix"> <Heading><C>@Appendix <A>name</A></C></Heading> <P/> <Index Key="@Appendix"><Code>@Appendix</Code></Index> This is analogous to <C>@Chapter</C>, but generates <Code>Appendix</Code> elements instead of <Code>Chapter</Code> elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in <Code>scaffold.appendix</Code>. <P/> Example: <P/> <Listing><![CDATA[ @Appendix Supplementary material @Section Additional tables ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@Section"> <Heading><C>@Section <A>name</A></C></Heading> <P/> <Index Key="@Section"><Code>@Section</Code></Index> <Index Key="@SectionLabel"><Code>@SectionLabel</Code></Index> <Index Key="@SectionTitle"><Code>@SectionTitle</Code></Index> Sets an active section like <C>@Chapter</C> sets an active chapter. The section automatically ends with the next <C>@Section</C> or <C>@Chapter</C> command. <P/> <Listing><![CDATA[ #! @Section My first manual section #! In this section I am going to document my first method. ]]></Listing> <P/> The <C>@SectionLabel</C> <A>label</A> command can be used to set the label of the section to <C>Section_</C><A>label</A> instead of <C>Chapter_chaptername_Section_</C><A>name</A>. <P/> The <C>@SectionTitle</C> <A>title</A> command can be used to set a heading for the section that is different from <A>name</A>. <P/> </Subsection> <Subsection Label="Subsection_@Subsection"> <Heading><C>@Subsection <A>name</A></C></Heading> <P/> <Index Key="@Subsection"><Code>@Subsection</Code></Index> <Index Key="@SubsectionLabel"><Code>@SubsectionLabel</Code></Index> <Index Key="@SubsectionTitle"><Code>@SubsectionTitle</Code></Index> Sets an active subsection like <C>@Section</C> sets an active section. The subsection automatically ends with the next <C>@Subsection</C>, <C>@Section</C> or <C>@Chapter</C> command. It also ends with the next documented function. Indeed, internally each function <Q>manpage</Q> is treated like a subsection. <P/> <Listing><![CDATA[ #! @Subsection My first manual subsection #! In this subsection I am going to document my first example. ]]></Listing> <P/> The <C>@SubsectionLabel</C> <A>label</A> command can be used to set the label of the subsection to <C>Subsection_</C><A>label</A> instead of <C>Chapter_chaptername_Section_sectionname_Subsection_</C><A>name</A>. <P/> The <C>@SubsectionTitle</C> <A>title</A> command can be used to set a heading for the subsection that is different from <A>name</A>. <P/> </Subsection> <Subsection Label="Subsection_@BeginGroup"> <Heading><C>@BeginGroup <A>[grpname]</A></C></Heading> <P/> <Index Key="@BeginGroup"><Code>@BeginGroup</Code></Index> Starts a group. All following documented declarations without an explicit <C>@Group</C> 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 <C>@EndGroup</C> command is reached. <P/> See section <Ref Sect="Section_Groups"/> for more information about groups. <P/> </Subsection> <Subsection Label="Subsection_@EndGroup"> <Heading><C>@EndGroup</C></Heading> <P/> <Index Key="@EndGroup"><Code>@EndGroup</Code></Index> Ends the current group. <P/> <Listing><![CDATA[ #! @BeginGroup MyGroup #! DeclareAttribute( "GroupedAttribute", IsList ); DeclareOperation( "NonGroupedOperation", [ IsObject ] ); #! DeclareOperation( "GroupedOperation", [ IsList, IsRubbish ] ); #! @EndGroup ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@GroupTitle"> <Heading>@GroupTitle <A>title</A></Heading> <P/> <Index Key="@GroupTitle"><Code>@GroupTitle</Code></Index> Sets the subsection heading for the current group to <A>title</A>. In the absence of any <C>@GroupTitle</C> command, the heading will be the name of the first entry in the group. See <Ref Sect="Section_Groups"/> for more information. <P/> </Subsection> <Subsection Label="Subsection_@BeginExample"> <Heading><C>@BeginExample</C> and <C>@EndExample</C></Heading> <P/> <Index Key="@BeginExample"><Code>@BeginExample</Code></Index> <Index Key="@EndExample"><Code>@EndExample</Code></Index> <C>@BeginExample</C> marks the start of an example to be put into the manual. It differs from &GAPDoc;'s <Code><Example></Code> (see <Ref Subsect="Log" BookName="gapdoc"/>), 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 <C>gap></C> prompt for the display in the manual is added by &AutoDoc;. <C>@EndExample</C> ends the example block. <P/> To illustrate this command, consider this input: <Listing><![CDATA[ #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample ]]></Listing> This results in the following output: <Example> gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120 </Example> The &AutoDoc; command <C>@Example</C> is an alias of <C>@BeginExample</C>. If you enable <C>extract_examples := true</C> when calling <Ref Func="AutoDoc"/>, these examples can also be turned into <F>.tst</F> files (see Section <Ref Sect="Subsection_Tut:IntegrateExisting:EverythingThere"/>). <P/> </Subsection> <Subsection Label="Subsection_@BeginExampleSession"> <Heading><C>@BeginExampleSession</C> and <C>@EndExampleSession</C></Heading> <P/> <Index Key="@BeginExampleSession"><Code>@BeginExampleSession</Code></Index> <Index Key="@EndExampleSession"><Code>@EndExampleSession</Code></Index> <C>@BeginExampleSession</C> marks the start of an example to be put into the manual, while <C>@EndExampleSession</C> ends the example block. It is the direct analog of &GAPDoc;'s <Code><Example></Code> (see <Ref Subsect="Log" BookName="gapdoc"/>). <P/> To illustrate this command, consider this input: <Listing><![CDATA[ #! @BeginExampleSession #! gap> S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) #! gap> Order(S5); #! 120 #! @EndExampleSession ]]></Listing> This results in the following output: <Example> gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Order(S5); 120 </Example> <P/> It inserts an example into the manual just as <C>@Example</C> 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 (<C>#!</C>). 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 <C>#!</C> and the <C>gap></C> prompt. The &AutoDoc; command <C>@ExampleSession</C> is an alias of <C>@BeginExampleSession</C>. <P/> </Subsection> <Subsection Label="Subsection_@BeginLog"> <Heading><C>@BeginLog</C> and <C>@EndLog</C></Heading> <P/> <Index Key="@BeginLog"><Code>@BeginLog</Code></Index> <Index Key="@EndLog"><Code>@EndLog</Code></Index> Works just like the <C>@BeginExample</C> command, but the example will not be tested. See the &GAPDoc; manual for more information. The &AutoDoc; command <C>@Log</C> is an alias of <C>@BeginLog</C>. <P/> </Subsection> <Subsection Label="Subsection_@BeginLogSession"> <Heading><C>@BeginLogSession</C> and <C>@EndLogSession</C></Heading> <P/> <Index Key="@BeginLogSession"><Code>@BeginLogSession</Code></Index> <Index Key="@EndLogSession"><Code>@EndLogSession</Code></Index> Works just like the <C>@BeginExampleSession</C> command, but the example will not be tested if manual examples are run. It is the direct analog of &GAPDoc;'s <Code><Log></Code> (see <Ref Subsect="Log" BookName="gapdoc"/>). The &AutoDoc; command <C>@LogSession</C> is an alias of <C>@BeginLogSession</C>. <P/> </Subsection> <Subsection Label="Subsection_@DoNotReadRestOfFile"> <Heading><C>@DoNotReadRestOfFile</C></Heading> <P/> <Index Key="@DoNotReadRestOfFile"><Code>@DoNotReadRestOfFile</Code></Index> Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files. <P/> <Listing><![CDATA[ #! This will appear in the manual #! @DoNotReadRestOfFile #! This will not appear in the manual. ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@BeginChunk"> <Heading><C>@BeginChunk <A>name</A></C>, <C>@EndChunk</C>, and <C>@InsertChunk <A>name</A></C></Heading> <P/> <Index Key="@BeginChunk"><C>@BeginChunk <A>name</A></C></Index> <Index Key="@EndChunk"><Code>@EndChunk</Code></Index> <Index Key="@EndChunk"><C>@InsertChunk <A>name</A></C></Index> Text inside a <C>@BeginChunk</C> / <C>@EndChunk</C> part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. <P/> That chunk of text can then later on be inserted in any other place by using the <C>@InsertChunk <A>name</A></C> command. <P/> If you do not provide an <C>@EndChunk</C>, the chunk ends at the end of the file. <Listing><![CDATA[ #! @BeginChunk MyChunk #! Hello, world. #! @EndChunk #! @InsertChunk MyChunk ## The text "Hello, world." is inserted right before this. ]]></Listing> <P/> You can use this to define an example like this in one file: <P/> <Listing><![CDATA[ #! @BeginChunk Example_Symmetric_Group #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample #! @EndChunk ]]></Listing> <P/> And then later, insert the example in a different file, like this: <P/> <Listing><![CDATA[ #! @InsertChunk Example_Symmetric_Group ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@BeginCode"> <Heading><C>@BeginCode <A>name</A></C>, @EndCode, and <C>@InsertCode <A>name</A></C></Heading> <P/> <Index Key="@BeginCode"><C>@BeginCode <A>name</A></C></Index> <Index Key="@EndCode"><Code>@EndCode</Code></Index> <Index Key="@InsertCode"><C>@InsertCode <A>name</A></C></Index> Inserts the text between <C>@BeginCode</C> and <C>@EndCode</C> verbatim at the point where <C>@InsertCode</C> is called. This is useful to insert code excerpts directly into the manual. <Listing><![CDATA[ #! @BeginCode Increment i := i + 1; #! @EndCode #! @InsertCode Increment ## Code is inserted here. ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@LatexOnly"> <Heading><C>@LatexOnly <A>text</A></C>, <C>@BeginLatexOnly</C>, and <C>@EndLatexOnly</C></Heading> <P/> <Index Key="@LatexOnly"><C>@LatexOnly <A>text</A></C></Index> <Index Key="@BeginLatexOnly"><Code>@BeginLatexOnly</Code></Index> <Index Key="@EndLatexOnly"><Code>@EndLatexOnly</Code></Index> Code inserted between <C>@BeginLatexOnly</C> and <C>@EndLatexOnly</C> or after <C>@LatexOnly</C> is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary &LaTeX;-commands. <Listing><![CDATA[ #! @BeginLatexOnly #! \include{picture.tex} #! @EndLatexOnly #! @LatexOnly \include{picture.tex} ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@NotLatex"> <Heading><C>@NotLatex <A>text</A></C>, <C>@BeginNotLatex</C>, and <C>@EndNotLatex</C></Heading> <P/> <Index Key="@NotLatex"><C>@NotLatex <A>text</A></C></Index> <Index Key="@BeginNotLatex"><Code>@BeginNotLatex</Code></Index> <Index Key="@EndNotLatex"><Code>@EndNotLatex</Code></Index> Code inserted between <C>@BeginNotLatex</C> and <C>@EndNotLatex</C> or after <C>@NotLatex</C> is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version. <Listing><![CDATA[ #! @BeginNotLatex #! For further information see the PDF version of this manual. #! @EndNotLatex #! @NotLatex For further information see the PDF version of this manual. ]]></Listing> <P/> </Subsection> <Subsection Label="Subsection_@Index"> <Heading><C>@Index <A>key</A> [<A>entry text</A>]</C></Heading> <P/> <Index Key="@Index"><C>@Index <A>key</A> [<A>entry text</A>]</C></Index> Adds an index entry to the current documentation text. The command <C>@Index key entry text</C> generates <Code><Index Key="key">entry text</Index></Code>. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. <C>@Index "my key" entry text</C>. The entry text is processed like normal documentation text, so markdown-like inline code such as <Keyword>true</Keyword> is supported. <P/> </Subsection> </Section> <Section Label="Section_TitlepageCommands"> <Heading>Title page commands</Heading> <P/> The following commands can be used to add corresponding parts to the title page of a document generated by &AutoDoc;. <List> <Item> <C>@Title</C> </Item> <Item> <C>@Subtitle</C> </Item> <Item> <C>@Version</C> </Item> <Item> <C>@TitleComment</C> </Item> <Item> <C>@Author</C> </Item> <Item> <C>@Date</C> </Item> <Item> <C>@Address</C> </Item> <Item> <C>@Abstract</C> </Item> <Item> <C>@Copyright</C> </Item> <Item> <C>@Acknowledgements</C> </Item> <Item> <C>@Colophon</C> </Item> </List> Many of these values can (and for package manuals typically should) be extracted from <F>PackageInfo.g</F>. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful for worksheets created with <Ref Func="AutoDocWorksheet"/>, since worksheets do not have a <F>PackageInfo.g</F> file from which this information could be extracted. <P/> </Section> <Section Label="Section_PlainText"> <Heading>Plain text files</Heading> <P/> Files that have the suffix <C>.autodoc</C> and are listed in the <C>autodoc.files</C> option of <Ref Func="AutoDoc"/>, resp. are contained in one of the directories listed in <C>autodoc.scan_dirs</C> or one of their subdirectories, are treated as standalone &AutoDoc; input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material. <P/> Conceptually, a <F>.autodoc</F> file uses the same parser as &AutoDoc; comments, but without the comment marker. In a <F>.autodoc</F> file, lines do not need to start with <C>#!</C> and in fact usually should not. This makes <F>.autodoc</F> files one convenient way to replace hand-written XML chapters when you prefer &AutoDoc;'s command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and &AutoDoc; itself still uses that style in files such as <F>gap/Magic.gd</F>. For the surrounding workflow, see Chapter <Ref Chap="Chapter_Tutorials"/>. <P/> The most important difference from declaration comments is that a plain text file does <E>not</E> document a declaration by adjacency. There is no following <C>Declare...</C> or <C>InstallMethod</C> statement for &AutoDoc; to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration. <P/> In practice, this gives the following rule of thumb. <P/> <List> <Item> Use source comments beginning with <C>#!</C> to document declarations. This is the mode for <C>@Description</C>, <C>@Returns</C>, <C>@Arguments</C>, <C>@Label</C>, <C>@Group</C>, and <C>@ChapterInfo</C>. </Item> <Item> Use either <F>.autodoc</F> files or source comments for standalone manual structure and prose. Commands such as <C>@Chapter</C>, <C>@Section</C>, <C>@Subsection</C>, grouping commands, examples and logs, chunks and code insertion, <C>@Index</C>, title-page commands, Markdown-style headings, fenced code blocks, and ordinary &GAPDoc; XML markup work in both styles. </Item> </List> <P/> As a concrete example, the following file can serve as a complete chapter written in <F>.autodoc</F> format. <P/> <Listing><![CDATA[ @Chapter Test @Section First Section @Subsection First Subsection This text belongs directly to the manual chapter. It can use XML tags such as <A>arg</A> or <Ref .../>. @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession @Index "Worksheet Autoplain" Plain worksheet index entry with `true` ]]></Listing> <P/> This is essentially the style used in the worksheet fixture <F>tst/worksheets/autoplain.sheet/plain.autodoc</F>. <P/> The same structural commands can also be used inside source comments, for example: <P/> <Listing><![CDATA[ #! @Chapter Reference #! @Section The AutoDoc() function #! Some introductory text for this section. ]]></Listing> <P/> This source-comment style is still fully supported and is used in <F>gap/Magic.gd</F>. <P/> The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include <F>_AutoDocMainFile.xml</F> from the main XML file as described in Chapter <Ref Chap="Chapter_Tutorials"/>, and add one or more <F>.autodoc</F> files via <C>autodoc.files</C> or <C>autodoc.scan_dirs</C>. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged. <P/> One caveat is worth keeping in mind. If you want a standalone <F>.autodoc</F> file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue <C>#60</C> in the AutoDoc issue tracker. <P/> So, while <F>.autodoc</F> files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient. <P/> </Section> <Section Label="Section_Groups"> <Heading>Grouping</Heading> <P/> 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 <C>@GroupTitle</C> command; if that is not supplied, then the heading of the first manual item in the group will be used as the heading. <P/> 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 <C>@BeginGroup</C> / <C>@EndGroup</C> pairs using the same group name, in different places, and these all will refer to the same group. <P/> Moreover, this means that you can add items to a group via the <C>@Group</C> command in the &AutoDoc; comment of an arbitrary declaration, at any time. <P/> The following code <Listing><![CDATA[ #! @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 ); ]]></Listing> <P/> produces the following: <P/> <Listing><![CDATA[ <ManSection Label="Group1"> <Heading>A family of operations</Heading> <Oper Arg="arg" Name="FirstOperation" Label="for IsInt"/> <Oper Arg="arg1,arg2" Name="SecondOperation" Label="for IsInt, IsGroup"/> <Oper Arg="arg1,arg2" Name="ThirdOperation" Label="for IsGroup, IsInt"/> <Description> First sentence. Second sentence. Third sentence. </Description> </ManSection> ]]></Listing> <P/> </Section> <Section Label="Section_MarkdownExtension"> <Heading>Markdown-like formatting of text in &AutoDoc;</Heading> <P/> &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. <P/> <Subsection Label="Subsection_MarkdownExtensionList"> <Heading>Lists</Heading> <P/> 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: <P/> <Listing><![CDATA[ #! 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. ]]></Listing> <P/> This is the output:<Br/> The list starts in the next line <List> <Item> item 1 </Item> <Item> item 2 which is a bit longer <List> <Item> and also contains a nested list </Item> <Item> with two items </Item> </List> </Item> <Item> item 3 of the outer list </Item> </List> This does not belong to the list anymore.<Br/> <P/> The *, -, and + are fully interchangeable and can even be used mixed, but this is not recommended. <P/> </Subsection> <Subsection Label="Subsection_MarkdownExtensionMath"> <Heading>Math modes</Heading> <P/> 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;. <P/> <Listing><![CDATA[ #! This is an inline formula: $1+1 = 2$. #! This is a display formula: #! $$ \sum_{i=1}^n i. $$ ]]></Listing> <P/> produces the following output:<Br/> This is an inline formula: <Math>1+1 = 2</Math>. This is a display formula: <Display> \sum_{i=1}^n i. </Display> <P/> </Subsection> <Subsection Label="Subsection_MarkdownExtensionEmph"> <Heading>Emphasize</Heading> <P/> 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: <P/> <Listing><![CDATA[ #! **This** is very important. #! This is __also important__. #! **Naturally, more than one line #! can be important.** ]]></Listing> <P/> This produces the following output:<Br/> <E>This</E> is very important. This is <E>also important</E>. <E>Naturally, more than one line can be important.</E> <P/> </Subsection> <Subsection Label="Subsection_MarkdownExtensionInlineCode"> <Heading>Inline code</Heading> <P/> 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: <P/> <Listing><![CDATA[ #! Call function `foobar()` at the start. ]]></Listing> <P/> This produces the following output:<Br/> Call function <C>foobar()</C> at the start. <P/> </Subsection> <Subsection Label="Subsection_MarkdownExtensionFencedCode"> <Heading>Fenced code blocks</Heading> <P/> One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values <C>@listing</C>, <C>@example</C>, and <C>@log</C> select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate <Code><Listing></Code>. Example: <P/> <Listing><![CDATA[ #! ```@listing #! if x = 2 then #! Print("1 + 1 = 2 holds, all is good\n"); #! fi; #! ``` #! ~~~@example #! gap> [ 1 .. 3 ] ^ 2; #! [ 1, 4, 9 ] #! ~~~ #! ```@log #! #I some log message #! ``` ]]></Listing> <P/> This produces the following output:<Br/> <Listing><![CDATA[ if x = 2 then Print("1 + 1 = 2 holds, all is good\n"); fi; ]]></Listing> <Example><![CDATA[ gap> [ 1 .. 3 ] ^ 2; [ 1, 4, 9 ] ]]></Example> <Log><![CDATA[ #I some log message ]]></Log> <P/> </Subsection> </Section> <Section Label="Section_Deprecated"> <Heading>Deprecated commands</Heading> <P/> The following commands used to be supported, but are not supported anymore. <P/> <List> <Mark><C>@EndSection</C></Mark> <Item>You can simply remove any use of this, &AutoDoc; ends sections automatically at the start of any new section or chapter.</Item> <Mark><C>@EndSubsection</C></Mark> <Item>You can simply remove any use of this, &AutoDoc; ends subsections automatically at the start of any new subsection, section or chapter.</Item> <Mark><C>@BeginAutoDoc</C> and <C>@EndAutoDoc</C></Mark> <Item>It suffices to prepend each declaration that is meant to appear in the manual with a minimal &AutoDoc; comment <C>#!</C>.</Item> <Mark><C>@BeginSystem <A>name</A></C>, <C>@EndSystem</C>, and <C>@InsertSystem <A>name</A></C></Mark> <Item>Please use the chunk commands from subsection <Ref Subsect="Subsection_@BeginChunk"/> instead.</Item> <Mark><C>@AutoDocPlainText</C> and <C>@EndAutoDocPlainText</C></Mark> <Item>Use <C>.autodoc</C> files or &AutoDoc; comments instead.</Item> </List> </Section> </Chapter> ����������������������������������������������������������������������AutoDoc-2026.05.03/doc/_Chapter_Overview.xml��������������������������������������������������������0000644�0000000�0000000�00000005240�15175510000�015272� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <Chapter Label="Chapter_Overview"> <Heading>What &AutoDoc; offers</Heading> <P/> &AutoDoc; helps you create and maintain package manuals for &GAP;. It is built on top of &GAPDoc; and generates the XML input that &GAPDoc; consumes. So &AutoDoc; complements &GAPDoc; instead of replacing it. <P/> The package is designed for a <Q>mix and match</Q> workflow: you can adopt only the parts that help you today, and add more over time. <P/> <Section Label="Section_Overview:Features"> <Heading>Core features</Heading> <P/> <List> <Item> Build package manuals via one reproducible command, usually <C>gap makedoc.g</C>. </Item> <Item> Generate and maintain a title page from metadata in <F>PackageInfo.g</F>. </Item> <Item> Generate and maintain a main XML file that includes your chapters. </Item> <Item> Extract manual examples into <F>.tst</F> files via <C>extract_examples := true</C>. </Item> <Item> Document declarations directly in source files via &AutoDoc; comments beginning with <C>#!</C>. </Item> <Item> Organize chapter and section text either in source comments or in standalone <F>.autodoc</F> files. </Item> <Item> Combine &AutoDoc; comments, classic &GAPDoc; source comments, and hand-written XML chapters in one manual. </Item> </List> <P/> </Section> <Section Label="Section_Overview:MixAndMatch"> <Heading>Adopting &AutoDoc; incrementally</Heading> <P/> You do not have to switch everything at once. Typical adoption paths include: <List> <Item> Use only <Ref Func="AutoDoc"/> to rebuild an existing &GAPDoc; manual. </Item> <Item> Enable only title-page generation, while keeping your custom main XML. </Item> <Item> Keep your existing title page but use generated entities such as <C>&VERSION;</C>, <C>&RELEASEYEAR;</C>, and <C>&RELEASEDATE;</C>. </Item> <Item> Add &AutoDoc; comments only for new code, and leave old documentation as-is. </Item> <Item> Keep existing XML chapters, or gradually add source comments and <F>.autodoc</F> files where they fit your preferred workflow. </Item> <Item> Later, gradually move chapters or source documentation to your preferred style. </Item> </List> <P/> This flexibility is central: &AutoDoc; should make your current setup better, without forcing a full rewrite first. <P/> </Section> <Section Label="Section_Overview:WhereNext"> <Heading>Where to continue</Heading> <P/> For practical setup and migration workflows, continue with chapter <Ref Chap="Chapter_Tutorials"/>. For the command reference of documentation comments, including standalone <F>.autodoc</F> files, see chapter <Ref Chap="Chapter_Comments"/>. </Section> </Chapter> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_Chapter_Reference.xml�������������������������������������������������������0000644�0000000�0000000�00000056047�15175510000�015375� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <Chapter Label="Chapter_Reference"> <Heading>Reference</Heading> <Section Label="Section_AutoDocWorksheet"> <Heading>AutoDoc worksheets</Heading> <ManSection> <Func Arg="[filenames,] [optrec]" Name="AutoDocWorksheet" /> <Description> The purpose of this function is to create stand-alone PDF and HTML files using &AutoDoc; without associating them with a package. <P/> Instead of a package directory, you pass one filename or a list of filenames containing &AutoDoc; text from which the document is created. Settings are supplied via an optional record using the same entries as the <A>optrec</A> argument of <Ref Func="AutoDoc"/>. Alternatively, you may omit <A>filenames</A> and specify the files via <C>optrec.autodoc.files</C>. <P/> A simple worksheet file can define title-page information and chapter content directly in the source file, including example blocks. If this is stored in <F>worksheet.g</F>, you can generate documentation via <Log><![CDATA[ AutoDocWorksheet( "worksheet.g" ); ]]></Log> This creates documentation in a <F>doc</F> subdirectory of the current directory. <P/> Since worksheets do not have a <F>PackageInfo.g</F>, title-page fields are specified directly in the worksheet file. <P/> For backwards compatibility, worksheet calls still accept GAP global options for specifying the option-record entries such as <C>dir</C>, <C>scaffold</C>, <C>autodoc</C>, <C>gapdoc</C>, and <C>extract_examples</C>. However, this feature is deprecated. </Description> </ManSection> </Section> <Section Label="Chapter_Reference_Section_The_AutoDoc()_function"> <Heading>The AutoDoc() function</Heading> <ManSection> <Func Arg="[pkgdir], [optrec]" Name="AutoDoc" /> <Returns>nothing </Returns> <Description> This is the main function of the &AutoDoc; package. It can perform any combination of the following tasks: <Enum> <Item> 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 <F>doc/_main.xml</F> 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 <F>doc/title.xml</F> 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 <F>PackageInfo.g</F>. </Item> <Item> It can scan your package for &AutoDoc; based documentation, using documentation comments and commands. This produces additional XML files to be used as part of the package manual. </Item> <Item> 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 <Ref Func='MakeGAPDocDoc' BookName='gapdoc'/> to convert the XML sources, and it also instructs &GAPDoc; to copy supplementary files (such as CSS style files) into your doc directory (see <Ref Func='CopyHTMLStyleFiles' BookName='gapdoc'/>). </Item> </Enum> These tasks can be enabled independently, so you can use as much or as little of &AutoDoc; as your package currently needs. For more information and some examples, please refer to Chapter <Ref Chap='Chapter_Tutorials'/>. <P/> The parameters have the following meanings: <List> <Mark><A>pkgdir</A></Mark> <Item> This optional parameter is used to determine the package directory in which &AutoDoc; will operate, and to find the metadata concerning the package being documented. If given, it should be an <C>IsDirectory</C> object. If the argument is omitted, then &AutoDoc; checks if it was called from a <F>makedoc.g</F> file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both cases, the specified directory must contain a <F>PackageInfo.g</F> file, and &AutoDoc; extracts all needed metadata from that. The <C>IsDirectory</C> 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. <P/> For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package &GAP; knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package. <P/> Note that when using <C>AutoDocWorksheet</C> (see <Ref Sect='Section_AutoDocWorksheet'/>), there is no parameter corresponding to <A>pkgdir</A> and so the <Q>package directory</Q> is always the current directory, and there is no metadata. </Item> <Mark><A>optrec</A></Mark> <Item> <A>optrec</A> can be a record with some additional options. The following are currently supported: <List> <Mark><A>dir</A></Mark> <Item> This should either be a string, in which case it must be a path <E>relative</E> to the specified package directory, or a <C>Directory()</C> object. (Thus, the only way to designate an absolute directory is with a <C>Directory()</C> 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. <Br/> <E>Default value: <C>"doc/"</C>.</E> </Item> <Mark><A>scaffold</A></Mark> <Item> This controls whether and how to generate scaffold XML files for the package documentation. <P/> The value should be either <K>true</K>, <K>false</K> or a record. If it is a record or <K>true</K> (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if <A>opt.scaffold</A> is missing but the package's info record in <F>PackageInfo.g</F> has an <C>AutoDoc</C> entry. In all other cases (in particular if <A>opt.scaffold</A> is <K>false</K>), scaffolding is disabled. <P/> If scaffolding is enabled, and <A>PackageInfo.AutoDoc</A> exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings. <P/> <P/> If <A>opt.scaffold</A> is a record, it may contain the following entries. <P/> <List> <Mark><A>includes</A></Mark> <Item> 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 <F>_AutoDocMainFile.xml</F> 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. </Item> <Mark><A>index</A></Mark> <Item> By default, the scaffold creates an index. If you do not want an index, set this to <K>false</K>. </Item> <Mark><A>appendix</A></Mark> <Item> This entry is similar to <A>opt.scaffold.includes</A> but is used to specify files to include after the main body of the manual, i.e. typically appendices written directly in &GAPDoc; XML. Appendices created with <C>@Appendix</C> are included automatically after these files when scaffolding generates the main XML file. </Item> <Mark><A>bib</A></Mark> <Item> The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file <F>doc/PACKAGENAME.bib</F> then it is assumed that you want to use this as your bibliography. </Item> <Mark><A>bibstyle</A></Mark> <Item> Overrides the bibliography style used for LaTeX output. This is written as the <C>Style</C> attribute of the generated <C><Bibliography .../></C> element, so valid values are the bibliography style names understood by &GAPDoc; and BibTeX, such as <C>alpha</C>, <C>alphaurl</C>, or <C>plain</C>. </Item> <Mark><A>entities</A></Mark> <Item> A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record <Q>SomePackage</Q>, <Listing><![CDATA[ rec( SomePackage := "<Package>SomePackage</Package>", RELEASEYEAR := "2015" )]]></Listing> then the following entity definitions are added to the XML preamble: <Listing><![CDATA[<!ENTITY SomePackage '<Package>SomePackage</Package>'> <!ENTITY RELEASEYEAR '2015'>]]></Listing> This allows you to write <Q>&SomePackage;</Q> and <Q>&RELEASEYEAR;</Q> in your documentation, which will be replaced by respective values specified in the entities definition. <P/> Note that &AutoDoc; predefines several entities: <List> <Mark><A>VERSION</A></Mark> <Item>Set to the <C>Version</C> field of your package info record.</Item> <Mark><A>RELEASEYEAR</A></Mark> <Item>Set to a string containing the release year, as derived from the <C>Date</C> field of your package info record.</Item> <Mark><A>RELEASEDATE</A></Mark> <Item>Derived from the <C>Date</C> field of your package info record.</Item> <Mark><A>SomePackage</A></Mark> <Item> The precise name of this entity is derived from the <C>PackageName</C> field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above. </Item> </List> </Item> <Mark><A>TitlePage</A></Mark> <Item> A record with extra title-page fields for the generated manual. Field names are interpreted as title-page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with <Listing><![CDATA[ rec( Acknowledgements := "Many thanks to ..." )]]></Listing> If this is set in <F>PackageInfo.g</F> as <C>PkgInfo.AutoDoc.TitlePage</C>, it has the same meaning as this option; see subsection <Ref Subsect='Subsection_Tut:PackageInfo'/> in chapter <Ref Chap='Chapter_Tutorials'/> for details and an example. <P/> For the list of valid title-page elements, see the &GAPDoc; manual, specifically section <Ref Subsect='TitlePage' BookName='gapdoc'/>. </Item> <Mark><A>MainPage</A></Mark> <Item> 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 <K>false</K> </Item> <Mark><A>document_class</A></Mark> <Item> 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;. </Item> <Mark><A>latex_header_file</A></Mark> <Item> Replaces the standard header from &GAPDoc; completely with the header in this &LaTeX; file. Please be careful here, and look at &GAPDoc;'s <F>latexheader.tex</F> file for an example. </Item> </List> </Item> <Mark><A>autodoc</A></Mark> <Item> This controls whether and how to generate additional XML documentation files by scanning for &AutoDoc; documentation comments. <P/> The value should be either <K>true</K>, <K>false</K> or a record. If it is a record or <K>true</K> (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if <A>opt.autodoc</A> is missing but the package depends (directly) on the &AutoDoc; package. In all other cases (in particular if <A>opt.autodoc</A> is <K>false</K>), this feature is disabled. <P/> <P/> If <A>opt.autodoc</A> is a record, it may contain the following entries. <P/> <List> <Mark><A>files</A></Mark> <Item> 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 <A>autodoc.scan_dirs</A>, see below. </Item> <Mark><A>scan_dirs</A></Mark> <Item> A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for &AutoDoc; documentation comments. The special entries <C>"."</C> and <C>""</C> still only scan the package root itself. This controls where &AutoDoc; looks for source comments beginning with <C>#!</C> and for standalone <F>.autodoc</F> files. It does not affect where &GAPDoc; looks for GAPDoc comments; that is controlled separately by <A>gapdoc.scan_dirs</A>. <Br/> <E>Default value: <C>[ ".", "gap", "lib", "examples", "examples/doc" ]</C>.</E> </Item> <Mark><A>level</A></Mark> <Item> 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. </Item> </List> </Item> <Mark><A>gapdoc</A></Mark> <Item> This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text files from your various XML files. <P/> The value should be either <K>true</K>, <K>false</K> or a record. If it is a record or <K>true</K> (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if <A>opt.gapdoc</A> is missing. In all other cases (in particular if <A>opt.gapdoc</A> is <K>false</K>), this feature is disabled. <P/> <P/> If <A>opt.gapdoc</A> is a record, it may contain the following entries. <P/> <List> <Mark><A>main</A></Mark> <Item> 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. <Br/> <E>Default value: <C>_main.xml</C> when scaffolding is enabled for package manuals, otherwise <C>PACKAGENAME.xml</C>.</E> </Item> <Mark><A>files</A></Mark> <Item> 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 <A>gapdoc.scan_dirs</A>, see below. </Item> <Mark><A>scan_dirs</A></Mark> <Item> A list of subdirectories of the package directory (given as relative paths) which &AutoDoc; then scans recursively for .gi, .gd and .g files; all of these files are then scanned for &GAPDoc; documentation comments. The special entries <C>"."</C> and <C>""</C> still only scan the package root itself. This controls only where &GAPDoc; comments are searched for. It does not affect where &AutoDoc; looks for source comments beginning with <C>#!</C> or for <F>.autodoc</F> files; use <A>autodoc.scan_dirs</A> for that. <Br/> <E>Default value: <C>[ ".", "gap", "lib", "examples", "examples/doc" ]</C>.</E> </Item> <Mark><A>LaTeXOptions</A></Mark> <Item> Must be a record with entries which can be understood by <Ref Func='SetGapDocLaTeXOptions' BookName='gapdoc'/>. 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. </Item> <Mark><A>gap_root_relative_path</A></Mark> <Item> Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to <K>false</K>), 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.<Br/> Thus, if a relative path is provided via this option (or if it is set to <K>true</K>, in which case the relative path <F>../../..</F> is used), then &AutoDoc; and &GAPDoc; attempt to replace all absolute paths in references to &GAP; manuals by paths based on this relative path.<P/> <P/> On a technical level, &AutoDoc; passes the relative path to the <A>gaproot</A> parameter of <Ref Func='MakeGAPDocDoc' BookName='gapdoc'/><P/> </Item> </List> </Item> <Mark><A>extract_examples</A></Mark> <Item> Either <K>true</K> or a record. If set to <K>true</K>, then all manual examples are extracted and placed into files <F>tst/PACKAGENAME01.tst</F>, <F>tst/PACKAGENAME02.tst</F>, ... and so on, with one file for each chapter. For chapters with no examples, no file is created.<P/> If set to a record, it may contain the following entries: <List> <Mark>subdir</Mark> <Item> A string or <C>Directory()</C> object selecting where the generated <F>.tst</F> files are written. The default is <F>tst</F>. If a string is given, it is interpreted relative to the package directory, so values such as <F>tst/generated</F> are supported. </Item> <Mark>units</Mark> <Item> 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. <P/> On a technical level, &AutoDoc; passes the value to the <A>units</A> parameter of <Ref Func='ExtractExamples' BookName='gapdoc'/>. </Item> <Mark>skip_empty_in_numbering</Mark> <Item> If set to <K>true</K> (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 <F>tst/PACKAGENAME01.tst</F>. If this option is set to <K>false</K>, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file <F>tst/PACKAGENAME02.tst</F>. </Item> </List> </Item> </List> </Item> </List> <P/> The function also checks the following GAP global options, i.e. options supplied via GAP's value-option syntax and visible through nested calls. These are not entries of <A>optrec</A>. See <Ref Chap="Options Stack" BookName="ref"/> for more information about GAP's global options system. <List> <Mark><A>nopdf</A></Mark> <Item> If this global option is set to <Keyword>true</Keyword>, then &AutoDoc; tells &GAPDoc; not to build the PDF version of the manual. HTML and text output are still generated. <P/> This is useful on systems without a working <Code>pdflatex</Code> installation, or when you only need the non-PDF outputs while iterating on the manual. <P/> For example: <Listing><![CDATA[ AutoDoc( rec( autodoc := true ) : nopdf );]]></Listing> Also, if the environment variable <Code>NOPDF</Code> is set, then &AutoDoc; behaves as if the global option <A>nopdf</A> had been enabled. </Item> <Mark><A>relativePath</A></Mark> <Item> This has the same effect as <A>gapdoc.gap_root_relative_path</A>, but as a GAP global option. It takes precedence over that record entry if both are specified. <P/> If <A>relativePath</A> is <Keyword>true</Keyword>, then the default relative path <F>../../..</F> is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root. <P/> For example: <Listing><![CDATA[ AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );]]></Listing> </Item> </List> In particular, a call such as <Listing><![CDATA[ Read( "makedoc.g" : nopdf, relativePath );]]></Listing> sets both global options to <Keyword>true</Keyword>, and they remain visible to the <Ref Func="AutoDoc"/> call inside <F>makedoc.g</F>. <P/> </Description> </ManSection> <ManSection> <InfoClass Name="InfoAutoDoc" /> <Description> Info class for the <Package>AutoDoc</Package> package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths. <P/> This can be set by calling, for example, <C>SetInfoLevel(InfoAutoDoc, 0)</C>. Default value is 1. </Description> </ManSection> </Section> </Chapter> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_Chapter_Tutorials.xml�������������������������������������������������������0000644�0000000�0000000�00000067234�15175510000�015465� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <Chapter Label="Chapter_Tutorials"> <Heading>Getting started using &AutoDoc;</Heading> <P/> This chapter gives practical workflows for adding &AutoDoc; to a package. For a high-level feature overview and adoption strategy, see chapter <Ref Chap="Chapter_Overview"/>. <P/> <Section Label="Section_Tut:ChooseWorkflow"> <Heading>Choose your workflow</Heading> <P/> You can use &AutoDoc; in several ways, and it is fine to combine them: <List> <Item> Start a new package manual from scratch (Section <Ref Sect="Section_Tut:Scratch"/>). </Item> <Item> Integrate &AutoDoc; into an existing &GAPDoc; manual (Section <Ref Sect="Section_Tut:IntegrateExisting"/>). </Item> <Item> Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged. </Item> </List> <P/> This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful. </Section> <Section Label="Section_Tut:Scratch"> <Heading>Creating a package manual from scratch</Heading> <P/> Suppose your package is already up and running, but so far has no manual. Then you can rapidly generate a <Q>scaffold</Q> for a package manual using the <Ref Func="AutoDoc"/> command like this: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); ]]></Listing> When called from a file such as <F>makedoc.g</F>, &AutoDoc; uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the <F>PackageInfo.g</F> file from that package directory. It extracts information about the package from it (such as its name and version, see Section <Ref Sect="Subsection_Tut:Scaffolds:Title"/>). It then creates two XML files <F>doc/_main.xml</F> and <F>doc/title.xml</F> inside the package directory. Finally, it runs &GAPDoc; on them to produce a nice initial PDF and HTML version of your fresh manual. <P/> To ensure that the &GAP; help system picks up your package manual, you should also add something like the following to your <F>PackageInfo.g</F>: <Listing><![CDATA[ PackageDoc := rec( BookName := ~.PackageName, ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := ~.Subtitle, ), ]]></Listing> <P/> 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 <F>PackageInfo.g</F>. 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. <P/> Next of course you need to provide actual content (unfortunately, we were not yet able to automate <E>that</E> 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 <Ref Chap="Distributing" BookName="gapdoc"/>, as well as Section <Ref Sect="Section_Tut:IntegrateExisting"/> of this manual on how to teach the <Ref Func="AutoDoc"/> command to include this extra documentation. Or you could use the special documentation facilities &AutoDoc; provides (see Section <Ref Sect="Section_Tut:AdvancedAutoDoc"/>). <P/> You will probably want to re-run the <Ref Func="AutoDoc"/> command frequently, e.g. whenever you modified your documentation or your <F>PackageInfo.g</F>. To make this more convenient and reproducible, we recommend putting its invocation into a file <F>makedoc.g</F> in your package <Index Key="makedoc.g"><F>makedoc.g</F></Index> directory, with content based on the following example: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); QUIT; ]]></Listing> Then you can regenerate the package manual from the command line with the following command: <Listing><![CDATA[ gap makedoc.g ]]></Listing> <P/> If you also want regression tests from your manual examples, enable <C>extract_examples := true</C>; this is explained in Section <Ref Sect="Subsection_Tut:IntegrateExisting:EverythingThere"/>. <P/> </Section> <Section Label="Section_Tut:AdvancedAutoDoc"> <Heading>Documenting code with &AutoDoc;</Heading> <P/> &AutoDoc; supports several equally supported ways to organize your manual text. You can put chapter and section material directly into <C>#!</C> comments inside <F>.g</F>, <F>.gd</F>, or <F>.gi</F> files, you can put it into standalone <F>.autodoc</F> files, and you can mix either style with existing &GAPDoc; XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter <Ref Chap="Chapter_Comments"/>, especially Section <Ref Sect="Section_PlainText"/>. <P/> To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an &AutoDoc; comment of the form <C>#!</C> directly in front of it. For example: <Listing><![CDATA[ #! DeclareOperation( "ToricVariety", [ IsConvexObject ] ); ]]></Listing> <P/> 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: <P/> Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the <C>Declare...</C> statement. <P/> <Listing><![CDATA[ #! @Arguments conv #! @Returns a toric variety #! @Description #! Creates a toric variety out #! of the convex object <A>conv</A>. DeclareOperation( "ToricVariety", [ IsConvexObject ] ); ]]></Listing> <P/> In these comment lines, you can freely use normal &GAPDoc; XML markup (with the usual exceptions for lines starting with <C>@</C>, which are interpreted as &AutoDoc; commands). So, for instance, tags like <Code><Ref></Code>, <Code><A></Code>, <Code><K></Code>, <Code><List></Code>, etc. can be written directly in <C>#!</C> comment text. <P/> For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using <C>#! @Chapter</C>, <C>#! @Section</C>, and related commands, while others prefer standalone <F>.autodoc</F> files. In an <F>.autodoc</F> file you write the same commands without the <C>#!</C> prefix, and you list the file in <C>autodoc.files</C> or place it in a directory scanned via <C>autodoc.scan_dirs</C>. AutoDoc itself still uses the source-comment style in places, for example in <F>gap/Magic.gd</F>. <P/> One caveat applies if you decide to keep prose in a standalone <F>.autodoc</F> file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue <C>#60</C> in the AutoDoc issue tracker. <P/> For a thorough description of what you can do with &AutoDoc; documentation comments, please refer to chapter <Ref Chap="Chapter_Comments"/>. <P/> <!-- Once we switched AutoDoc itself to use AutoDoc comments, mention that, i.e. point out that all operations and functions documented in this manual are documented exactly like described here, and that one can hence use that as examples. --> <P/> <!-- <P/> # <#GAPDoc Label="ToricVarietyConst"> # <ManSection> # <Oper Arg="conv" Name="ToricVariety" # Label="for IsConvexObject"/> # <Returns>a toric variety</Returns> # <Description> # Creates a toric variety out # of the convex object <A>conv</A>. # </Description> # </ManSection> # <#/GAPDoc> DeclareOperation( "ToricVariety", [ IsConvexObject ] ); --> <P/> Suppose you have not been using &GAPDoc; before but instead used the process described in section <Ref Sect="Section_Tut:Scratch"/> to create your manual. Then the following &GAP; command will regenerate the manual and automatically include all newly documented functions, operations etc.: <P/> <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true, autodoc := true ) ); ]]></Listing> <P/> 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 and standalone <F>.autodoc</F> files. Just make sure to first edit the main XML file of your documentation, and insert the line <Listing><![CDATA[ <#Include SYSTEM "_AutoDocMainFile.xml"> ]]></Listing> in a suitable place. This means that you can mix &AutoDoc; documentation comments and <F>.autodoc</F> files freely with your existing documentation; you can even still make use of any existing &GAPDoc; documentation comments in your code. <P/> The following command should be useful for you in this case; it still scans the package code for &AutoDoc; documentation comments and then runs &GAPDoc; to produce HTML and PDF output, but does not touch your documentation XML files otherwise. <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); ]]></Listing> <P/> </Section> <Section Label="Section_Tut:IntegrateExisting"> <Heading>Using &AutoDoc; in an existing &GAPDoc; manual</Heading> <P/> Even if you already have an existing &GAPDoc; manual, it might be interesting for you to use &AutoDoc; for two purposes: <P/> First, with &AutoDoc; it is very convenient to regenerate your documentation. <P/> 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 <F>PackageInfo.g</F> is fully automated this way (including the correct version, release data, author information and so on). <P/> There are various examples of packages using &AutoDoc; for this purpose only, e.g. &io; and <Package>orb</Package>. <P/> In particular, this setup works well if you want to keep your existing manual structure and only adopt selected &AutoDoc; features first; for example automatic title-page data and predefined entities such as <C>&VERSION;</C>, <C>&RELEASEYEAR;</C> and <C>&RELEASEDATE;</C> (see Section <Ref Sect="Subsection_Tut:PackageInfo:Entities"/>). <P/> <Subsection Label="Subsection_Tut:IntegrateExisting:EverythingThere"> <Heading>Using &AutoDoc; on a complete &GAPDoc; manual</Heading> <P/> Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your <F>.g</F>, <F>.gd</F>, and <F>.gi</F> files. Suppose the main XML file is named <F>PACKAGENAME.xml</F> and is in the <F>/doc</F> subdirectory of your package. Then you can rebuild your manual by executing the following two &GAP; commands from a &GAP; session started in the root directory of your package: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( ); ]]></Listing> Note that in particular, you do not have to worry about keeping a list of your implementation files up-to-date. <P/> But there is more. &AutoDoc; can create <F>.tst</F> files from the examples in your manual to test your package. This can be achieved via <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := true ) ); ]]></Listing> Now files <F>PACKAGENAME01.tst</F>, <F>PACKAGENAME02.tst</F> and so appear in the <F>tst/</F> subdirectory of your package, and can be tested as usual using <Ref BookName="ref" Func="Test"/> respectively <Ref BookName="ref" Func="TestDirectory"/>. <P/> If you prefer to keep generated tests in a separate location, set <C>extract_examples.subdir</C> to a path relative to the package root: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) ); ]]></Listing> This writes the extracted examples into <F>tst/generated/</F> instead. <P/> </Subsection> <Subsection Label="Subsection_Tut:IntegrateExisting:GapDocOptions"> <Heading>Setting different &GAPDoc; options</Heading> <P/> Sometimes, the default values for the &GAPDoc; command used by &AutoDoc; may not be suitable for your manual. <P/> Suppose your main XML file is <E>not</E> named <F>PACKAGENAME.xml</F>, but rather something else, e.g. <F>main.xml</F>. Then you can tell &AutoDoc; to use this file as the main XML file via <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( main := "main" ) ) ); ]]></Listing> <P/> &AutoDoc; can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option <C>autodoc.scan_dirs</C> controls where it looks for source comments beginning with <C>#!</C> and for standalone <F>.autodoc</F> files. By default, it scans the package root directory and the subdirectories <F>gap</F>, <F>lib</F>, <F>examples</F> and <F>examples/doc</F>; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust <C>autodoc.scan_dirs</C>. The following example instructs &AutoDoc; to only search in the subdirectory <F>package_sources</F> of the package's root directory for those files. <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( scan_dirs := [ "package_sources" ] ) ) ); ]]></Listing> The separate option <C>gapdoc.scan_dirs</C> serves a different purpose: it controls where &GAPDoc; comments are searched for. <P/> 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: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) ); ]]></Listing> Giving such a file does not prevent the standard <C>scan_dirs</C> from being scanned for other files. <P/> 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 <Ref Func="AutoDoc"/> will then build the documentation in the <F>doc</F> subdirectory of your package. From this directory, the gap root directory has the relative path <F>../../..</F>. Then you can enable the relative paths by <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) ); ]]></Listing> or, since <F>../../..</F> is the standard option for <C>gap_root_relative_path</C>, by <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) ); ]]></Listing> <P/> The same behavior is also available via the global option <Code>relativePath</Code>. This is particularly convenient in a short <F>makedoc.g</F> script, and it overrides <Code>gapdoc.gap_root_relative_path</Code> if both are given. Since this is a GAP global option, you can also set it outside the eventual <Ref Func="AutoDoc"/> call and let it propagate through nested calls; see <Ref Chap="Options Stack" BookName="ref"/> for more information about GAP's global options system: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : relativePath := "../../.." ); ]]></Listing> If you pass <Code>relativePath := true</Code>, then &AutoDoc; uses the default relative path <F>../../..</F>. <P/> For example, if your <F>makedoc.g</F> reads the manual via <Ref Func="AutoDoc"/>, then the following command sets both <Code>relativePath</Code> and <Code>nopdf</Code> to <Keyword>true</Keyword> for that nested call: <Listing><![CDATA[ Read( "makedoc.g" : nopdf, relativePath ); ]]></Listing> <P/> Finally, if you only want HTML and text output, you can suppress PDF generation with the global option <Code>nopdf</Code>: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : nopdf ); ]]></Listing> This is useful if <Code>pdflatex</Code> is unavailable, or when you want a faster documentation rebuild while editing. <P/> You can also request the same behavior from the shell by setting the environment variable <Code>NOPDF</Code> before invoking <F>makedoc.g</F>. For example: <Listing><![CDATA[ NOPDF=1 gap makedoc.g ]]></Listing> If <Code>NOPDF</Code> is set, &AutoDoc; skips PDF generation even if no <Code>nopdf</Code> option is given in the GAP code. <P/> </Subsection> <Subsection Label="Subsection_Tut:Checklist"> <Heading>Checklist for converting an existing &GAPDoc; manual to use &AutoDoc;</Heading> <P/> Here is a checklist for authors of a package &PackageName;, <E>which already has a &GAPDoc; based manual</E>, who wish to use &AutoDoc; to build the manual from now on. We assume that the manual is currently built by reading a file <File>makedoc.g</File> and that the main <File>.xml</File> file is named <File>manual.xml</File>. <P/> The files <File>PackageInfo.g</File>, <File>makedoc.g</File>, <File>doc/title.xml</File> and <File>doc/_main.xml</File> (if it exists) will be altered by this procedure, so it may be wise to keep backup copies. <P/> You should have copies of the &AutoDoc; files <File>PackageInfo.g</File> and <File>makedoc.g</File> to hand when reading these instructions. <P/> <List> <Item> Copy <File>AutoDoc/makedoc.g</File> to <File>PackageName/makedoc.g</File>. </Item> <Item> Edit <File>PackageName/makedoc.g</File> as follows. <List> <Item> Change the header comment to match other files in your package. </Item> <Item> After <Code>LoadPackage("AutoDoc");</Code> add <Code>LoadPackage("PackageName");</Code>. </Item> <Item> In the <Code>AutoDoc</Code> record delete <Code>autodoc := true;</Code>. </Item> <Item> <Index Key="Scaffold record in makedoc.g"></Index> In the <Code>scaffold</Code> record change the <Code>includes</Code> list to be the list of your <Code>.xml</Code> files that are contained in <File>manual.xml</File>. </Item> <Item> <Index Key="Bibliography field in makedoc.g"></Index> If you do not have a bibliography you may delete the <Code>bib := "bib.xml",</Code> field in the scaffold. Otherwise, edit the file name if you have a different file. If you only have a <Code>.bib</Code> file (<Code>manual.bib</Code> or <Code>bib.xml.bib</Code> say) you should rename this file <File>PackageName.bib</File>. </Item> <Item> <Index Key="LaTeXOptions record in makedoc.g"></Index> In the <Code>LaTeXOptions</Code> record, which is in the <Code>gapdoc</Code> record, enter any &LaTeX; <Code>newcommands</Code> previously in <File>manual.xml</File>. (If there are none you may safely delete this record.) To illustrate this option, the &AutoDoc; file <File>makedoc.g</File> defines the command <Code>\bbZ</Code> by <Code>\newcommand{\bbZ}{\mathbb{Z}}</Code>, which may be used to produce the &LaTeX; formula <M>f : \bbZ^2 \to \bbZ</M>. However, note that this only works in the PDF version of the file. </Item> </List> </Item> <Item> Now edit <File>PackageName/PackageInfo.g</File> as follows. <List> <Item> Delete any <Code>PKGVERSIONDATA</Code> chunk that may be there. One reason for converting your manual to use &AutoDoc; is to stop using entities such as <Code>PACKAGENAMEVERSION</Code>. </Item> <Item> Copy the <Code>AutoDoc</Code> record from <File>AutoDoc/PackageInfo.g</File> to the end of your file (just before the final <Code>"));"</Code>. </Item> <Item> <Index Key="Copyright field in PackageInfo.g"></Index> <Index Key="Abstract field in PackageInfo.g"></Index> <Index Key="Acknowledgements field in PackageInfo.g"></Index> Replace the <Code>Copyright</Code>, <Code>Abstract</Code> and <Code>Acknowledgements</Code> fields of the <Code>TitlePage</Code> record with the corresponding material from your <File>manual.xml</File>. (If you do not have an abstract, then delete the <Code>Abstract</Code> field, etc.) <!-- For other introductory components, such as <Code>Colophon</Code>, --> <!-- consult the file <File>gap/Magic.gd</File>. --> </Item> <Item> <Index Key="Entities record in makedoc.g"></Index> In the <Code>entities</Code> record enter any entities previously stored in your <File>manual.xml</File>. (Again, if you have none, you may safely delete this record.) To illustrate this option the &AutoDoc; file <File>PackageInfo.g</File> defines entities for the names of packages &io; and &PackageName;. </Item> </List> </Item> <Item> If you are using a GitHub repository, as well as running "<Code>git add</Code>" on files <File>makedoc.g</File>, <File>PackageInfo.g</File> and <File>doc/PackageName.bib</File>, you should run "<Code>git rm -f</Code>" on files <File>doc/manual.xml</File>, and <File>doc/title.xml</File>. </Item> </List> You should now be ready to run &GAP; and <Code>Read("makedoc.g");</Code> in your package root directory. <P/> </Subsection> </Section> <Section Label="Section_Tut:Scaffolds"> <Heading>Scaffolds</Heading> <P/> <!-- TODO: insert an introduction here --> <P/> <Subsection Label="Subsection_Tut:Scaffolds:Title"> <Heading>Generating a title page</Heading> <P/> 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. <P/> All this data is also contained in your <F>PackageInfo.g</F>, 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 <F>PackageInfo.g</F> files: <Listing><![CDATA[ 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> ]]></Listing> 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. <P/> 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 <F>PackageInfo.g</F>. The following commands do just that (in addition to building your manual), by generating a file called <F>doc/title.xml</F>. <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := rec( MainPage := false ) ) ); ]]></Listing> Note that this only outputs <F>doc/title.xml</F> but does not touch any other files of your documentation. In particular, you need to explicitly include <F>doc/title.xml</F> from your main XML file. <P/> 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. <P/> </Subsection> <Subsection Label="Subsection_Tut:Scaffolds:Main"> <Heading>Generating the main XML file</Heading> <P/> 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. <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); ]]></Listing> <P/> You can instruct &AutoDoc; to include additional XML files by giving it a list of filenames, as in the following example: <Listing><![CDATA[ LoadPackage( "AutoDoc" ); AutoDoc(rec( scaffold := rec( includes := [ "somefile.xml", "anotherfile.xml" ] ) )); ]]></Listing> <P/> For more information, please consult the documentation of the <Ref Func="AutoDoc"/> function. <P/> </Subsection> <Subsection Label="Subsection_Tut:PackageInfo"> <Heading>What data is used from <F>PackageInfo.g</F>?</Heading> <P/> &AutoDoc; can use data from <F>PackageInfo.g</F> in order to generate a title page. Specifically, the following components of the package info record are taken into account: <P/> <List> <Mark>PackageName</Mark><Item> This is used to set the <Code><Title></Code> element of the title page. </Item> <Mark>Subtitle</Mark><Item> This is used to set the <Code><Subtitle></Code> element of the title page. </Item> <Mark>Version</Mark><Item> This is used to set the <Code><Version></Code> element of the title page, with the string <Q>Version </Q> prepended. </Item> <Mark>Date</Mark><Item> This is used to set the <Code><Date></Code> element of the title page. </Item> <Mark>Persons</Mark><Item> This is used to generate <Code><Author></Code> elements in the generated title page. </Item> <Mark>PackageDoc</Mark><Item> 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 <C>PackageDoc.BookName</C> component and then passes that on to &GAPDoc; when creating the HTML, PDF and text versions of the manual. </Item> <Mark>AutoDoc</Mark><Item> This record controls extra settings used by &AutoDoc; while generating the manual. In particular, <C>PkgInfo.AutoDoc.TitlePage</C> lets you add or override title-page elements coming from package metadata. <P/> Typical fields you may set there include <C>TitleComment</C>, <C>Abstract</C>, <C>Copyright</C>, <C>Acknowledgements</C> and <C>Colophon</C>. For example, in <F>PackageInfo.g</F>: <Listing><![CDATA[ SetPackageInfo( rec( ... AutoDoc := rec( TitlePage := rec( Copyright := "(C) 2026 Jane Doe", Acknowledgements := "Funded by Example Grant 1234." ) ) ) ); ]]></Listing> This inserts <Code><Copyright></Code> and <Code><Acknowledgements></Code> blocks into the generated <F>title.xml</F>. <P/> <C>PkgInfo.AutoDoc.TitlePage</C> has exactly the same meaning as <C>scaffold.TitlePage</C> in <Ref Func="AutoDoc"/>. The function documentation for <C>scaffold.TitlePage</C> points back to this subsection. </Item> </List> <P/> </Subsection> <Subsection Label="Subsection_Tut:PackageInfo:Entities"> <Heading>Entities from <F>PackageInfo.g</F> and scaffold options</Heading> <P/> Besides title-page fields, you can define custom entities in <C>AutoDoc.entities</C> inside <F>PackageInfo.g</F>. They are written to <F>doc/_entities.xml</F>, so they can be used both by generated main files and by hand-written main XML files. <P/> In addition, &AutoDoc; predefines the entities <C>VERSION</C>, <C>RELEASEYEAR</C> and <C>RELEASEDATE</C>, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with <F>PackageInfo.g</F>. <P/> You can specify scaffold-related settings in <F>PackageInfo.g</F> and in your <F>makedoc.g</F> call at the same time; both records are merged, and values from <F>makedoc.g</F> take precedence when both define the same key. <P/> </Subsection> </Section> <Section Label="Section_Tut:WorksheetsPointer"> <Heading>Worksheets</Heading> <P/> For stand-alone documents that are not tied to a package, use <Ref Func="AutoDocWorksheet"/>. Its documentation and examples are in Section <Ref Sect="Section_AutoDocWorksheet"/> of chapter <Ref Chap="AutoDoc"/>. </Section> </Chapter> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_Chunks.xml������������������������������������������������������������������0000644�0000000�0000000�00000000000�15175510000�013236� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_entities.xml����������������������������������������������������������������0000644�0000000�0000000�00000000352�15175510000�013641� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!ENTITY AutoDoc '<Package>AutoDoc</Package>'> <!ENTITY PackageName '<Package>PackageName</Package>'> <!ENTITY RELEASEDATE '3 May 2026'> <!ENTITY RELEASEYEAR '2026'> <!ENTITY VERSION '2026.05.03'> <!ENTITY io '<Package>io</Package>'> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_main.tex��������������������������������������������������������������������0000644�0000000�0000000�00000314165�15175510000�012753� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������% generated by GAPDoc2LaTeX from XML source (Frank Luebeck) \documentclass[a4paper,11pt]{report} \usepackage{a4wide} \newcommand{\bbZ}{\mathbb{Z}} \usepackage[top=37mm,bottom=37mm,left=27mm,right=27mm]{geometry} \sloppy \pagestyle{myheadings} \usepackage{amssymb} \usepackage[utf8]{inputenc} \usepackage{makeidx} \makeindex \usepackage{color} \definecolor{FireBrick}{rgb}{0.5812,0.0074,0.0083} \definecolor{RoyalBlue}{rgb}{0.0236,0.0894,0.6179} \definecolor{RoyalGreen}{rgb}{0.0236,0.6179,0.0894} \definecolor{RoyalRed}{rgb}{0.6179,0.0236,0.0894} \definecolor{LightBlue}{rgb}{0.8544,0.9511,1.0000} \definecolor{Black}{rgb}{0.0,0.0,0.0} \definecolor{linkColor}{rgb}{0.0,0.0,0.554} \definecolor{citeColor}{rgb}{0.0,0.0,0.554} \definecolor{fileColor}{rgb}{0.0,0.0,0.554} \definecolor{urlColor}{rgb}{0.0,0.0,0.554} \definecolor{promptColor}{rgb}{0.0,0.0,0.589} \definecolor{brkpromptColor}{rgb}{0.589,0.0,0.0} \definecolor{gapinputColor}{rgb}{0.589,0.0,0.0} \definecolor{gapoutputColor}{rgb}{0.0,0.0,0.0} %% for a long time these were red and blue by default, %% now black, but keep variables to overwrite \definecolor{FuncColor}{rgb}{0.0,0.0,0.0} %% strange name because of pdflatex bug: \definecolor{Chapter }{rgb}{0.0,0.0,0.0} \definecolor{DarkOlive}{rgb}{0.1047,0.2412,0.0064} \usepackage{fancyvrb} \usepackage{mathptmx,helvet} \usepackage[T1]{fontenc} \usepackage{textcomp} \usepackage[ pdftex=true, bookmarks=true, a4paper=true, pdftitle={Written with GAPDoc}, pdfcreator={LaTeX with hyperref package / GAPDoc}, colorlinks=true, backref=page, breaklinks=true, linkcolor=linkColor, citecolor=citeColor, filecolor=fileColor, urlcolor=urlColor, pdfpagemode={UseNone}, ]{hyperref} \newcommand{\maintitlesize}{\fontsize{50}{55}\selectfont} % write page numbers to a .pnr log file for online help \newwrite\pagenrlog \immediate\openout\pagenrlog =\jobname.pnr \immediate\write\pagenrlog{PAGENRS := [} \newcommand{\logpage}[1]{\protect\write\pagenrlog{#1, \thepage,}} %% were never documented, give conflicts with some additional packages \newcommand{\GAP}{\textsf{GAP}} %% nicer description environments, allows long labels \usepackage{enumitem} \setdescription{style=nextline} %% depth of toc \setcounter{tocdepth}{1} %% command for ColorPrompt style examples \newcommand{\gapprompt}[1]{\color{promptColor}{\bfseries #1}} \newcommand{\gapbrkprompt}[1]{\color{brkpromptColor}{\bfseries #1}} \newcommand{\gapinput}[1]{\color{gapinputColor}{#1}} \begin{document} \logpage{[ 0, 0, 0 ]} \begin{titlepage} \mbox{}\vfill \begin{center}{\maintitlesize \textbf{ AutoDoc \mbox{}}}\\ \vfill \hypersetup{pdftitle= AutoDoc } \markright{\scriptsize \mbox{}\hfill AutoDoc \hfill\mbox{}} {\Huge \textbf{ Generate documentation from \textsf{GAP} source code \mbox{}}}\\ \vfill {\Huge 2026.05.03 \mbox{}}\\[1cm] { 3 May 2026 \mbox{}}\\[1cm] \mbox{}\\[2cm] {\Large \textbf{ Sebastian Gutsche \mbox{}}}\\ {\Large \textbf{ Max Horn \mbox{}}}\\ \hypersetup{pdfauthor= Sebastian Gutsche ; Max Horn } \end{center}\vfill \mbox{}\\ {\mbox{}\\ \small \noindent \textbf{ Sebastian Gutsche } Email: \href{mailto://gutsche@mathematik.uni-siegen.de} {\texttt{gutsche@mathematik.uni\texttt{\symbol{45}}siegen.de}}\\ Homepage: \href{https://algebra.mathematik.uni-siegen.de/gutsche/} {\texttt{https://algebra.mathematik.uni\texttt{\symbol{45}}siegen.de/gutsche/}}\\ Address: \begin{minipage}[t]{8cm}\noindent Department Mathematik\\ Universit{\"a}t Siegen\\ Walter\texttt{\symbol{45}}Flex\texttt{\symbol{45}}Stra{\ss}e 3\\ 57072 Siegen\\ Germany\\ \end{minipage} }\\ {\mbox{}\\ \small \noindent \textbf{ Max Horn } Email: \href{mailto://mhorn@rptu.de} {\texttt{mhorn@rptu.de}}\\ Homepage: \href{https://www.quendi.de/math} {\texttt{https://www.quendi.de/math}}\\ Address: \begin{minipage}[t]{8cm}\noindent Fachbereich Mathematik\\ RPTU Kaiserslautern\texttt{\symbol{45}}Landau\\ Gottlieb\texttt{\symbol{45}}Daimler\texttt{\symbol{45}}Stra{\ss}e 48\\ 67663 Kaiserslautern\\ Germany\\ \end{minipage} }\\ \end{titlepage} \newpage\setcounter{page}{2} {\small \section*{Abstract} \logpage{[ 0, 0, 1 ]} \textsf{AutoDoc} is a \textsf{GAP} package whose purpose is to aid \textsf{GAP} package authors in creating and maintaining the documentation of their packages. \mbox{}}\\[1cm] {\small \section*{Copyright} \logpage{[ 0, 0, 2 ]} {\copyright} 2012\texttt{\symbol{45}}2026 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. \mbox{}}\\[1cm] {\small \section*{Acknowledgements} \logpage{[ 0, 0, 3 ]} This documentation was prepared using the \textsf{GAPDoc} package \cite{GAPDoc}. \mbox{}}\\[1cm] \newpage \def\contentsname{Contents\logpage{[ 0, 0, 4 ]}} \tableofcontents \newpage \chapter{\textcolor{Chapter }{What \textsf{AutoDoc} offers}}\label{Chapter_Overview} \logpage{[ 1, 0, 0 ]} \hyperdef{L}{X786190217AE14EBF}{} { \textsf{AutoDoc} helps you create and maintain package manuals for \textsf{GAP}. It is built on top of \textsf{GAPDoc} and generates the XML input that \textsf{GAPDoc} consumes. So \textsf{AutoDoc} complements \textsf{GAPDoc} instead of replacing it. The package is designed for a ``mix and match'' workflow: you can adopt only the parts that help you today, and add more over time. \section{\textcolor{Chapter }{Core features}}\label{Section_Overview:Features} \logpage{[ 1, 1, 0 ]} \hyperdef{L}{X7A835D9779307F98}{} { \begin{itemize} \item Build package manuals via one reproducible command, usually \texttt{gap makedoc.g}. \item Generate and maintain a title page from metadata in \texttt{PackageInfo.g}. \item Generate and maintain a main XML file that includes your chapters. \item Extract manual examples into \texttt{.tst} files via \texttt{extract{\textunderscore}examples := true}. \item Document declarations directly in source files via \textsf{AutoDoc} comments beginning with \texttt{\#!}. \item Organize chapter and section text either in source comments or in standalone \texttt{.autodoc} files. \item Combine \textsf{AutoDoc} comments, classic \textsf{GAPDoc} source comments, and hand\texttt{\symbol{45}}written XML chapters in one manual. \end{itemize} } \section{\textcolor{Chapter }{Adopting \textsf{AutoDoc} incrementally}}\label{Section_Overview:MixAndMatch} \logpage{[ 1, 2, 0 ]} \hyperdef{L}{X8081E3BA7B3EC702}{} { You do not have to switch everything at once. Typical adoption paths include: \begin{itemize} \item Use only \texttt{AutoDoc} (\ref{AutoDoc}) to rebuild an existing \textsf{GAPDoc} manual. \item Enable only title\texttt{\symbol{45}}page generation, while keeping your custom main XML. \item Keep your existing title page but use generated entities such as \texttt{\&VERSION;}, \texttt{\&RELEASEYEAR;}, and \texttt{\&RELEASEDATE;}. \item Add \textsf{AutoDoc} comments only for new code, and leave old documentation as\texttt{\symbol{45}}is. \item Keep existing XML chapters, or gradually add source comments and \texttt{.autodoc} files where they fit your preferred workflow. \item Later, gradually move chapters or source documentation to your preferred style. \end{itemize} This flexibility is central: \textsf{AutoDoc} should make your current setup better, without forcing a full rewrite first. } \section{\textcolor{Chapter }{Where to continue}}\label{Section_Overview:WhereNext} \logpage{[ 1, 3, 0 ]} \hyperdef{L}{X83D6D8B481C07CD8}{} { For practical setup and migration workflows, continue with chapter \ref{Chapter_Tutorials}. For the command reference of documentation comments, including standalone \texttt{.autodoc} files, see chapter \ref{Chapter_Comments}. } } \chapter{\textcolor{Chapter }{Getting started using \textsf{AutoDoc}}}\label{Chapter_Tutorials} \logpage{[ 2, 0, 0 ]} \hyperdef{L}{X7A0D7AA484F466E1}{} { This chapter gives practical workflows for adding \textsf{AutoDoc} to a package. For a high\texttt{\symbol{45}}level feature overview and adoption strategy, see chapter \ref{Chapter_Overview}. \section{\textcolor{Chapter }{Choose your workflow}}\label{Section_Tut:ChooseWorkflow} \logpage{[ 2, 1, 0 ]} \hyperdef{L}{X7BEF736283D2A7A9}{} { You can use \textsf{AutoDoc} in several ways, and it is fine to combine them: \begin{itemize} \item Start a new package manual from scratch (Section \ref{Section_Tut:Scratch}). \item Integrate \textsf{AutoDoc} into an existing \textsf{GAPDoc} manual (Section \ref{Section_Tut:IntegrateExisting}). \item Use only selected features, such as title\texttt{\symbol{45}}page generation or example extraction, while keeping everything else unchanged. \end{itemize} This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful. } \section{\textcolor{Chapter }{Creating a package manual from scratch}}\label{Section_Tut:Scratch} \logpage{[ 2, 2, 0 ]} \hyperdef{L}{X7BFBC6907B26AA95}{} { 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 \texttt{AutoDoc} (\ref{AutoDoc}) command like this: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); \end{Verbatim} When called from a file such as \texttt{makedoc.g}, \textsf{AutoDoc} uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the \texttt{PackageInfo.g} file from that package directory. It extracts information about the package from it (such as its name and version, see Section \ref{Subsection_Tut:Scaffolds:Title}). It then creates two XML files \texttt{doc/{\textunderscore}main.xml} and \texttt{doc/title.xml} inside the package directory. Finally, it runs \textsf{GAPDoc} on them to produce a nice initial PDF and HTML version of your fresh manual. To ensure that the \textsf{GAP} help system picks up your package manual, you should also add something like the following to your \texttt{PackageInfo.g}: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] PackageDoc := rec( BookName := ~.PackageName, ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := ~.Subtitle, ), \end{Verbatim} 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 \texttt{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\texttt{\symbol{45}}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 \emph{that} for you, more research on artificial intelligence is required). To add more content, you have several options: You could add further \textsf{GAPDoc} XML files containing extra chapters, sections and so on. Or you could use classic \textsf{GAPDoc} source comments. For details on either, please refer to (\textbf{GAPDoc: Distributing a Document into Several Files}), as well as Section \ref{Section_Tut:IntegrateExisting} of this manual on how to teach the \texttt{AutoDoc} (\ref{AutoDoc}) command to include this extra documentation. Or you could use the special documentation facilities \textsf{AutoDoc} provides (see Section \ref{Section_Tut:AdvancedAutoDoc}). You will probably want to re\texttt{\symbol{45}}run the \texttt{AutoDoc} (\ref{AutoDoc}) command frequently, e.g. whenever you modified your documentation or your \texttt{PackageInfo.g}. To make this more convenient and reproducible, we recommend putting its invocation into a file \texttt{makedoc.g} in your package \index{makedoc.g@\texttt{makedoc.g}} directory, with content based on the following example: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); QUIT; \end{Verbatim} Then you can regenerate the package manual from the command line with the following command: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] gap makedoc.g \end{Verbatim} If you also want regression tests from your manual examples, enable \texttt{extract{\textunderscore}examples := true}; this is explained in Section \ref{Subsection_Tut:IntegrateExisting:EverythingThere}. } \section{\textcolor{Chapter }{Documenting code with \textsf{AutoDoc}}}\label{Section_Tut:AdvancedAutoDoc} \logpage{[ 2, 3, 0 ]} \hyperdef{L}{X87A00EED866E22E8}{} { \textsf{AutoDoc} supports several equally supported ways to organize your manual text. You can put chapter and section material directly into \texttt{\#!} comments inside \texttt{.g}, \texttt{.gd}, or \texttt{.gi} files, you can put it into standalone \texttt{.autodoc} files, and you can mix either style with existing \textsf{GAPDoc} XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter \ref{Chapter_Comments}, especially Section \ref{Section_PlainText}. To get one of your global functions, operations, attributes etc. to appear in the package manual, simply insert an \textsf{AutoDoc} comment of the form \texttt{\#!} directly in front of it. For example: \begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=] #! DeclareOperation( "ToricVariety", [ IsConvexObject ] ); \end{Verbatim} 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: Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the \texttt{Declare...} statement. \begin{Verbatim}[commandchars=|BE,fontsize=\small,frame=single,label=] #! @Arguments conv #! @Returns a toric variety #! @Description #! Creates a toric variety out #! of the convex object <A>conv</A>. DeclareOperation( "ToricVariety", [ IsConvexObject ] ); \end{Verbatim} In these comment lines, you can freely use normal \textsf{GAPDoc} XML markup (with the usual exceptions for lines starting with \texttt{@}, which are interpreted as \textsf{AutoDoc} commands). So, for instance, tags like \texttt{{\textless}Ref{\textgreater}}, \texttt{{\textless}A{\textgreater}}, \texttt{{\textless}K{\textgreater}}, \texttt{{\textless}List{\textgreater}}, etc. can be written directly in \texttt{\#!} comment text. For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using \texttt{\#! @Chapter}, \texttt{\#! @Section}, and related commands, while others prefer standalone \texttt{.autodoc} files. In an \texttt{.autodoc} file you write the same commands without the \texttt{\#!} prefix, and you list the file in \texttt{autodoc.files} or place it in a directory scanned via \texttt{autodoc.scan{\textunderscore}dirs}. AutoDoc itself still uses the source\texttt{\symbol{45}}comment style in places, for example in \texttt{gap/Magic.gd}. One caveat applies if you decide to keep prose in a standalone \texttt{.autodoc} file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue \texttt{\#60} in the AutoDoc issue tracker. For a thorough description of what you can do with \textsf{AutoDoc} documentation comments, please refer to chapter \ref{Chapter_Comments}. Suppose you have not been using \textsf{GAPDoc} before but instead used the process described in section \ref{Section_Tut:Scratch} to create your manual. Then the following \textsf{GAP} command will regenerate the manual and automatically include all newly documented functions, operations etc.: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true, autodoc := true ) ); \end{Verbatim} If you are not using the scaffolding feature, e.g. because you already have an existing \textsf{GAPDoc} based manual, then you can still use \textsf{AutoDoc} documentation comments and standalone \texttt{.autodoc} files. Just make sure to first edit the main XML file of your documentation, and insert the line \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] <#Include SYSTEM "_AutoDocMainFile.xml"> \end{Verbatim} in a suitable place. This means that you can mix \textsf{AutoDoc} documentation comments and \texttt{.autodoc} files freely with your existing documentation; you can even still make use of any existing \textsf{GAPDoc} documentation comments in your code. The following command should be useful for you in this case; it still scans the package code for \textsf{AutoDoc} documentation comments and then runs \textsf{GAPDoc} to produce HTML and PDF output, but does not touch your documentation XML files otherwise. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) ); \end{Verbatim} } \section{\textcolor{Chapter }{Using \textsf{AutoDoc} in an existing \textsf{GAPDoc} manual}}\label{Section_Tut:IntegrateExisting} \logpage{[ 2, 4, 0 ]} \hyperdef{L}{X7FA614637B807F4D}{} { Even if you already have an existing \textsf{GAPDoc} manual, it might be interesting for you to use \textsf{AutoDoc} for two purposes: First, with \textsf{AutoDoc} it 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 \texttt{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 \textsf{AutoDoc} for this purpose only, e.g. \textsf{io} and \textsf{orb}. In particular, this setup works well if you want to keep your existing manual structure and only adopt selected \textsf{AutoDoc} features first; for example automatic title\texttt{\symbol{45}}page data and predefined entities such as \texttt{\&VERSION;}, \texttt{\&RELEASEYEAR;} and \texttt{\&RELEASEDATE;} (see Section \ref{Subsection_Tut:PackageInfo:Entities}). \subsection{\textcolor{Chapter }{Using \textsf{AutoDoc} on a complete \textsf{GAPDoc} manual}}\label{Subsection_Tut:IntegrateExisting:EverythingThere} \logpage{[ 2, 4, 1 ]} \hyperdef{L}{X7F3CEB097AF47C1E}{} { Suppose you already have a complete XML manual, with some main and title XML files and some documentation for operations distributed over all your \texttt{.g}, \texttt{.gd}, and \texttt{.gi} files. Suppose the main XML file is named \texttt{PACKAGENAME.xml} and is in the \texttt{/doc} subdirectory of your package. Then you can rebuild your manual by executing the following two \textsf{GAP} commands from a \textsf{GAP} session started in the root directory of your package: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( ); \end{Verbatim} Note that in particular, you do not have to worry about keeping a list of your implementation files up\texttt{\symbol{45}}to\texttt{\symbol{45}}date. But there is more. \textsf{AutoDoc} can create \texttt{.tst} files from the examples in your manual to test your package. This can be achieved via \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := true ) ); \end{Verbatim} Now files \texttt{PACKAGENAME01.tst}, \texttt{PACKAGENAME02.tst} and so appear in the \texttt{tst/} subdirectory of your package, and can be tested as usual using \texttt{Test} (\textbf{Reference: Test}) respectively \texttt{TestDirectory} (\textbf{Reference: TestDirectory}). If you prefer to keep generated tests in a separate location, set \texttt{extract{\textunderscore}examples.subdir} to a path relative to the package root: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) ); \end{Verbatim} This writes the extracted examples into \texttt{tst/generated/} instead. } \subsection{\textcolor{Chapter }{Setting different \textsf{GAPDoc} options}}\label{Subsection_Tut:IntegrateExisting:GapDocOptions} \logpage{[ 2, 4, 2 ]} \hyperdef{L}{X7D0DDF2284F2D24A}{} { Sometimes, the default values for the \textsf{GAPDoc} command used by \textsf{AutoDoc} may not be suitable for your manual. Suppose your main XML file is \emph{not} named \texttt{PACKAGENAME.xml}, but rather something else, e.g. \texttt{main.xml}. Then you can tell \textsf{AutoDoc} to use this file as the main XML file via \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( main := "main" ) ) ); \end{Verbatim} \textsf{AutoDoc} can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option \texttt{autodoc.scan{\textunderscore}dirs} controls where it looks for source comments beginning with \texttt{\#!} and for standalone \texttt{.autodoc} files. By default, it scans the package root directory and the subdirectories \texttt{gap}, \texttt{lib}, \texttt{examples} and \texttt{examples/doc}; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust \texttt{autodoc.scan{\textunderscore}dirs}. The following example instructs \textsf{AutoDoc} to only search in the subdirectory \texttt{package{\textunderscore}sources} of the package's root directory for those files. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( scan_dirs := [ "package_sources" ] ) ) ); \end{Verbatim} The separate option \texttt{gapdoc.scan{\textunderscore}dirs} serves a different purpose: it controls where \textsf{GAPDoc} comments are searched for. 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: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) ); \end{Verbatim} Giving such a file does not prevent the standard \texttt{scan{\textunderscore}dirs} from being scanned for other files. Next, \textsf{GAPDoc} supports the documentation to be built with relative paths. This means, links to manuals of other packages or the \textsf{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 \textsf{GAP} installation around later. Suppose you are starting \textsf{GAP} in the root path of your package as always, and the standard call of \texttt{AutoDoc} (\ref{AutoDoc}) will then build the documentation in the \texttt{doc} subdirectory of your package. From this directory, the gap root directory has the relative path \texttt{../../..}. Then you can enable the relative paths by \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := "../../.." ) ) ); \end{Verbatim} or, since \texttt{../../..} is the standard option for \texttt{gap{\textunderscore}root{\textunderscore}relative{\textunderscore}path}, by \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( gapdoc := rec( gap_root_relative_path := true ) ) ); \end{Verbatim} The same behavior is also available via the global option \texttt{relativePath}. This is particularly convenient in a short \texttt{makedoc.g} script, and it overrides \texttt{gapdoc.gap{\textunderscore}root{\textunderscore}relative{\textunderscore}path} if both are given. Since this is a GAP global option, you can also set it outside the eventual \texttt{AutoDoc} (\ref{AutoDoc}) call and let it propagate through nested calls; see (\textbf{Reference: Options Stack}) for more information about GAP's global options system: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : relativePath := "../../.." ); \end{Verbatim} If you pass \texttt{relativePath := true}, then \textsf{AutoDoc} uses the default relative path \texttt{../../..}. For example, if your \texttt{makedoc.g} reads the manual via \texttt{AutoDoc} (\ref{AutoDoc}), then the following command sets both \texttt{relativePath} and \texttt{nopdf} to \texttt{true} for that nested call: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] Read( "makedoc.g" : nopdf, relativePath ); \end{Verbatim} Finally, if you only want HTML and text output, you can suppress PDF generation with the global option \texttt{nopdf}: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : nopdf ); \end{Verbatim} This is useful if \texttt{pdflatex} is unavailable, or when you want a faster documentation rebuild while editing. You can also request the same behavior from the shell by setting the environment variable \texttt{NOPDF} before invoking \texttt{makedoc.g}. For example: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] NOPDF=1 gap makedoc.g \end{Verbatim} If \texttt{NOPDF} is set, \textsf{AutoDoc} skips PDF generation even if no \texttt{nopdf} option is given in the GAP code. } \subsection{\textcolor{Chapter }{Checklist for converting an existing \textsf{GAPDoc} manual to use \textsf{AutoDoc}}}\label{Subsection_Tut:Checklist} \logpage{[ 2, 4, 3 ]} \hyperdef{L}{X83448D91868D7994}{} { Here is a checklist for authors of a package \textsf{PackageName}, \emph{which already has a \textsf{GAPDoc} based manual}, who wish to use \textsf{AutoDoc} to build the manual from now on. We assume that the manual is currently built by reading a file \texttt{makedoc.g} and that the main \texttt{.xml} file is named \texttt{manual.xml}. The files \texttt{PackageInfo.g}, \texttt{makedoc.g}, \texttt{doc/title.xml} and \texttt{doc/{\textunderscore}main.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 \textsf{AutoDoc} files \texttt{PackageInfo.g} and \texttt{makedoc.g} to hand when reading these instructions. \begin{itemize} \item Copy \texttt{AutoDoc/makedoc.g} to \texttt{PackageName/makedoc.g}. \item Edit \texttt{PackageName/makedoc.g} as follows. \begin{itemize} \item Change the header comment to match other files in your package. \item After \texttt{LoadPackage("AutoDoc");} add \texttt{LoadPackage("PackageName");}. \item In the \texttt{AutoDoc} record delete \texttt{autodoc := true;}. \item \index{Scaffold record in makedoc.g@} In the \texttt{scaffold} record change the \texttt{includes} list to be the list of your \texttt{.xml} files that are contained in \texttt{manual.xml}. \item \index{Bibliography field in makedoc.g@} If you do not have a bibliography you may delete the \texttt{bib := "bib.xml",} field in the scaffold. Otherwise, edit the file name if you have a different file. If you only have a \texttt{.bib} file (\texttt{manual.bib} or \texttt{bib.xml.bib} say) you should rename this file \texttt{PackageName.bib}. \item \index{LaTeXOptions record in makedoc.g@} In the \texttt{LaTeXOptions} record, which is in the \texttt{gapdoc} record, enter any {\LaTeX} \texttt{newcommands} previously in \texttt{manual.xml}. (If there are none you may safely delete this record.) To illustrate this option, the \textsf{AutoDoc} file \texttt{makedoc.g} defines the command \texttt{\texttt{\symbol{92}}bbZ} by \texttt{\texttt{\symbol{92}}newcommand\texttt{\symbol{123}}\texttt{\symbol{92}}bbZ\texttt{\symbol{125}}\texttt{\symbol{123}}\texttt{\symbol{92}}mathbb\texttt{\symbol{123}}Z\texttt{\symbol{125}}\texttt{\symbol{125}}}, which may be used to produce the {\LaTeX} formula $f : \bbZ^2 \to \bbZ$. However, note that this only works in the PDF version of the file. \end{itemize} \item Now edit \texttt{PackageName/PackageInfo.g} as follows. \begin{itemize} \item Delete any \texttt{PKGVERSIONDATA} chunk that may be there. One reason for converting your manual to use \textsf{AutoDoc} is to stop using entities such as \texttt{PACKAGENAMEVERSION}. \item Copy the \texttt{AutoDoc} record from \texttt{AutoDoc/PackageInfo.g} to the end of your file (just before the final \texttt{"));"}. \item \index{Copyright field in PackageInfo.g@} \index{Abstract field in PackageInfo.g@} \index{Acknowledgements field in PackageInfo.g@} Replace the \texttt{Copyright}, \texttt{Abstract} and \texttt{Acknowledgements} fields of the \texttt{TitlePage} record with the corresponding material from your \texttt{manual.xml}. (If you do not have an abstract, then delete the \texttt{Abstract} field, etc.) \item \index{Entities record in makedoc.g@} In the \texttt{entities} record enter any entities previously stored in your \texttt{manual.xml}. (Again, if you have none, you may safely delete this record.) To illustrate this option the \textsf{AutoDoc} file \texttt{PackageInfo.g} defines entities for the names of packages \textsf{io} and \textsf{PackageName}. \end{itemize} \item If you are using a GitHub repository, as well as running "\texttt{git add}" on files \texttt{makedoc.g}, \texttt{PackageInfo.g} and \texttt{doc/PackageName.bib}, you should run "\texttt{git rm \texttt{\symbol{45}}f}" on files \texttt{doc/manual.xml}, and \texttt{doc/title.xml}. \end{itemize} You should now be ready to run \textsf{GAP} and \texttt{Read("makedoc.g");} in your package root directory. } } \section{\textcolor{Chapter }{Scaffolds}}\label{Section_Tut:Scaffolds} \logpage{[ 2, 5, 0 ]} \hyperdef{L}{X8524193D824CDE0D}{} { \subsection{\textcolor{Chapter }{Generating a title page}}\label{Subsection_Tut:Scaffolds:Title} \logpage{[ 2, 5, 1 ]} \hyperdef{L}{X7CF22DE28478316F}{} { For most (if not all) \textsf{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 \texttt{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. \textsf{GAPDoc} can help to a degree with this via entities. Thus, you will sometimes see code like this in \texttt{PackageInfo.g} files: \begin{Verbatim}[commandchars=@|B,fontsize=\small,frame=single,label=] 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> \end{Verbatim} 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 \textsf{AutoDoc} to generate a title page for your manual based on the information in your \texttt{PackageInfo.g}. The following commands do just that (in addition to building your manual), by generating a file called \texttt{doc/title.xml}. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := rec( MainPage := false ) ) ); \end{Verbatim} Note that this only outputs \texttt{doc/title.xml} but does not touch any other files of your documentation. In particular, you need to explicitly include \texttt{doc/title.xml} from your main XML file. However, you can also tell \textsf{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 \textsf{AutoDoc} not to generate a main page. } \subsection{\textcolor{Chapter }{Generating the main XML file}}\label{Subsection_Tut:Scaffolds:Main} \logpage{[ 2, 5, 2 ]} \hyperdef{L}{X7CD72CC780874FD5}{} { 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 \textsf{AutoDoc} documentation comments. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) ); \end{Verbatim} You can instruct \textsf{AutoDoc} to include additional XML files by giving it a list of filenames, as in the following example: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] LoadPackage( "AutoDoc" ); AutoDoc(rec( scaffold := rec( includes := [ "somefile.xml", "anotherfile.xml" ] ) )); \end{Verbatim} For more information, please consult the documentation of the \texttt{AutoDoc} (\ref{AutoDoc}) function. } \subsection{\textcolor{Chapter }{What data is used from \texttt{PackageInfo.g}?}}\label{Subsection_Tut:PackageInfo} \logpage{[ 2, 5, 3 ]} \hyperdef{L}{X799956EA85D3FC15}{} { \textsf{AutoDoc} can use data from \texttt{PackageInfo.g} in order to generate a title page. Specifically, the following components of the package info record are taken into account: \begin{description} \item[{PackageName}] This is used to set the \texttt{{\textless}Title{\textgreater}} element of the title page. \item[{Subtitle}] This is used to set the \texttt{{\textless}Subtitle{\textgreater}} element of the title page. \item[{Version}] This is used to set the \texttt{{\textless}Version{\textgreater}} element of the title page, with the string ``Version '' prepended. \item[{Date}] This is used to set the \texttt{{\textless}Date{\textgreater}} element of the title page. \item[{Persons}] This is used to generate \texttt{{\textless}Author{\textgreater}} elements in the generated title page. \item[{PackageDoc}] This is a record (or a list of records) which is used to tell the \textsf{GAP} help system about the package manual. Currently \textsf{AutoDoc} extracts the value of the \texttt{PackageDoc.BookName} component and then passes that on to \textsf{GAPDoc} when creating the HTML, PDF and text versions of the manual. \item[{AutoDoc}] This record controls extra settings used by \textsf{AutoDoc} while generating the manual. In particular, \texttt{PkgInfo.AutoDoc.TitlePage} lets you add or override title\texttt{\symbol{45}}page elements coming from package metadata. Typical fields you may set there include \texttt{TitleComment}, \texttt{Abstract}, \texttt{Copyright}, \texttt{Acknowledgements} and \texttt{Colophon}. For example, in \texttt{PackageInfo.g}: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] SetPackageInfo( rec( ... AutoDoc := rec( TitlePage := rec( Copyright := "(C) 2026 Jane Doe", Acknowledgements := "Funded by Example Grant 1234." ) ) ) ); \end{Verbatim} This inserts \texttt{{\textless}Copyright{\textgreater}} and \texttt{{\textless}Acknowledgements{\textgreater}} blocks into the generated \texttt{title.xml}. \texttt{PkgInfo.AutoDoc.TitlePage} has exactly the same meaning as \texttt{scaffold.TitlePage} in \texttt{AutoDoc} (\ref{AutoDoc}). The function documentation for \texttt{scaffold.TitlePage} points back to this subsection. \end{description} } \subsection{\textcolor{Chapter }{Entities from \texttt{PackageInfo.g} and scaffold options}}\label{Subsection_Tut:PackageInfo:Entities} \logpage{[ 2, 5, 4 ]} \hyperdef{L}{X79EAEF277DD1FAE1}{} { Besides title\texttt{\symbol{45}}page fields, you can define custom entities in \texttt{AutoDoc.entities} inside \texttt{PackageInfo.g}. They are written to \texttt{doc/{\textunderscore}entities.xml}, so they can be used both by generated main files and by hand\texttt{\symbol{45}}written main XML files. In addition, \textsf{AutoDoc} predefines the entities \texttt{VERSION}, \texttt{RELEASEYEAR} and \texttt{RELEASEDATE}, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with \texttt{PackageInfo.g}. You can specify scaffold\texttt{\symbol{45}}related settings in \texttt{PackageInfo.g} and in your \texttt{makedoc.g} call at the same time; both records are merged, and values from \texttt{makedoc.g} take precedence when both define the same key. } } \section{\textcolor{Chapter }{Worksheets}}\label{Section_Tut:WorksheetsPointer} \logpage{[ 2, 6, 0 ]} \hyperdef{L}{X801D4A2F8292704C}{} { For stand\texttt{\symbol{45}}alone documents that are not tied to a package, use \texttt{AutoDocWorksheet} (\ref{AutoDocWorksheet}). Its documentation and examples are in Section \ref{Section_AutoDocWorksheet} of chapter \ref{AutoDoc}. } } \chapter{\textcolor{Chapter }{\textsf{AutoDoc} documentation comments}}\label{Chapter_Comments} \logpage{[ 3, 0, 0 ]} \hyperdef{L}{X87668C487B1A2094}{} { You can document declarations of global functions and variables, operations, attributes etc. by inserting \emph{\textsf{AutoDoc}} comments into your sources before these declarations. An \textsf{AutoDoc} comment always starts with \texttt{\#!}. This is also the smallest possible \textsf{AutoDoc} command. If you want your declaration documented, just write \texttt{\#!} at the line before the documentation. For example: \begin{Verbatim}[commandchars=@|B,fontsize=\small,frame=single,label=] #! DeclareOperation( "AnOperation", [ IsList ] ); \end{Verbatim} This will produce a manual entry for the operation \texttt{AnOperation}. For declaration documentation, the associated declaration must appear immediately after the \textsf{AutoDoc} comment block. In particular, do not insert other code (such as \texttt{if false then} or assignments) between the comment block and the \texttt{Declare...} statement. This also works for \texttt{InstallMethod} and \texttt{InstallOtherMethod}. In that case, \textsf{AutoDoc} uses the installed method's name and filter list to create a manual entry for the implemented item. Inside of \textsf{AutoDoc} comments, \emph{\textsf{AutoDoc} commands} starting with \texttt{@} can be used to control the output \textsf{AutoDoc} produces. Any comment line that does \emph{not} start with an \textsf{AutoDoc} command is treated as regular documentation text and may contain (almost) arbitrary \textsf{GAPDoc} XML markup, such as \texttt{{\textless}Ref{\textgreater}}, \texttt{{\textless}A{\textgreater}}, \texttt{{\textless}List{\textgreater}}, and similar tags. This lets you use the normal \textsf{GAPDoc} formatting toolbox directly inside \textsf{AutoDoc} comments. For example: \begin{Verbatim}[commandchars=|BE,fontsize=\small,frame=single,label=] #! @Description #! See <Ref Chap="Chapter_Tutorials"/> for setup details. #! The argument <A>obj</A> must satisfy <K>IsObject</K>. \end{Verbatim} As explained in chapter \ref{Chapter_Overview}, you can combine \textsf{AutoDoc} comments with hand\texttt{\symbol{45}}written XML and classic \textsf{GAPDoc} comments. For practical setup and migration workflows, see chapter \ref{Chapter_Tutorials}. \section{\textcolor{Chapter }{Documenting declarations}}\label{Chapter_Comments_Section_Documenting_declarations} \logpage{[ 3, 1, 0 ]} \hyperdef{L}{X871482CE838C68F6}{} { In the bare form above, the manual entry for \texttt{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 \textsf{AutoDoc} comment before the declaration. Currently, the following commands are provided: \subsection{\textcolor{Chapter }{\texttt{@Description \mbox{\texttt{\mdseries\slshape descr}}}}}\label{Subsection_@Description} \logpage{[ 3, 1, 1 ]} \hyperdef{L}{X7F1D85188262A827}{} { \index{"@Description@\texttt{"@Description \mbox{\texttt{\mdseries\slshape descr}}}} Adds the text in the following lines of the \textsf{AutoDoc} to the description of the declaration in the manual. Lines are until the next \textsf{AutoDoc} command or until the declaration is reached. } \subsection{\textcolor{Chapter }{\texttt{@Returns \mbox{\texttt{\mdseries\slshape ret val}}}}}\label{Subsection_@Returns} \logpage{[ 3, 1, 2 ]} \hyperdef{L}{X7EFF79F47BE24F78}{} { \index{"@Returns@\texttt{"@Returns \mbox{\texttt{\mdseries\slshape ret{\textunderscore}val}}}} The string \mbox{\texttt{\mdseries\slshape ret{\textunderscore}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. } \subsection{\textcolor{Chapter }{\texttt{@Arguments \mbox{\texttt{\mdseries\slshape args}}}}}\label{Subsection_@Arguments} \logpage{[ 3, 1, 3 ]} \hyperdef{L}{X81DAA454857F7971}{} { \index{"@Arguments@\texttt{"@Arguments \mbox{\texttt{\mdseries\slshape args}}}} The string \mbox{\texttt{\mdseries\slshape 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 \textsf{GAP} options are used, this can be followed by a colon : and one or more assignments, like ``n[, r]: tries := 100''. For \texttt{DeclareGlobalName}, using \texttt{@Arguments} or \texttt{@Returns} also makes \textsf{AutoDoc} document the item as a function. This is useful because \texttt{DeclareGlobalName} itself does not reveal whether the name denotes a function or a variable. } \subsection{\textcolor{Chapter }{\texttt{@ItemType \mbox{\texttt{\mdseries\slshape kind}}}}}\label{Subsection_@ItemType} \logpage{[ 3, 1, 4 ]} \hyperdef{L}{X852A9FCA7AB6EC4E}{} { \index{"@ItemType@\texttt{"@ItemType \mbox{\texttt{\mdseries\slshape kind}}}} Overrides the kind of manual item created for the following declaration or installed method. The supported values are \texttt{Attr}, \texttt{Cat}, \texttt{Coll}, \texttt{Constr}, \texttt{Fam}, \texttt{Filt}, \texttt{Func}, \texttt{InfoClass}, \texttt{Meth}, \texttt{Oper}, \texttt{Prop}, \texttt{Repr}, and \texttt{Var}. The values \texttt{Cat}, \texttt{Coll}, and \texttt{Repr} are \textsf{AutoDoc}\texttt{\symbol{45}}specific aliases. They emit \texttt{Filt} entries with the corresponding \textsf{GAPDoc} filter type. This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as \texttt{DeclareAttribute} or \texttt{DeclareProperty}, \textsf{AutoDoc} already knows the intended type from the declaration itself. It is useful for \texttt{DeclareGlobalName}, because that declaration can refer to either a function or a variable. \textsf{AutoDoc} defaults such entries to \texttt{Var}, but switches to \texttt{Func} as soon as \texttt{@Arguments} or \texttt{@Returns} indicates function\texttt{\symbol{45}}style documentation. You can still use \texttt{@ItemType} to override this explicitly. It is useful for \texttt{DeclareSynonym}, because that declaration can document a function synonym or one of several filter\texttt{\symbol{45}}like synonyms. Use \texttt{@ItemType Filt}, \texttt{Cat}, \texttt{Coll}, or \texttt{Repr} to control which kind of filter entry should be emitted. For example: \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @ItemType Repr DeclareSynonym( "IsSomethingRep", IsComponentObjectRep ); \end{Verbatim} This makes \textsf{AutoDoc} emit a \texttt{{\textless}Filt Type="Representation" .../{\textgreater}} manual entry. } \subsection{\textcolor{Chapter }{\texttt{@Group \mbox{\texttt{\mdseries\slshape grpname}}}}}\label{Subsection_@Group} \logpage{[ 3, 1, 5 ]} \hyperdef{L}{X8677FE8F80C00B14}{} { \index{"@Group@\texttt{"@Group \mbox{\texttt{\mdseries\slshape grpname}}}} Adds the following method to a group with the given name. See section \ref{Section_Groups} for more information about groups. } \subsection{\textcolor{Chapter }{\texttt{@Label \mbox{\texttt{\mdseries\slshape label}}}}}\label{Subsection_@Label} \logpage{[ 3, 1, 6 ]} \hyperdef{L}{X7B0E20A27D64DF6F}{} { \index{"@Label@\texttt{"@Label \mbox{\texttt{\mdseries\slshape 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 \texttt{DeclareOperation}, \texttt{DeclareAttribute}, etc.), a default label is generated from this filter list. \begin{Verbatim}[commandchars=|BC,fontsize=\small,frame=single,label=] #! @Label testlabel DeclareProperty( "AProperty", IsObject ); \end{Verbatim} leads to this: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] <ManSection> <Prop Arg="arg" Name="AProperty" Label="testlabel"/> <Returns> <K>true</K> or <K>false</K> </Returns> <Description> </Description> </ManSection> \end{Verbatim} while \begin{Verbatim}[commandchars=@|B,fontsize=\small,frame=single,label=] #! DeclareProperty( "AProperty", IsObject ); \end{Verbatim} leads to this: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] <ManSection> <Prop Arg="arg" Name="AProperty" Label="for IsObject"/> <Returns> <K>true</K> or <K>false</K> </Returns> <Description> </Description> </ManSection> \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@ChapterInfo \mbox{\texttt{\mdseries\slshape chapter}}, \mbox{\texttt{\mdseries\slshape section}}}}}\label{Subsection_@ChapterInfo} \logpage{[ 3, 1, 7 ]} \hyperdef{L}{X78938EE37A532FFA}{} { \index{"@ChapterInfo@\texttt{"@ChapterInfo}} Adds the entry to the given chapter and section. Here, \mbox{\texttt{\mdseries\slshape chapter}} and \mbox{\texttt{\mdseries\slshape section}} are the respective titles. As an example, a full \textsf{AutoDoc} comment with all options could look like this: \begin{Verbatim}[commandchars=|EF,fontsize=\small,frame=single,label=] #! @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 ); \end{Verbatim} } } \section{\textcolor{Chapter }{Other documentation comments}}\label{Chapter_Comments_Section_Other_documentation_comments} \logpage{[ 3, 2, 0 ]} \hyperdef{L}{X8152FEF9844B1ACD}{} { There are also some commands which can be used in \textsf{AutoDoc} comments that are not associated to any declaration. This is useful for additional text in your documentation, examples, mathematical chapters, etc. \subsection{\textcolor{Chapter }{\texttt{@Chapter \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@Chapter} \logpage{[ 3, 2, 1 ]} \hyperdef{L}{X823E613385D09F6F}{} { \index{"@Chapter@\texttt{"@Chapter}} \index{"@ChapterLabel@\texttt{"@ChapterLabel}} \index{"@ChapterTitle@\texttt{"@ChapterTitle}} Sets the active chapter, all subsequent functions which do not have an explicit chapter declared in their \textsf{AutoDoc} comment via \texttt{@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 \texttt{@Description}, will be added to the chapter as regular text. Additionally, the chapters label will be set to \texttt{Chapter{\textunderscore}}\mbox{\texttt{\mdseries\slshape name}}. Example: \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @Chapter My chapter #! This is my chapter. #! I document my stuff in it. \end{Verbatim} The \texttt{@ChapterLabel} \mbox{\texttt{\mdseries\slshape label}} command can be used to set the label of the chapter to \texttt{Chapter{\textunderscore}}\mbox{\texttt{\mdseries\slshape label}} instead of \texttt{Chapter{\textunderscore}}\mbox{\texttt{\mdseries\slshape name}}. Additionally, the chapter will be stored as \texttt{{\textunderscore}Chapter{\textunderscore}}\mbox{\texttt{\mdseries\slshape label}}\texttt{.xml}. The \texttt{@ChapterTitle} \mbox{\texttt{\mdseries\slshape title}} command can be used to set a heading for the chapter that is different from \mbox{\texttt{\mdseries\slshape name}}. Note that the title does not affect the label. If you use all three commands, i.e., \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @Chapter name #! @ChapterLabel label #! @ChapterTitle title \end{Verbatim} \texttt{title} is used for the headline, \texttt{label} for cross\texttt{\symbol{45}}referencing, and \texttt{name} for setting the same chapter as active chapter again. } \subsection{\textcolor{Chapter }{\texttt{@Appendix \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@Appendix} \logpage{[ 3, 2, 2 ]} \hyperdef{L}{X83163DA586882825}{} { \index{"@Appendix@\texttt{"@Appendix}} This is analogous to \texttt{@Chapter}, but generates \texttt{Appendix} elements instead of \texttt{Chapter} elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in \texttt{scaffold.appendix}. Example: \begin{Verbatim}[commandchars=!|B,fontsize=\small,frame=single,label=] @Appendix Supplementary material @Section Additional tables \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@Section \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@Section} \logpage{[ 3, 2, 3 ]} \hyperdef{L}{X78AA98BA7E0635D0}{} { \index{"@Section@\texttt{"@Section}} \index{"@SectionLabel@\texttt{"@SectionLabel}} \index{"@SectionTitle@\texttt{"@SectionTitle}} Sets an active section like \texttt{@Chapter} sets an active chapter. The section automatically ends with the next \texttt{@Section} or \texttt{@Chapter} command. \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @Section My first manual section #! In this section I am going to document my first method. \end{Verbatim} The \texttt{@SectionLabel} \mbox{\texttt{\mdseries\slshape label}} command can be used to set the label of the section to \texttt{Section{\textunderscore}}\mbox{\texttt{\mdseries\slshape label}} instead of \texttt{Chapter{\textunderscore}chaptername{\textunderscore}Section{\textunderscore}}\mbox{\texttt{\mdseries\slshape name}}. The \texttt{@SectionTitle} \mbox{\texttt{\mdseries\slshape title}} command can be used to set a heading for the section that is different from \mbox{\texttt{\mdseries\slshape name}}. } \subsection{\textcolor{Chapter }{\texttt{@Subsection \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@Subsection} \logpage{[ 3, 2, 4 ]} \hyperdef{L}{X7FD77434802A3580}{} { \index{"@Subsection@\texttt{"@Subsection}} \index{"@SubsectionLabel@\texttt{"@SubsectionLabel}} \index{"@SubsectionTitle@\texttt{"@SubsectionTitle}} Sets an active subsection like \texttt{@Section} sets an active section. The subsection automatically ends with the next \texttt{@Subsection}, \texttt{@Section} or \texttt{@Chapter} command. It also ends with the next documented function. Indeed, internally each function ``manpage'' is treated like a subsection. \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @Subsection My first manual subsection #! In this subsection I am going to document my first example. \end{Verbatim} The \texttt{@SubsectionLabel} \mbox{\texttt{\mdseries\slshape label}} command can be used to set the label of the subsection to \texttt{Subsection{\textunderscore}}\mbox{\texttt{\mdseries\slshape label}} instead of \texttt{Chapter{\textunderscore}chaptername{\textunderscore}Section{\textunderscore}sectionname{\textunderscore}Subsection{\textunderscore}}\mbox{\texttt{\mdseries\slshape name}}. The \texttt{@SubsectionTitle} \mbox{\texttt{\mdseries\slshape title}} command can be used to set a heading for the subsection that is different from \mbox{\texttt{\mdseries\slshape name}}. } \subsection{\textcolor{Chapter }{\texttt{@BeginGroup \mbox{\texttt{\mdseries\slshape [grpname]}}}}}\label{Subsection_@BeginGroup} \logpage{[ 3, 2, 5 ]} \hyperdef{L}{X7D3060C17EDBCED1}{} { \index{"@BeginGroup@\texttt{"@BeginGroup}} Starts a group. All following documented declarations without an explicit \texttt{@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 \texttt{@EndGroup} command is reached. See section \ref{Section_Groups} for more information about groups. } \subsection{\textcolor{Chapter }{\texttt{@EndGroup}}}\label{Subsection_@EndGroup} \logpage{[ 3, 2, 6 ]} \hyperdef{L}{X7C17EB007FD42C87}{} { \index{"@EndGroup@\texttt{"@EndGroup}} Ends the current group. \begin{Verbatim}[commandchars=|CF,fontsize=\small,frame=single,label=] #! @BeginGroup MyGroup #! DeclareAttribute( "GroupedAttribute", IsList ); DeclareOperation( "NonGroupedOperation", [ IsObject ] ); #! DeclareOperation( "GroupedOperation", [ IsList, IsRubbish ] ); #! @EndGroup \end{Verbatim} } \subsection{\textcolor{Chapter }{@GroupTitle \mbox{\texttt{\mdseries\slshape title}}}}\label{Subsection_@GroupTitle} \logpage{[ 3, 2, 7 ]} \hyperdef{L}{X82FB96F37FAE8167}{} { \index{"@GroupTitle@\texttt{"@GroupTitle}} Sets the subsection heading for the current group to \mbox{\texttt{\mdseries\slshape title}}. In the absence of any \texttt{@GroupTitle} command, the heading will be the name of the first entry in the group. See \ref{Section_Groups} for more information. } \subsection{\textcolor{Chapter }{\texttt{@BeginExample} and \texttt{@EndExample}}}\label{Subsection_@BeginExample} \logpage{[ 3, 2, 8 ]} \hyperdef{L}{X83D6DA3B83D3436C}{} { \index{"@BeginExample@\texttt{"@BeginExample}} \index{"@EndExample@\texttt{"@EndExample}} \texttt{@BeginExample} marks the start of an example to be put into the manual. It differs from \textsf{GAPDoc}'s \texttt{{\textless}Example{\textgreater}} (see (\textbf{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 \textsf{GAP}, and parsed by \textsf{AutoDoc}. To achieve this, \textsf{GAP} commands are not preceded by a comment, while output has to be preceded by an \textsf{AutoDoc} comment. The \texttt{gap{\textgreater}} prompt for the display in the manual is added by \textsf{AutoDoc}. \texttt{@EndExample} ends the example block. To illustrate this command, consider this input: \begin{Verbatim}[commandchars=|AC,fontsize=\small,frame=single,label=] #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample \end{Verbatim} This results in the following output: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@S5 := SymmetricGroup(5);| Sym( [ 1 .. 5 ] ) !gapprompt@gap>| !gapinput@Order(S5);| 120 \end{Verbatim} The \textsf{AutoDoc} command \texttt{@Example} is an alias of \texttt{@BeginExample}. If you enable \texttt{extract{\textunderscore}examples := true} when calling \texttt{AutoDoc} (\ref{AutoDoc}), these examples can also be turned into \texttt{.tst} files (see Section \ref{Subsection_Tut:IntegrateExisting:EverythingThere}). } \subsection{\textcolor{Chapter }{\texttt{@BeginExampleSession} and \texttt{@EndExampleSession}}}\label{Subsection_@BeginExampleSession} \logpage{[ 3, 2, 9 ]} \hyperdef{L}{X861E2E778510CAF7}{} { \index{"@BeginExampleSession@\texttt{"@BeginExampleSession}} \index{"@EndExampleSession@\texttt{"@EndExampleSession}} \texttt{@BeginExampleSession} marks the start of an example to be put into the manual, while \texttt{@EndExampleSession} ends the example block. It is the direct analog of \textsf{GAPDoc}'s \texttt{{\textless}Example{\textgreater}} (see (\textbf{GAPDoc: Log})). To illustrate this command, consider this input: \begin{Verbatim}[commandchars=|AC,fontsize=\small,frame=single,label=] #! @BeginExampleSession #! gap> S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) #! gap> Order(S5); #! 120 #! @EndExampleSession \end{Verbatim} This results in the following output: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@S5 := SymmetricGroup(5);| Sym( [ 1 .. 5 ] ) !gapprompt@gap>| !gapinput@Order(S5);| 120 \end{Verbatim} It inserts an example into the manual just as \texttt{@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 \textsf{AutoDoc} comment (\texttt{\#!}). 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 \texttt{\#!} and the \texttt{gap{\textgreater}} prompt. The \textsf{AutoDoc} command \texttt{@ExampleSession} is an alias of \texttt{@BeginExampleSession}. } \subsection{\textcolor{Chapter }{\texttt{@BeginLog} and \texttt{@EndLog}}}\label{Subsection_@BeginLog} \logpage{[ 3, 2, 10 ]} \hyperdef{L}{X81A2D44D834C0A17}{} { \index{"@BeginLog@\texttt{"@BeginLog}} \index{"@EndLog@\texttt{"@EndLog}} Works just like the \texttt{@BeginExample} command, but the example will not be tested. See the \textsf{GAPDoc} manual for more information. The \textsf{AutoDoc} command \texttt{@Log} is an alias of \texttt{@BeginLog}. } \subsection{\textcolor{Chapter }{\texttt{@BeginLogSession} and \texttt{@EndLogSession}}}\label{Subsection_@BeginLogSession} \logpage{[ 3, 2, 11 ]} \hyperdef{L}{X7BADE876794FF309}{} { \index{"@BeginLogSession@\texttt{"@BeginLogSession}} \index{"@EndLogSession@\texttt{"@EndLogSession}} Works just like the \texttt{@BeginExampleSession} command, but the example will not be tested if manual examples are run. It is the direct analog of \textsf{GAPDoc}'s \texttt{{\textless}Log{\textgreater}} (see (\textbf{GAPDoc: Log})). The \textsf{AutoDoc} command \texttt{@LogSession} is an alias of \texttt{@BeginLogSession}. } \subsection{\textcolor{Chapter }{\texttt{@DoNotReadRestOfFile}}}\label{Subsection_@DoNotReadRestOfFile} \logpage{[ 3, 2, 12 ]} \hyperdef{L}{X78DC644E8519280C}{} { \index{"@DoNotReadRestOfFile@\texttt{"@DoNotReadRestOfFile}} Prevents the rest of the file from being read by the parser. Useful for unfinished or temporary files. \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! This will appear in the manual #! @DoNotReadRestOfFile #! This will not appear in the manual. \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@BeginChunk \mbox{\texttt{\mdseries\slshape name}}}, \texttt{@EndChunk}, and \texttt{@InsertChunk \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@BeginChunk} \logpage{[ 3, 2, 13 ]} \hyperdef{L}{X83C01F9B7FA1C973}{} { \index{"@BeginChunk@\texttt{"@BeginChunk \mbox{\texttt{\mdseries\slshape name}}}} \index{"@EndChunk@\texttt{"@EndChunk}} \index{"@EndChunk@\texttt{"@InsertChunk \mbox{\texttt{\mdseries\slshape name}}}} Text inside a \texttt{@BeginChunk} / \texttt{@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 \texttt{@InsertChunk \mbox{\texttt{\mdseries\slshape name}}} command. If you do not provide an \texttt{@EndChunk}, the chunk ends at the end of the file. \begin{Verbatim}[commandchars=|AD,fontsize=\small,frame=single,label=] #! @BeginChunk MyChunk #! Hello, world. #! @EndChunk #! @InsertChunk MyChunk ## The text "Hello, world." is inserted right before this. \end{Verbatim} You can use this to define an example like this in one file: \begin{Verbatim}[commandchars=|AD,fontsize=\small,frame=single,label=] #! @BeginChunk Example_Symmetric_Group #! @BeginExample S5 := SymmetricGroup(5); #! Sym( [ 1 .. 5 ] ) Order(S5); #! 120 #! @EndExample #! @EndChunk \end{Verbatim} And then later, insert the example in a different file, like this: \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! @InsertChunk Example_Symmetric_Group \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@BeginCode \mbox{\texttt{\mdseries\slshape name}}}, @EndCode, and \texttt{@InsertCode \mbox{\texttt{\mdseries\slshape name}}}}}\label{Subsection_@BeginCode} \logpage{[ 3, 2, 14 ]} \hyperdef{L}{X7D3671AF86B995B9}{} { \index{"@BeginCode@\texttt{"@BeginCode \mbox{\texttt{\mdseries\slshape name}}}} \index{"@EndCode@\texttt{"@EndCode}} \index{"@InsertCode@\texttt{"@InsertCode \mbox{\texttt{\mdseries\slshape name}}}} Inserts the text between \texttt{@BeginCode} and \texttt{@EndCode} verbatim at the point where \texttt{@InsertCode} is called. This is useful to insert code excerpts directly into the manual. \begin{Verbatim}[commandchars=|AD,fontsize=\small,frame=single,label=] #! @BeginCode Increment i := i + 1; #! @EndCode #! @InsertCode Increment ## Code is inserted here. \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@LatexOnly \mbox{\texttt{\mdseries\slshape text}}}, \texttt{@BeginLatexOnly}, and \texttt{@EndLatexOnly}}}\label{Subsection_@LatexOnly} \logpage{[ 3, 2, 15 ]} \hyperdef{L}{X8033B34F80A12A10}{} { \index{"@LatexOnly@\texttt{"@LatexOnly \mbox{\texttt{\mdseries\slshape text}}}} \index{"@BeginLatexOnly@\texttt{"@BeginLatexOnly}} \index{"@EndLatexOnly@\texttt{"@EndLatexOnly}} Code inserted between \texttt{@BeginLatexOnly} and \texttt{@EndLatexOnly} or after \texttt{@LatexOnly} is only inserted in the PDF version of the manual or worksheet. It can hold arbitrary {\LaTeX}\texttt{\symbol{45}}commands. \begin{Verbatim}[commandchars=|AC,fontsize=\small,frame=single,label=] #! @BeginLatexOnly #! \include{picture.tex} #! @EndLatexOnly #! @LatexOnly \include{picture.tex} \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@NotLatex \mbox{\texttt{\mdseries\slshape text}}}, \texttt{@BeginNotLatex}, and \texttt{@EndNotLatex}}}\label{Subsection_@NotLatex} \logpage{[ 3, 2, 16 ]} \hyperdef{L}{X7EF303147F1BCC22}{} { \index{"@NotLatex@\texttt{"@NotLatex \mbox{\texttt{\mdseries\slshape text}}}} \index{"@BeginNotLatex@\texttt{"@BeginNotLatex}} \index{"@EndNotLatex@\texttt{"@EndNotLatex}} Code inserted between \texttt{@BeginNotLatex} and \texttt{@EndNotLatex} or after \texttt{@NotLatex} is inserted in the HTML and text versions of the manual or worksheet, but not in the PDF version. \begin{Verbatim}[commandchars=|AC,fontsize=\small,frame=single,label=] #! @BeginNotLatex #! For further information see the PDF version of this manual. #! @EndNotLatex #! @NotLatex For further information see the PDF version of this manual. \end{Verbatim} } \subsection{\textcolor{Chapter }{\texttt{@Index \mbox{\texttt{\mdseries\slshape key}} [\mbox{\texttt{\mdseries\slshape entry text}}]}}}\label{Subsection_@Index} \logpage{[ 3, 2, 17 ]} \hyperdef{L}{X82FD2EEB788E76F1}{} { \index{"@Index@\texttt{"@Index \mbox{\texttt{\mdseries\slshape key}} [\mbox{\texttt{\mdseries\slshape entry text}}]}} Adds an index entry to the current documentation text. The command \texttt{@Index key entry text} generates \texttt{{\textless}Index Key="key"{\textgreater}entry text{\textless}/Index{\textgreater}}. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. \texttt{@Index "my key" entry text}. The entry text is processed like normal documentation text, so markdown\texttt{\symbol{45}}like inline code such as \texttt{true} is supported. } } \section{\textcolor{Chapter }{Title page commands}}\label{Section_TitlepageCommands} \logpage{[ 3, 3, 0 ]} \hyperdef{L}{X841E3AD584F5385C}{} { The following commands can be used to add corresponding parts to the title page of a document generated by \textsf{AutoDoc}. \begin{itemize} \item \texttt{@Title} \item \texttt{@Subtitle} \item \texttt{@Version} \item \texttt{@TitleComment} \item \texttt{@Author} \item \texttt{@Date} \item \texttt{@Address} \item \texttt{@Abstract} \item \texttt{@Copyright} \item \texttt{@Acknowledgements} \item \texttt{@Colophon} \end{itemize} Many of these values can (and for package manuals typically should) be extracted from \texttt{PackageInfo.g}. If you set them explicitly in comments, they override extracted or scaffold\texttt{\symbol{45}}defined values. This is usually most useful for worksheets created with \texttt{AutoDocWorksheet} (\ref{AutoDocWorksheet}), since worksheets do not have a \texttt{PackageInfo.g} file from which this information could be extracted. } \section{\textcolor{Chapter }{Plain text files}}\label{Section_PlainText} \logpage{[ 3, 4, 0 ]} \hyperdef{L}{X828AE38F80CB02E7}{} { Files that have the suffix \texttt{.autodoc} and are listed in the \texttt{autodoc.files} option of \texttt{AutoDoc} (\ref{AutoDoc}), resp. are contained in one of the directories listed in \texttt{autodoc.scan{\textunderscore}dirs} or one of their subdirectories, are treated as standalone \textsf{AutoDoc} input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title\texttt{\symbol{45}}page metadata, and similar prose\texttt{\symbol{45}}heavy material. Conceptually, a \texttt{.autodoc} file uses the same parser as \textsf{AutoDoc} comments, but without the comment marker. In a \texttt{.autodoc} file, lines do not need to start with \texttt{\#!} and in fact usually should not. This makes \texttt{.autodoc} files one convenient way to replace hand\texttt{\symbol{45}}written XML chapters when you prefer \textsf{AutoDoc}'s command syntax and Markdown\texttt{\symbol{45}}like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and \textsf{AutoDoc} itself still uses that style in files such as \texttt{gap/Magic.gd}. For the surrounding workflow, see Chapter \ref{Chapter_Tutorials}. The most important difference from declaration comments is that a plain text file does \emph{not} document a declaration by adjacency. There is no following \texttt{Declare...} or \texttt{InstallMethod} statement for \textsf{AutoDoc} to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration. In practice, this gives the following rule of thumb. \begin{itemize} \item Use source comments beginning with \texttt{\#!} to document declarations. This is the mode for \texttt{@Description}, \texttt{@Returns}, \texttt{@Arguments}, \texttt{@Label}, \texttt{@Group}, and \texttt{@ChapterInfo}. \item Use either \texttt{.autodoc} files or source comments for standalone manual structure and prose. Commands such as \texttt{@Chapter}, \texttt{@Section}, \texttt{@Subsection}, grouping commands, examples and logs, chunks and code insertion, \texttt{@Index}, title\texttt{\symbol{45}}page commands, Markdown\texttt{\symbol{45}}style headings, fenced code blocks, and ordinary \textsf{GAPDoc} XML markup work in both styles. \end{itemize} As a concrete example, the following file can serve as a complete chapter written in \texttt{.autodoc} format. \begin{Verbatim}[commandchars=!|D,fontsize=\small,frame=single,label=] @Chapter Test @Section First Section @Subsection First Subsection This text belongs directly to the manual chapter. It can use XML tags such as <A>arg</A> or <Ref .../>. @BeginExampleSession !gapprompt|gap>D !gapinput|S5 := SymmetricGroup(5);D Sym( [ 1 .. 5 ] ) !gapprompt|gap>D !gapinput|Size(S5);D 120 @EndExampleSession @Index "Worksheet Autoplain" Plain worksheet index entry with `true` \end{Verbatim} This is essentially the style used in the worksheet fixture \texttt{tst/worksheets/autoplain.sheet/plain.autodoc}. The same structural commands can also be used inside source comments, for example: \begin{Verbatim}[commandchars=|BE,fontsize=\small,frame=single,label=] #! @Chapter Reference #! @Section The AutoDoc() function #! Some introductory text for this section. \end{Verbatim} This source\texttt{\symbol{45}}comment style is still fully supported and is used in \texttt{gap/Magic.gd}. The mixed\texttt{\symbol{45}}workflow case is equally common. Suppose an existing manual still has a hand\texttt{\symbol{45}}written main XML file and perhaps some hand\texttt{\symbol{45}}written XML chapters. Then you can keep those files, include \texttt{{\textunderscore}AutoDocMainFile.xml} from the main XML file as described in Chapter \ref{Chapter_Tutorials}, and add one or more \texttt{.autodoc} files via \texttt{autodoc.files} or \texttt{autodoc.scan{\textunderscore}dirs}. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged. One caveat is worth keeping in mind. If you want a standalone \texttt{.autodoc} file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue \texttt{\#60} in the AutoDoc issue tracker. So, while \texttt{.autodoc} files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration\texttt{\symbol{45}}bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient. } \section{\textcolor{Chapter }{Grouping}}\label{Section_Groups} \logpage{[ 3, 5, 0 ]} \hyperdef{L}{X7D7A38F87BC40C48}{} { In \textsf{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 \texttt{@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 \texttt{@BeginGroup} / \texttt{@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 \texttt{@Group} command in the \textsf{AutoDoc} comment of an arbitrary declaration, at any time. The following code \begin{Verbatim}[commandchars=|CH,fontsize=\small,frame=single,label=] #! @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 ); \end{Verbatim} produces the following: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] <ManSection Label="Group1"> <Heading>A family of operations</Heading> <Oper Arg="arg" Name="FirstOperation" Label="for IsInt"/> <Oper Arg="arg1,arg2" Name="SecondOperation" Label="for IsInt, IsGroup"/> <Oper Arg="arg1,arg2" Name="ThirdOperation" Label="for IsGroup, IsInt"/> <Description> First sentence. Second sentence. Third sentence. </Description> </ManSection> \end{Verbatim} } \section{\textcolor{Chapter }{Markdown\texttt{\symbol{45}}like formatting of text in \textsf{AutoDoc}}}\label{Section_MarkdownExtension} \logpage{[ 3, 6, 0 ]} \hyperdef{L}{X79558A2F7FE187B4}{} { \textsf{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. \subsection{\textcolor{Chapter }{Lists}}\label{Subsection_MarkdownExtensionList} \logpage{[ 3, 6, 1 ]} \hyperdef{L}{X7B256AE5780F140A}{} { One can create lists of items by beginning a new line with *, +, \texttt{\symbol{45}}, 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: \begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=] #! 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. \end{Verbatim} This is the output:\\ The list starts in the next line \begin{itemize} \item item 1 \item item 2 which is a bit longer \begin{itemize} \item and also contains a nested list \item with two items \end{itemize} \item item 3 of the outer list \end{itemize} This does not belong to the list anymore.\\ The *, \texttt{\symbol{45}}, and + are fully interchangeable and can even be used mixed, but this is not recommended. } \subsection{\textcolor{Chapter }{Math modes}}\label{Subsection_MarkdownExtensionMath} \logpage{[ 3, 6, 2 ]} \hyperdef{L}{X871412737A0E12E2}{} { One can start an inline formula with a \$, and also end it with \$, just like in {\LaTeX}. This will translate into \textsf{GAPDoc}s inline math environment. For display mode one can use \$\$, also like {\LaTeX}. \begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=] #! This is an inline formula: $1+1 = 2$. #! This is a display formula: #! $$ \sum_{i=1}^n i. $$ \end{Verbatim} produces the following output:\\ This is an inline formula: $1+1 = 2$. This is a display formula: \[ \sum_{i=1}^n i. \] } \subsection{\textcolor{Chapter }{Emphasize}}\label{Subsection_MarkdownExtensionEmph} \logpage{[ 3, 6, 3 ]} \hyperdef{L}{X7ED0330479146EFC}{} { One can emphasize text by using two asterisks (**) or two underscores ({\textunderscore}{\textunderscore}) at the beginning and the end of the text which should be emphasized. Example: \begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=] #! **This** is very important. #! This is __also important__. #! **Naturally, more than one line #! can be important.** \end{Verbatim} This produces the following output:\\ \emph{This} is very important. This is \emph{also important}. \emph{Naturally, more than one line can be important.} } \subsection{\textcolor{Chapter }{Inline code}}\label{Subsection_MarkdownExtensionInlineCode} \logpage{[ 3, 6, 4 ]} \hyperdef{L}{X838CCDEB7E0ECEE2}{} { 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: \begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=] #! Call function `foobar()` at the start. \end{Verbatim} This produces the following output:\\ Call function \texttt{foobar()} at the start. } \subsection{\textcolor{Chapter }{Fenced code blocks}}\label{Subsection_MarkdownExtensionFencedCode} \logpage{[ 3, 6, 5 ]} \hyperdef{L}{X7C0629B183765575}{} { One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values \texttt{@listing}, \texttt{@example}, and \texttt{@log} select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate \texttt{{\textless}Listing{\textgreater}}. Example: \begin{Verbatim}[commandchars=|AB,fontsize=\small,frame=single,label=] #! ```@listing #! if x = 2 then #! Print("1 + 1 = 2 holds, all is good\n"); #! fi; #! ``` #! ~~~@example #! gap> [ 1 .. 3 ] ^ 2; #! [ 1, 4, 9 ] #! ~~~ #! ```@log #! #I some log message #! ``` \end{Verbatim} This produces the following output:\\ \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] if x = 2 then Print("1 + 1 = 2 holds, all is good\n"); fi; \end{Verbatim} \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@[ 1 .. 3 ] ^ 2;| [ 1, 4, 9 ] \end{Verbatim} \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] #I some log message \end{Verbatim} } } \section{\textcolor{Chapter }{Deprecated commands}}\label{Section_Deprecated} \logpage{[ 3, 7, 0 ]} \hyperdef{L}{X78CA9E5C7F494C19}{} { The following commands used to be supported, but are not supported anymore. \begin{description} \item[{\texttt{@EndSection}}] You can simply remove any use of this, \textsf{AutoDoc} ends sections automatically at the start of any new section or chapter. \item[{\texttt{@EndSubsection}}] You can simply remove any use of this, \textsf{AutoDoc} ends subsections automatically at the start of any new subsection, section or chapter. \item[{\texttt{@BeginAutoDoc} and \texttt{@EndAutoDoc}}] It suffices to prepend each declaration that is meant to appear in the manual with a minimal \textsf{AutoDoc} comment \texttt{\#!}. \item[{\texttt{@BeginSystem \mbox{\texttt{\mdseries\slshape name}}}, \texttt{@EndSystem}, and \texttt{@InsertSystem \mbox{\texttt{\mdseries\slshape name}}}}] Please use the chunk commands from subsection \ref{Subsection_@BeginChunk} instead. \item[{\texttt{@AutoDocPlainText} and \texttt{@EndAutoDocPlainText}}] Use \texttt{.autodoc} files or \textsf{AutoDoc} comments instead. \end{description} } } \chapter{\textcolor{Chapter }{Reference}}\label{Chapter_Reference} \logpage{[ 4, 0, 0 ]} \hyperdef{L}{X782AAE4E86411FF4}{} { \section{\textcolor{Chapter }{AutoDoc worksheets}}\label{Section_AutoDocWorksheet} \logpage{[ 4, 1, 0 ]} \hyperdef{L}{X80ED3C2A78146AD1}{} { \subsection{\textcolor{Chapter }{AutoDocWorksheet}} \logpage{[ 4, 1, 1 ]}\nobreak \hyperdef{L}{X809FE4137C08B28D}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{AutoDocWorksheet({\mdseries\slshape [filenames][,] [optrec]})\index{AutoDocWorksheet@\texttt{AutoDocWorksheet}} \label{AutoDocWorksheet} }\hfill{\scriptsize (function)}}\\ The purpose of this function is to create stand\texttt{\symbol{45}}alone PDF and HTML files using \textsf{AutoDoc} without associating them with a package. Instead of a package directory, you pass one filename or a list of filenames containing \textsf{AutoDoc} text from which the document is created. Settings are supplied via an optional record using the same entries as the \mbox{\texttt{\mdseries\slshape optrec}} argument of \texttt{AutoDoc} (\ref{AutoDoc}). Alternatively, you may omit \mbox{\texttt{\mdseries\slshape filenames}} and specify the files via \texttt{optrec.autodoc.files}. A simple worksheet file can define title\texttt{\symbol{45}}page information and chapter content directly in the source file, including example blocks. If this is stored in \texttt{worksheet.g}, you can generate documentation via \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] AutoDocWorksheet( "worksheet.g" ); \end{Verbatim} This creates documentation in a \texttt{doc} subdirectory of the current directory. Since worksheets do not have a \texttt{PackageInfo.g}, title\texttt{\symbol{45}}page fields are specified directly in the worksheet file. For backwards compatibility, worksheet calls still accept GAP global options for specifying the option\texttt{\symbol{45}}record entries such as \texttt{dir}, \texttt{scaffold}, \texttt{autodoc}, \texttt{gapdoc}, and \texttt{extract{\textunderscore}examples}. However, this feature is deprecated. } } \section{\textcolor{Chapter }{The AutoDoc() function}}\label{Chapter_Reference_Section_The_AutoDoc()_function} \logpage{[ 4, 2, 0 ]} \hyperdef{L}{X863584DB8497D8BA}{} { \subsection{\textcolor{Chapter }{AutoDoc}} \logpage{[ 4, 2, 1 ]}\nobreak \hyperdef{L}{X7CBD8AAF7DCEF352}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{AutoDoc({\mdseries\slshape [pkgdir][,] [optrec]})\index{AutoDoc@\texttt{AutoDoc}} \label{AutoDoc} }\hfill{\scriptsize (function)}}\\ \textbf{\indent Returns:\ } nothing This is the main function of the \textsf{AutoDoc} package. It can perform any combination of the following tasks: \begin{enumerate} \item It can (re)generate a scaffold for your package manual. That is, it can produce two XML files in \textsf{GAPDoc} format to be used as part of your manual: First, a file named \texttt{doc/{\textunderscore}main.xml} 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 \textsf{AutoDoc} as well as additional files created by other means), tells \textsf{GAPDoc} to generate a table of contents and an index, and more. Secondly, it creates a file \texttt{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 \texttt{PackageInfo.g}. \item It can scan your package for \textsf{AutoDoc} based documentation, using documentation comments and commands. This produces additional XML files to be used as part of the package manual. \item It can use \textsf{GAPDoc} to generate PDF, text and HTML (with MathJax enabled) documentation from the \textsf{GAPDoc} XML files it generated as well as additional such files provided by you. For this, it invokes \texttt{MakeGAPDocDoc} (\textbf{GAPDoc: MakeGAPDocDoc}) to convert the XML sources, and it also instructs \textsf{GAPDoc} to copy supplementary files (such as CSS style files) into your doc directory (see \texttt{CopyHTMLStyleFiles} (\textbf{GAPDoc: CopyHTMLStyleFiles})). \end{enumerate} These tasks can be enabled independently, so you can use as much or as little of \textsf{AutoDoc} as your package currently needs. For more information and some examples, please refer to Chapter \ref{Chapter_Tutorials}. The parameters have the following meanings: \begin{description} \item[{\mbox{\texttt{\mdseries\slshape pkgdir}}}] This optional parameter is used to determine the package directory in which \textsf{AutoDoc} will operate, and to find the metadata concerning the package being documented. If given, it should be an \texttt{IsDirectory} object. If the argument is omitted, then \textsf{AutoDoc} checks if it was called from a \texttt{makedoc.g} file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both cases, the specified directory must contain a \texttt{PackageInfo.g} file, and \textsf{AutoDoc} extracts all needed metadata from that. The \texttt{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. For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package \textsf{GAP} knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package. Note that when using \texttt{AutoDocWorksheet} (see \ref{Section_AutoDocWorksheet}), there is no parameter corresponding to \mbox{\texttt{\mdseries\slshape pkgdir}} and so the ``package directory'' is always the current directory, and there is no metadata. \item[{\mbox{\texttt{\mdseries\slshape optrec}}}] \mbox{\texttt{\mdseries\slshape optrec}} can be a record with some additional options. The following are currently supported: \begin{description} \item[{\mbox{\texttt{\mdseries\slshape dir}}}] This should either be a string, in which case it must be a path \emph{relative} to the specified package directory, or a \texttt{Directory()} object. (Thus, the only way to designate an absolute directory is with a \texttt{Directory()} object.) This option specifies where the package documentation (e.g. the \textsf{GAPDoc} XML or the manual PDF, etc.) files are stored and/or will be generated. \\ \emph{Default value: \texttt{"doc/"}.} \item[{\mbox{\texttt{\mdseries\slshape scaffold}}}] This controls whether and how to generate scaffold XML files for the package documentation. The value should be either \texttt{true}, \texttt{false} or a record. If it is a record or \texttt{true} (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if \mbox{\texttt{\mdseries\slshape opt.scaffold}} is missing but the package's info record in \texttt{PackageInfo.g} has an \texttt{AutoDoc} entry. In all other cases (in particular if \mbox{\texttt{\mdseries\slshape opt.scaffold}} is \texttt{false}), scaffolding is disabled. If scaffolding is enabled, and \mbox{\texttt{\mdseries\slshape PackageInfo.AutoDoc}} exists, then it is assumed to be a record, and its contents are used as default values for the scaffold settings. If \mbox{\texttt{\mdseries\slshape opt.scaffold}} is a record, it may contain the following entries. \begin{description} \item[{\mbox{\texttt{\mdseries\slshape 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 \textsf{AutoDoc} to document your operations with \textsf{AutoDoc} comments, you can add \texttt{{\textunderscore}AutoDocMainFile.xml} to this list to control at which point the documentation produced by \textsf{AutoDoc} is inserted. If you do not do this, it will be added after the last of your own XML files. \item[{\mbox{\texttt{\mdseries\slshape index}}}] By default, the scaffold creates an index. If you do not want an index, set this to \texttt{false}. \item[{\mbox{\texttt{\mdseries\slshape appendix}}}] This entry is similar to \mbox{\texttt{\mdseries\slshape opt.scaffold.includes}} but is used to specify files to include after the main body of the manual, i.e. typically appendices written directly in \textsf{GAPDoc} XML. Appendices created with \texttt{@Appendix} are included automatically after these files when scaffolding generates the main XML file. \item[{\mbox{\texttt{\mdseries\slshape bib}}}] The name of a bibliography file, in BibTeX or XML format. If this key is not set, but there is a file \texttt{doc/PACKAGENAME.bib} then it is assumed that you want to use this as your bibliography. \item[{\mbox{\texttt{\mdseries\slshape bibstyle}}}] Overrides the bibliography style used for LaTeX output. This is written as the \texttt{Style} attribute of the generated \texttt{{\textless}Bibliography .../{\textgreater}} element, so valid values are the bibliography style names understood by \textsf{GAPDoc} and BibTeX, such as \texttt{alpha}, \texttt{alphaurl}, or \texttt{plain}. \item[{\mbox{\texttt{\mdseries\slshape entities}}}] A record whose keys are taken as entity names, set to the corresponding (string) values. For example, if you pass the record ``SomePackage'', \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] rec( SomePackage := "<Package>SomePackage</Package>", RELEASEYEAR := "2015" ) \end{Verbatim} then the following entity definitions are added to the XML preamble: \begin{Verbatim}[commandchars=@|B,fontsize=\small,frame=single,label=] <!ENTITY SomePackage '<Package>SomePackage</Package>'> <!ENTITY RELEASEYEAR '2015'> \end{Verbatim} This allows you to write ``\&SomePackage;'' and ``\&RELEASEYEAR;'' in your documentation, which will be replaced by respective values specified in the entities definition. Note that \textsf{AutoDoc} predefines several entities: \begin{description} \item[{\mbox{\texttt{\mdseries\slshape VERSION}}}] Set to the \texttt{Version} field of your package info record. \item[{\mbox{\texttt{\mdseries\slshape RELEASEYEAR}}}] Set to a string containing the release year, as derived from the \texttt{Date} field of your package info record. \item[{\mbox{\texttt{\mdseries\slshape RELEASEDATE}}}] Derived from the \texttt{Date} field of your package info record. \item[{\mbox{\texttt{\mdseries\slshape SomePackage}}}] The precise name of this entity is derived from the \texttt{PackageName} field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above. \end{description} \item[{\mbox{\texttt{\mdseries\slshape TitlePage}}}] A record with extra title\texttt{\symbol{45}}page fields for the generated manual. Field names are interpreted as title\texttt{\symbol{45}}page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] rec( Acknowledgements := "Many thanks to ..." ) \end{Verbatim} If this is set in \texttt{PackageInfo.g} as \texttt{PkgInfo.AutoDoc.TitlePage}, it has the same meaning as this option; see subsection \ref{Subsection_Tut:PackageInfo} in chapter \ref{Chapter_Tutorials} for details and an example. For the list of valid title\texttt{\symbol{45}}page elements, see the \textsf{GAPDoc} manual, specifically section (\textbf{GAPDoc: TitlePage}). \item[{\mbox{\texttt{\mdseries\slshape 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 \textsf{AutoDoc} to generate a title page for you, you can set this option to \texttt{false} \item[{\mbox{\texttt{\mdseries\slshape document{\textunderscore}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}. \item[{\mbox{\texttt{\mdseries\slshape latex{\textunderscore}header{\textunderscore}file}}}] Replaces the standard header from \textsf{GAPDoc} completely with the header in this {\LaTeX} file. Please be careful here, and look at \textsf{GAPDoc}'s \texttt{latexheader.tex} file for an example. \end{description} \item[{\mbox{\texttt{\mdseries\slshape autodoc}}}] This controls whether and how to generate additional XML documentation files by scanning for \textsf{AutoDoc} documentation comments. The value should be either \texttt{true}, \texttt{false} or a record. If it is a record or \texttt{true} (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if \mbox{\texttt{\mdseries\slshape opt.autodoc}} is missing but the package depends (directly) on the \textsf{AutoDoc} package. In all other cases (in particular if \mbox{\texttt{\mdseries\slshape opt.autodoc}} is \texttt{false}), this feature is disabled. If \mbox{\texttt{\mdseries\slshape opt.autodoc}} is a record, it may contain the following entries. \begin{description} \item[{\mbox{\texttt{\mdseries\slshape files}}}] A list of files (given by paths relative to the package directory) to be scanned for \textsf{AutoDoc} documentation comments. Usually it is more convenient to use \mbox{\texttt{\mdseries\slshape autodoc.scan{\textunderscore}dirs}}, see below. \item[{\mbox{\texttt{\mdseries\slshape scan{\textunderscore}dirs}}}] A list of subdirectories of the package directory (given as relative paths) which \textsf{AutoDoc} then scans recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for \textsf{AutoDoc} documentation comments. The special entries \texttt{"."} and \texttt{""} still only scan the package root itself. This controls where \textsf{AutoDoc} looks for source comments beginning with \texttt{\#!} and for standalone \texttt{.autodoc} files. It does not affect where \textsf{GAPDoc} looks for GAPDoc comments; that is controlled separately by \mbox{\texttt{\mdseries\slshape gapdoc.scan{\textunderscore}dirs}}. \\ \emph{Default value: \texttt{[ ".", "gap", "lib", "examples", "examples/doc" ]}.} \item[{\mbox{\texttt{\mdseries\slshape 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. \end{description} \item[{\mbox{\texttt{\mdseries\slshape gapdoc}}}] This controls whether and how to invoke \textsf{GAPDoc} to create HTML, PDF and text files from your various XML files. The value should be either \texttt{true}, \texttt{false} or a record. If it is a record or \texttt{true} (the latter is equivalent to specifying an empty record), then this feature is enabled. It is also enabled if \mbox{\texttt{\mdseries\slshape opt.gapdoc}} is missing. In all other cases (in particular if \mbox{\texttt{\mdseries\slshape opt.gapdoc}} is \texttt{false}), this feature is disabled. If \mbox{\texttt{\mdseries\slshape opt.gapdoc}} is a record, it may contain the following entries. \begin{description} \item[{\mbox{\texttt{\mdseries\slshape 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. \\ \emph{Default value: \texttt{{\textunderscore}main.xml} when scaffolding is enabled for package manuals, otherwise \texttt{PACKAGENAME.xml}.} \item[{\mbox{\texttt{\mdseries\slshape files}}}] A list of files (given by paths relative to the package directory) to be scanned for \textsf{GAPDoc} documentation comments. Usually it is more convenient to use \mbox{\texttt{\mdseries\slshape gapdoc.scan{\textunderscore}dirs}}, see below. \item[{\mbox{\texttt{\mdseries\slshape scan{\textunderscore}dirs}}}] A list of subdirectories of the package directory (given as relative paths) which \textsf{AutoDoc} then scans recursively for .gi, .gd and .g files; all of these files are then scanned for \textsf{GAPDoc} documentation comments. The special entries \texttt{"."} and \texttt{""} still only scan the package root itself. This controls only where \textsf{GAPDoc} comments are searched for. It does not affect where \textsf{AutoDoc} looks for source comments beginning with \texttt{\#!} or for \texttt{.autodoc} files; use \mbox{\texttt{\mdseries\slshape autodoc.scan{\textunderscore}dirs}} for that. \\ \emph{Default value: \texttt{[ ".", "gap", "lib", "examples", "examples/doc" ]}.} \item[{\mbox{\texttt{\mdseries\slshape LaTeXOptions}}}] Must be a record with entries which can be understood by \texttt{SetGapDocLaTeXOptions} (\textbf{GAPDoc: SetGapDocLaTeXOptions}). Each entry can be a string, which will be given to \textsf{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 \textsf{GAPDoc} as option with the name of the entry. \item[{\mbox{\texttt{\mdseries\slshape gap{\textunderscore}root{\textunderscore}relative{\textunderscore}path}}}] Either a boolean, or a string containing a relative path. By default (if this option is not set, or is set to \texttt{false}), references in the generated documentation referring to external documentation (such as the \textsf{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 \textsf{GAP} package.\\ Thus, if a relative path is provided via this option (or if it is set to \texttt{true}, in which case the relative path \texttt{../../..} is used), then \textsf{AutoDoc} and \textsf{GAPDoc} attempt to replace all absolute paths in references to \textsf{GAP} manuals by paths based on this relative path. On a technical level, \textsf{AutoDoc} passes the relative path to the \mbox{\texttt{\mdseries\slshape gaproot}} parameter of \texttt{MakeGAPDocDoc} (\textbf{GAPDoc: MakeGAPDocDoc}) \end{description} \item[{\mbox{\texttt{\mdseries\slshape extract{\textunderscore}examples}}}] Either \texttt{true} or a record. If set to \texttt{true}, then all manual examples are extracted and placed into files \texttt{tst/PACKAGENAME01.tst}, \texttt{tst/PACKAGENAME02.tst}, ... and so on, with one file for each chapter. For chapters with no examples, no file is created. If set to a record, it may contain the following entries: \begin{description} \item[{subdir}] A string or \texttt{Directory()} object selecting where the generated \texttt{.tst} files are written. The default is \texttt{tst}. If a string is given, it is interpreted relative to the package directory, so values such as \texttt{tst/generated} are supported. \item[{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, \textsf{AutoDoc} passes the value to the \mbox{\texttt{\mdseries\slshape units}} parameter of \texttt{ExtractExamples} (\textbf{GAPDoc: ExtractExamples}). \item[{skip{\textunderscore}empty{\textunderscore}in{\textunderscore}numbering}] If set to \texttt{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 \texttt{tst/PACKAGENAME01.tst}. If this option is set to \texttt{false}, then the chapter numbers are used to generate the filenames; so the examples for chapter 2 would be put into the file \texttt{tst/PACKAGENAME02.tst}. \end{description} \end{description} \end{description} The function also checks the following GAP global options, i.e. options supplied via GAP's value\texttt{\symbol{45}}option syntax and visible through nested calls. These are not entries of \mbox{\texttt{\mdseries\slshape optrec}}. See (\textbf{Reference: Options Stack}) for more information about GAP's global options system. \begin{description} \item[{\mbox{\texttt{\mdseries\slshape nopdf}}}] If this global option is set to \texttt{true}, then \textsf{AutoDoc} tells \textsf{GAPDoc} not to build the PDF version of the manual. HTML and text output are still generated. This is useful on systems without a working \texttt{pdflatex} installation, or when you only need the non\texttt{\symbol{45}}PDF outputs while iterating on the manual. For example: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] AutoDoc( rec( autodoc := true ) : nopdf ); \end{Verbatim} Also, if the environment variable \texttt{NOPDF} is set, then \textsf{AutoDoc} behaves as if the global option \mbox{\texttt{\mdseries\slshape nopdf}} had been enabled. \item[{\mbox{\texttt{\mdseries\slshape relativePath}}}] This has the same effect as \mbox{\texttt{\mdseries\slshape gapdoc.gap{\textunderscore}root{\textunderscore}relative{\textunderscore}path}}, but as a GAP global option. It takes precedence over that record entry if both are specified. If \mbox{\texttt{\mdseries\slshape relativePath}} is \texttt{true}, then the default relative path \texttt{../../..} is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root. For example: \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] AutoDoc( rec( autodoc := true ) : relativePath := "../../.." ); \end{Verbatim} \end{description} In particular, a call such as \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=] Read( "makedoc.g" : nopdf, relativePath ); \end{Verbatim} sets both global options to \texttt{true}, and they remain visible to the \texttt{AutoDoc} call inside \texttt{makedoc.g}. } \subsection{\textcolor{Chapter }{InfoAutoDoc}} \logpage{[ 4, 2, 2 ]}\nobreak \hyperdef{L}{X81F946A785BA3D6E}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{InfoAutoDoc\index{InfoAutoDoc@\texttt{InfoAutoDoc}} \label{InfoAutoDoc} }\hfill{\scriptsize (info class)}}\\ Info class for the \textsf{AutoDoc} package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths. This can be set by calling, for example, \texttt{SetInfoLevel(InfoAutoDoc, 0)}. Default value is 1. } } } \def\bibname{References\logpage{[ "Bib", 0, 0 ]} \hyperdef{L}{X7A6F98FD85F02BFE}{} } \bibliographystyle{alpha} \bibliography{bib.xml} \addcontentsline{toc}{chapter}{References} \def\indexname{Index\logpage{[ "Ind", 0, 0 ]} \hyperdef{L}{X83A0356F839C696F}{} } \cleardoublepage \phantomsection \addcontentsline{toc}{chapter}{Index} \printindex \immediate\write\pagenrlog{["Ind", 0, 0], \arabic{page},} \newpage \immediate\write\pagenrlog{["End"], \arabic{page}];} \immediate\closeout\pagenrlog \end{document} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/_main.xml��������������������������������������������������������������������0000644�0000000�0000000�00000000540�15175510000�012740� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- This is an automatically generated file. --> <!DOCTYPE Book SYSTEM "gapdoc.dtd" [ <#Include SYSTEM "_entities.xml"> ] > <Book Name="AutoDoc"> <#Include SYSTEM "title.xml"> <TableOfContents/> <Body> <#Include SYSTEM "_AutoDocMainFile.xml"> </Body> <Bibliography Databases="bib.xml"/> <TheIndex/> </Book> ����������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/bib.xml����������������������������������������������������������������������0000644�0000000�0000000�00000001013�15175510000�012405� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE file SYSTEM "bibxmlext.dtd"> <file> <entry id="GAPDoc"><manual> <author> <name><first>Frank</first><last>Lübeck</last></name> <name><first>Max</first><last>Neunhöffer</last></name> </author> <title><C>GAPDoc (Version 1.6.7)</C> RWTH Aachen 2024 GAP package, https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html AutoDoc-2026.05.03/doc/bib.xml.bib0000644000000000000000000000126015175510000013144 0ustar00 @manual{ GAPDoc, author = {L{\"u}beck, F. and Neunh{\"o}ffer, M.}, title = {{GAPDoc (Version 1.6.7)}}, organization = {RWTH Aachen}, year = {2024}, note = {GAP package, \href {https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html} {\texttt{https://www.math.rwth\texttt{\symbol{45}}aachen.de/}\discretionary {}{}{}\texttt{\texttt{\symbol{126}}Frank.Luebeck/}\discretionary {}{}{}\texttt{GAPDoc/}\discretionary {}{}{}\texttt{index.html}}}, printedkey = {LN24} } AutoDoc-2026.05.03/doc/chap0.html0000644000000000000000000004074315175510000013025 0ustar00 GAP (AutoDoc) - Contents

AutoDoc

Generate documentation from GAP source code

2026.05.03

3 May 2026

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-2026 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 [LN24].

Contents


Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap0.txt0000644000000000000000000001367115175510000012700 0ustar00  AutoDoc   Generate documentation from GAP source code  2026.05.03 3 May 2026 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-2026 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 [LN24]. ------------------------------------------------------- Contents (AutoDoc) 1 What AutoDoc offers 1.1 Core features 1.2 Adopting AutoDoc incrementally 1.3 Where to continue 2 Getting started using AutoDoc 2.1 Choose your workflow 2.2 Creating a package manual from scratch 2.3 Documenting code with AutoDoc 2.4 Using AutoDoc in an existing GAPDoc manual 2.4-1 Using AutoDoc on a complete GAPDoc manual 2.4-2 Setting different GAPDoc options 2.4-3 Checklist for converting an existing GAPDoc manual to use AutoDoc 2.5 Scaffolds 2.5-1 Generating a title page 2.5-2 Generating the main XML file 2.5-3 What data is used from PackageInfo.g? 2.5-4 Entities from PackageInfo.g and scaffold options 2.6 Worksheets 3 AutoDoc documentation comments 3.1 Documenting declarations 3.1-1 @Description descr 3.1-2 @Returns ret val 3.1-3 @Arguments args 3.1-4 @ItemType kind 3.1-5 @Group grpname 3.1-6 @Label label 3.1-7 @ChapterInfo chapter, section 3.2 Other documentation comments 3.2-1 @Chapter name 3.2-2 @Appendix name 3.2-3 @Section name 3.2-4 @Subsection name 3.2-5 @BeginGroup [grpname] 3.2-6 @EndGroup 3.2-7 @GroupTitle title 3.2-8 @BeginExample and @EndExample 3.2-9 @BeginExampleSession and @EndExampleSession 3.2-10 @BeginLog and @EndLog 3.2-11 @BeginLogSession and @EndLogSession 3.2-12 @DoNotReadRestOfFile 3.2-13 @BeginChunk name, @EndChunk, and @InsertChunk name 3.2-14 @BeginCode name, @EndCode, and @InsertCode name 3.2-15 @LatexOnly text, @BeginLatexOnly, and @EndLatexOnly 3.2-16 @NotLatex text, @BeginNotLatex, and @EndNotLatex 3.2-17 @Index key [entry text] 3.3 Title page commands 3.4 Plain text files 3.5 Grouping 3.6 Markdown-like formatting of text in AutoDoc 3.6-1 Lists 3.6-2 Math modes 3.6-3 Emphasize 3.6-4 Inline code 3.6-5 Fenced code blocks 3.7 Deprecated commands 4 Reference 4.1 AutoDoc worksheets 4.1-1 AutoDocWorksheet 4.2 The AutoDoc() function 4.2-1 AutoDoc 4.2-2 InfoAutoDoc  AutoDoc-2026.05.03/doc/chap0_mj.html0000644000000000000000000004153615175510000013514 0ustar00 GAP (AutoDoc) - Contents
Goto Chapter: Top 1 2 3 4 Bib Ind

AutoDoc

Generate documentation from GAP source code

2026.05.03

3 May 2026

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-2026 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 [LN24].

Contents


Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap1.html0000644000000000000000000001407015175510000013020 0ustar00 GAP (AutoDoc) - Chapter 1: What AutoDoc offers
Goto Chapter: Top 1 2 3 4 Bib Ind

1 What AutoDoc offers

AutoDoc helps you create and maintain package manuals for GAP. It is built on top of GAPDoc and generates the XML input that GAPDoc consumes. So AutoDoc complements GAPDoc instead of replacing it.

The package is designed for a mix and match workflow: you can adopt only the parts that help you today, and add more over time.

1.1 Core features

  • Build package manuals via one reproducible command, usually gap makedoc.g.

  • Generate and maintain a title page from metadata in PackageInfo.g.

  • Generate and maintain a main XML file that includes your chapters.

  • Extract manual examples into .tst files via extract_examples := true.

  • Document declarations directly in source files via AutoDoc comments beginning with #!.

  • Organize chapter and section text either in source comments or in standalone .autodoc files.

  • Combine AutoDoc comments, classic GAPDoc source comments, and hand-written XML chapters in one manual.

1.2 Adopting AutoDoc incrementally

You do not have to switch everything at once. Typical adoption paths include:

  • Use only AutoDoc (4.2-1) to rebuild an existing GAPDoc manual.

  • Enable only title-page generation, while keeping your custom main XML.

  • Keep your existing title page but use generated entities such as &VERSION;, &RELEASEYEAR;, and &RELEASEDATE;.

  • Add AutoDoc comments only for new code, and leave old documentation as-is.

  • Keep existing XML chapters, or gradually add source comments and .autodoc files where they fit your preferred workflow.

  • Later, gradually move chapters or source documentation to your preferred style.

This flexibility is central: AutoDoc should make your current setup better, without forcing a full rewrite first.

1.3 Where to continue

For practical setup and migration workflows, continue with chapter 2. For the command reference of documentation comments, including standalone .autodoc files, see chapter 3.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap1.txt0000644000000000000000000000570715175510000012702 0ustar00 1 What AutoDoc offers AutoDoc helps you create and maintain package manuals for GAP. It is built on top of GAPDoc and generates the XML input that GAPDoc consumes. So AutoDoc complements GAPDoc instead of replacing it. The package is designed for a mix and match workflow: you can adopt only the parts that help you today, and add more over time. 1.1 Core features  Build package manuals via one reproducible command, usually gap makedoc.g.  Generate and maintain a title page from metadata in PackageInfo.g.  Generate and maintain a main XML file that includes your chapters.  Extract manual examples into .tst files via extract_examples := true.  Document declarations directly in source files via AutoDoc comments beginning with #!.  Organize chapter and section text either in source comments or in standalone .autodoc files.  Combine AutoDoc comments, classic GAPDoc source comments, and hand-written XML chapters in one manual. 1.2 Adopting AutoDoc incrementally You do not have to switch everything at once. Typical adoption paths include:  Use only AutoDoc (4.2-1) to rebuild an existing GAPDoc manual.  Enable only title-page generation, while keeping your custom main XML.  Keep your existing title page but use generated entities such as &VERSION;, &RELEASEYEAR;, and &RELEASEDATE;.  Add AutoDoc comments only for new code, and leave old documentation as-is.  Keep existing XML chapters, or gradually add source comments and .autodoc files where they fit your preferred workflow.  Later, gradually move chapters or source documentation to your preferred style. This flexibility is central: AutoDoc should make your current setup better, without forcing a full rewrite first. 1.3 Where to continue For practical setup and migration workflows, continue with chapter 2. For the command reference of documentation comments, including standalone .autodoc files, see chapter 3. AutoDoc-2026.05.03/doc/chap1_mj.html0000644000000000000000000001441615175510000013512 0ustar00 GAP (AutoDoc) - Chapter 1: What AutoDoc offers
Goto Chapter: Top 1 2 3 4 Bib Ind

1 What AutoDoc offers

AutoDoc helps you create and maintain package manuals for GAP. It is built on top of GAPDoc and generates the XML input that GAPDoc consumes. So AutoDoc complements GAPDoc instead of replacing it.

The package is designed for a mix and match workflow: you can adopt only the parts that help you today, and add more over time.

1.1 Core features

  • Build package manuals via one reproducible command, usually gap makedoc.g.

  • Generate and maintain a title page from metadata in PackageInfo.g.

  • Generate and maintain a main XML file that includes your chapters.

  • Extract manual examples into .tst files via extract_examples := true.

  • Document declarations directly in source files via AutoDoc comments beginning with #!.

  • Organize chapter and section text either in source comments or in standalone .autodoc files.

  • Combine AutoDoc comments, classic GAPDoc source comments, and hand-written XML chapters in one manual.

1.2 Adopting AutoDoc incrementally

You do not have to switch everything at once. Typical adoption paths include:

  • Use only AutoDoc (4.2-1) to rebuild an existing GAPDoc manual.

  • Enable only title-page generation, while keeping your custom main XML.

  • Keep your existing title page but use generated entities such as &VERSION;, &RELEASEYEAR;, and &RELEASEDATE;.

  • Add AutoDoc comments only for new code, and leave old documentation as-is.

  • Keep existing XML chapters, or gradually add source comments and .autodoc files where they fit your preferred workflow.

  • Later, gradually move chapters or source documentation to your preferred style.

This flexibility is central: AutoDoc should make your current setup better, without forcing a full rewrite first.

1.3 Where to continue

For practical setup and migration workflows, continue with chapter 2. For the command reference of documentation comments, including standalone .autodoc files, see chapter 3.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap2.html0000644000000000000000000011506515175510000013027 0ustar00 GAP (AutoDoc) - Chapter 2: Getting started using AutoDoc
Goto Chapter: Top 1 2 3 4 Bib Ind

2 Getting started using AutoDoc

This chapter gives practical workflows for adding AutoDoc to a package. For a high-level feature overview and adoption strategy, see chapter 1.

2.1 Choose your workflow

You can use AutoDoc in several ways, and it is fine to combine them:

  • Start a new package manual from scratch (Section 2.2).

  • Integrate AutoDoc into an existing GAPDoc manual (Section 2.4).

  • Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged.

This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful.

2.2 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.2-1) command like this:

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

When called from a file such as makedoc.g, AutoDoc uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the PackageInfo.g file from that package directory. It extracts information about the package from it (such as its name and version, see Section 2.5-1). It then creates two XML files doc/_main.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 2.4 of this manual on how to teach the AutoDoc (4.2-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 2.3).

You will probably want to re-run the AutoDoc (4.2-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:

gap makedoc.g

If you also want regression tests from your manual examples, enable extract_examples := true; this is explained in Section 2.4-1.

2.3 Documenting code with AutoDoc

AutoDoc supports several equally supported ways to organize your manual text. You can put chapter and section material directly into #! comments inside .g, .gd, or .gi files, you can put it into standalone .autodoc files, and you can mix either style with existing GAPDoc XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter 3, especially Section 3.4.

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:

Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the Declare... statement.

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

In these comment lines, you can freely use normal GAPDoc XML markup (with the usual exceptions for lines starting with @, which are interpreted as AutoDoc commands). So, for instance, tags like <Ref>, <A>, <K>, <List>, etc. can be written directly in #! comment text.

For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using #! @Chapter, #! @Section, and related commands, while others prefer standalone .autodoc files. In an .autodoc file you write the same commands without the #! prefix, and you list the file in autodoc.files or place it in a directory scanned via autodoc.scan_dirs. AutoDoc itself still uses the source-comment style in places, for example in gap/Magic.gd.

One caveat applies if you decide to keep prose in a standalone .autodoc file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

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

Suppose you have not been using GAPDoc before but instead used the process described in section 2.2 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 and standalone .autodoc files. Just make sure to first edit the main XML file of your documentation, and insert the line

&lt;#Include SYSTEM "_AutoDocMainFile.xml">

in a suitable place. This means that you can mix AutoDoc documentation comments and .autodoc files 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 then runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.

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

2.4 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, with AutoDoc it 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 this purpose only, e.g. io and orb.

In particular, this setup works well if you want to keep your existing manual structure and only adopt selected AutoDoc features first; for example automatic title-page data and predefined entities such as &VERSION;, &RELEASEYEAR; and &RELEASEDATE; (see Section 2.5-4).

2.4-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 session started in the root directory of your package:

LoadPackage( "AutoDoc" );
AutoDoc( );

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).

If you prefer to keep generated tests in a separate location, set extract_examples.subdir to a path relative to the package root:

LoadPackage( "AutoDoc" );
AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) );

This writes the extracted examples into tst/generated/ instead.

2.4-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" ) ) );

AutoDoc can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option autodoc.scan_dirs controls where it looks for source comments beginning with #! and for standalone .autodoc files. By default, it scans the package root directory and the subdirectories gap, lib, examples and examples/doc; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust autodoc.scan_dirs. The following example instructs AutoDoc to only search in the subdirectory package_sources of the package's root directory for those files.

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

The separate option gapdoc.scan_dirs serves a different purpose: it controls where GAPDoc comments are searched for.

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( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) );

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.2-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 ) ) );

The same behavior is also available via the global option relativePath. This is particularly convenient in a short makedoc.g script, and it overrides gapdoc.gap_root_relative_path if both are given. Since this is a GAP global option, you can also set it outside the eventual AutoDoc (4.2-1) call and let it propagate through nested calls; see Reference: Options Stack for more information about GAP's global options system:

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );

If you pass relativePath := true, then AutoDoc uses the default relative path ../../...

For example, if your makedoc.g reads the manual via AutoDoc (4.2-1), then the following command sets both relativePath and nopdf to true for that nested call:

Read( "makedoc.g" : nopdf, relativePath );

Finally, if you only want HTML and text output, you can suppress PDF generation with the global option nopdf:

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

This is useful if pdflatex is unavailable, or when you want a faster documentation rebuild while editing.

You can also request the same behavior from the shell by setting the environment variable NOPDF before invoking makedoc.g. For example:

NOPDF=1 gap makedoc.g

If NOPDF is set, AutoDoc skips PDF generation even if no nopdf option is given in the GAP code.

2.4-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/_main.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. However, note that this only works in the PDF version of the file.

  • 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.)

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

  • 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.

2.5 Scaffolds

2.5-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.

2.5-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.2-1) function.

2.5-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 record controls extra settings used by AutoDoc while generating the manual. In particular, PkgInfo.AutoDoc.TitlePage lets you add or override title-page elements coming from package metadata.

Typical fields you may set there include TitleComment, Abstract, Copyright, Acknowledgements and Colophon. For example, in PackageInfo.g:

SetPackageInfo( rec(
  ...
  AutoDoc := rec(
    TitlePage := rec(
      Copyright := "(C) 2026 Jane Doe",
      Acknowledgements := "Funded by Example Grant 1234."
    )
  )
) );

This inserts <Copyright> and <Acknowledgements> blocks into the generated title.xml.

PkgInfo.AutoDoc.TitlePage has exactly the same meaning as scaffold.TitlePage in AutoDoc (4.2-1). The function documentation for scaffold.TitlePage points back to this subsection.

2.5-4 Entities from PackageInfo.g and scaffold options

Besides title-page fields, you can define custom entities in AutoDoc.entities inside PackageInfo.g. They are written to doc/_entities.xml, so they can be used both by generated main files and by hand-written main XML files.

In addition, AutoDoc predefines the entities VERSION, RELEASEYEAR and RELEASEDATE, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with PackageInfo.g.

You can specify scaffold-related settings in PackageInfo.g and in your makedoc.g call at the same time; both records are merged, and values from makedoc.g take precedence when both define the same key.

2.6 Worksheets

For stand-alone documents that are not tied to a package, use AutoDocWorksheet (4.1-1). Its documentation and examples are in Section 4.1 of chapter 4.2-1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap2.txt0000644000000000000000000007501015175510000012675 0ustar00 2 Getting started using AutoDoc This chapter gives practical workflows for adding AutoDoc to a package. For a high-level feature overview and adoption strategy, see chapter 1. 2.1 Choose your workflow You can use AutoDoc in several ways, and it is fine to combine them:  Start a new package manual from scratch (Section 2.2).  Integrate AutoDoc into an existing GAPDoc manual (Section 2.4).  Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged. This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful. 2.2 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.2-1) command like this:  LoadPackage( "AutoDoc" ); AutoDoc( rec( scaffold := true ) );  When called from a file such as makedoc.g, AutoDoc uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the PackageInfo.g file from that package directory. It extracts information about the package from it (such as its name and version, see Section 2.5-1). It then creates two XML files doc/_main.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 2.4 of this manual on how to teach the AutoDoc (4.2-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 2.3). You will probably want to re-run the AutoDoc (4.2-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:  gap makedoc.g  If you also want regression tests from your manual examples, enable extract_examples := true; this is explained in Section 2.4-1. 2.3 Documenting code with AutoDoc AutoDoc supports several equally supported ways to organize your manual text. You can put chapter and section material directly into #! comments inside .g, .gd, or .gi files, you can put it into standalone .autodoc files, and you can mix either style with existing GAPDoc XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter 3, especially Section 3.4. 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: Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the Declare... statement.  #! @Arguments conv #! @Returns a toric variety #! @Description #! Creates a toric variety out #! of the convex object conv. DeclareOperation( "ToricVariety", [ IsConvexObject ] );  In these comment lines, you can freely use normal GAPDoc XML markup (with the usual exceptions for lines starting with @, which are interpreted as AutoDoc commands). So, for instance, tags like , , , , etc. can be written directly in #! comment text. For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using #! @Chapter, #! @Section, and related commands, while others prefer standalone .autodoc files. In an .autodoc file you write the same commands without the #! prefix, and you list the file in autodoc.files or place it in a directory scanned via autodoc.scan_dirs. AutoDoc itself still uses the source-comment style in places, for example in gap/Magic.gd. One caveat applies if you decide to keep prose in a standalone .autodoc file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue #60 in the AutoDoc issue tracker. For a thorough description of what you can do with AutoDoc documentation comments, please refer to chapter 3. Suppose you have not been using GAPDoc before but instead used the process described in section 2.2 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 and standalone .autodoc files. 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 comments and .autodoc files 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 then runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) );  2.4 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, with AutoDoc it 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 this purpose only, e.g. io and orb. In particular, this setup works well if you want to keep your existing manual structure and only adopt selected AutoDoc features first; for example automatic title-page data and predefined entities such as &VERSION;, &RELEASEYEAR; and &RELEASEDATE; (see Section 2.5-4). 2.4-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 session started in the root directory of your package:  LoadPackage( "AutoDoc" ); AutoDoc( );  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). If you prefer to keep generated tests in a separate location, set extract_examples.subdir to a path relative to the package root:  LoadPackage( "AutoDoc" ); AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) );  This writes the extracted examples into tst/generated/ instead. 2.4-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" ) ) );  AutoDoc can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option autodoc.scan_dirs controls where it looks for source comments beginning with #! and for standalone .autodoc files. By default, it scans the package root directory and the subdirectories gap, lib, examples and examples/doc; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust autodoc.scan_dirs. The following example instructs AutoDoc to only search in the subdirectory package_sources of the package's root directory for those files.  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := rec( scan_dirs := [ "package_sources" ] ) ) );  The separate option gapdoc.scan_dirs serves a different purpose: it controls where GAPDoc comments are searched for. 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( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) );  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.2-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 ) ) );  The same behavior is also available via the global option relativePath. This is particularly convenient in a short makedoc.g script, and it overrides gapdoc.gap_root_relative_path if both are given. Since this is a GAP global option, you can also set it outside the eventual AutoDoc (4.2-1) call and let it propagate through nested calls; see 'Reference: Options Stack' for more information about GAP's global options system:  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );  If you pass relativePath := true, then AutoDoc uses the default relative path ../../... For example, if your makedoc.g reads the manual via AutoDoc (4.2-1), then the following command sets both relativePath and nopdf to true for that nested call:  Read( "makedoc.g" : nopdf, relativePath );  Finally, if you only want HTML and text output, you can suppress PDF generation with the global option nopdf:  LoadPackage( "AutoDoc" ); AutoDoc( rec( autodoc := true ) : nopdf );  This is useful if pdflatex is unavailable, or when you want a faster documentation rebuild while editing. You can also request the same behavior from the shell by setting the environment variable NOPDF before invoking makedoc.g. For example:  NOPDF=1 gap makedoc.g  If NOPDF is set, AutoDoc skips PDF generation even if no nopdf option is given in the GAP code. 2.4-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/_main.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. However, note that this only works in the PDF version of the file.  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.)  In the entities record enter any entities previously stored in your manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the AutoDoc file PackageInfo.g defines entities for the names of packages io and PackageName.  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. 2.5 Scaffolds 2.5-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. 2.5-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.2-1) function. 2.5-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 record controls extra settings used by AutoDoc while generating the manual. In particular, PkgInfo.AutoDoc.TitlePage lets you add or override title-page elements coming from package metadata. Typical fields you may set there include TitleComment, Abstract, Copyright, Acknowledgements and Colophon. For example, in PackageInfo.g:   SetPackageInfo( rec(  ...  AutoDoc := rec(  TitlePage := rec(  Copyright := "(C) 2026 Jane Doe",  Acknowledgements := "Funded by Example Grant 1234."  )  ) ) );  This inserts <Copyright> and <Acknowledgements> blocks into the generated title.xml. PkgInfo.AutoDoc.TitlePage has exactly the same meaning as scaffold.TitlePage in AutoDoc (4.2-1). The function documentation for scaffold.TitlePage points back to this subsection. 2.5-4 Entities from PackageInfo.g and scaffold options Besides title-page fields, you can define custom entities in AutoDoc.entities inside PackageInfo.g. They are written to doc/_entities.xml, so they can be used both by generated main files and by hand-written main XML files. In addition, AutoDoc predefines the entities VERSION, RELEASEYEAR and RELEASEDATE, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with PackageInfo.g. You can specify scaffold-related settings in PackageInfo.g and in your makedoc.g call at the same time; both records are merged, and values from makedoc.g take precedence when both define the same key. 2.6 Worksheets For stand-alone documents that are not tied to a package, use AutoDocWorksheet (4.1-1). Its documentation and examples are in Section 4.1 of chapter 4.2-1. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AutoDoc-2026.05.03/doc/chap2_mj.html����������������������������������������������������������������0000644�0000000�0000000�00000115565�15175510000�013522� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?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://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script> <title>GAP (AutoDoc) - Chapter 2: Getting started using AutoDoc

2 Getting started using AutoDoc

This chapter gives practical workflows for adding AutoDoc to a package. For a high-level feature overview and adoption strategy, see chapter 1.

2.1 Choose your workflow

You can use AutoDoc in several ways, and it is fine to combine them:

  • Start a new package manual from scratch (Section 2.2).

  • Integrate AutoDoc into an existing GAPDoc manual (Section 2.4).

  • Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged.

This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful.

2.2 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.2-1) command like this:

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

When called from a file such as makedoc.g, AutoDoc uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the PackageInfo.g file from that package directory. It extracts information about the package from it (such as its name and version, see Section 2.5-1). It then creates two XML files doc/_main.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 2.4 of this manual on how to teach the AutoDoc (4.2-1) command to include this extra documentation. Or you could use the special documentation facilities AutoDoc provides (see Section 2.3).

You will probably want to re-run the AutoDoc (4.2-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:

gap makedoc.g

If you also want regression tests from your manual examples, enable extract_examples := true; this is explained in Section 2.4-1.

2.3 Documenting code with AutoDoc

AutoDoc supports several equally supported ways to organize your manual text. You can put chapter and section material directly into #! comments inside .g, .gd, or .gi files, you can put it into standalone .autodoc files, and you can mix either style with existing GAPDoc XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter 3, especially Section 3.4.

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:

Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the Declare... statement.

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

In these comment lines, you can freely use normal GAPDoc XML markup (with the usual exceptions for lines starting with @, which are interpreted as AutoDoc commands). So, for instance, tags like <Ref>, <A>, <K>, <List>, etc. can be written directly in #! comment text.

For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using #! @Chapter, #! @Section, and related commands, while others prefer standalone .autodoc files. In an .autodoc file you write the same commands without the #! prefix, and you list the file in autodoc.files or place it in a directory scanned via autodoc.scan_dirs. AutoDoc itself still uses the source-comment style in places, for example in gap/Magic.gd.

One caveat applies if you decide to keep prose in a standalone .autodoc file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

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

Suppose you have not been using GAPDoc before but instead used the process described in section 2.2 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 and standalone .autodoc files. Just make sure to first edit the main XML file of your documentation, and insert the line

&lt;#Include SYSTEM "_AutoDocMainFile.xml">

in a suitable place. This means that you can mix AutoDoc documentation comments and .autodoc files 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 then runs GAPDoc to produce HTML and PDF output, but does not touch your documentation XML files otherwise.

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

2.4 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, with AutoDoc it 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 this purpose only, e.g. io and orb.

In particular, this setup works well if you want to keep your existing manual structure and only adopt selected AutoDoc features first; for example automatic title-page data and predefined entities such as &VERSION;, &RELEASEYEAR; and &RELEASEDATE; (see Section 2.5-4).

2.4-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 session started in the root directory of your package:

LoadPackage( "AutoDoc" );
AutoDoc( );

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).

If you prefer to keep generated tests in a separate location, set extract_examples.subdir to a path relative to the package root:

LoadPackage( "AutoDoc" );
AutoDoc( rec( extract_examples := rec( subdir := "tst/generated" ) ) );

This writes the extracted examples into tst/generated/ instead.

2.4-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" ) ) );

AutoDoc can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option autodoc.scan_dirs controls where it looks for source comments beginning with #! and for standalone .autodoc files. By default, it scans the package root directory and the subdirectories gap, lib, examples and examples/doc; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust autodoc.scan_dirs. The following example instructs AutoDoc to only search in the subdirectory package_sources of the package's root directory for those files.

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

The separate option gapdoc.scan_dirs serves a different purpose: it controls where GAPDoc comments are searched for.

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( autodoc := rec( files := [ "path/to/some/hidden/file.gd" ] ) ) );

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.2-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 ) ) );

The same behavior is also available via the global option relativePath. This is particularly convenient in a short makedoc.g script, and it overrides gapdoc.gap_root_relative_path if both are given. Since this is a GAP global option, you can also set it outside the eventual AutoDoc (4.2-1) call and let it propagate through nested calls; see Reference: Options Stack for more information about GAP's global options system:

LoadPackage( "AutoDoc" );
AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );

If you pass relativePath := true, then AutoDoc uses the default relative path ../../...

For example, if your makedoc.g reads the manual via AutoDoc (4.2-1), then the following command sets both relativePath and nopdf to true for that nested call:

Read( "makedoc.g" : nopdf, relativePath );

Finally, if you only want HTML and text output, you can suppress PDF generation with the global option nopdf:

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

This is useful if pdflatex is unavailable, or when you want a faster documentation rebuild while editing.

You can also request the same behavior from the shell by setting the environment variable NOPDF before invoking makedoc.g. For example:

NOPDF=1 gap makedoc.g

If NOPDF is set, AutoDoc skips PDF generation even if no nopdf option is given in the GAP code.

2.4-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/_main.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\). However, note that this only works in the PDF version of the file.

  • 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.)

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

  • 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.

2.5 Scaffolds

2.5-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.

2.5-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.2-1) function.

2.5-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 record controls extra settings used by AutoDoc while generating the manual. In particular, PkgInfo.AutoDoc.TitlePage lets you add or override title-page elements coming from package metadata.

Typical fields you may set there include TitleComment, Abstract, Copyright, Acknowledgements and Colophon. For example, in PackageInfo.g:

SetPackageInfo( rec(
  ...
  AutoDoc := rec(
    TitlePage := rec(
      Copyright := "(C) 2026 Jane Doe",
      Acknowledgements := "Funded by Example Grant 1234."
    )
  )
) );

This inserts <Copyright> and <Acknowledgements> blocks into the generated title.xml.

PkgInfo.AutoDoc.TitlePage has exactly the same meaning as scaffold.TitlePage in AutoDoc (4.2-1). The function documentation for scaffold.TitlePage points back to this subsection.

2.5-4 Entities from PackageInfo.g and scaffold options

Besides title-page fields, you can define custom entities in AutoDoc.entities inside PackageInfo.g. They are written to doc/_entities.xml, so they can be used both by generated main files and by hand-written main XML files.

In addition, AutoDoc predefines the entities VERSION, RELEASEYEAR and RELEASEDATE, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with PackageInfo.g.

You can specify scaffold-related settings in PackageInfo.g and in your makedoc.g call at the same time; both records are merged, and values from makedoc.g take precedence when both define the same key.

2.6 Worksheets

For stand-alone documents that are not tied to a package, use AutoDocWorksheet (4.1-1). Its documentation and examples are in Section 4.1 of chapter 4.2-1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap3.html0000644000000000000000000014661415175510000013034 0ustar00 GAP (AutoDoc) - Chapter 3: AutoDoc documentation comments
Goto Chapter: Top 1 2 3 4 Bib Ind

3 AutoDoc documentation comments

You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declarations. 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.

For declaration documentation, the associated declaration must appear immediately after the AutoDoc comment block. In particular, do not insert other code (such as if false then or assignments) between the comment block and the Declare... statement.

This also works for InstallMethod and InstallOtherMethod. In that case, AutoDoc uses the installed method's name and filter list to create a manual entry for the implemented item.

Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces. Any comment line that does not start with an AutoDoc command is treated as regular documentation text and may contain (almost) arbitrary GAPDoc XML markup, such as <Ref>, <A>, <List>, and similar tags. This lets you use the normal GAPDoc formatting toolbox directly inside AutoDoc comments.

For example:

#! @Description
#!  See <Ref Chap="Chapter_Tutorials"/> for setup details.
#!  The argument <A>obj</A> must satisfy <K>IsObject</K>.

As explained in chapter 1, you can combine AutoDoc comments with hand-written XML and classic GAPDoc comments. For practical setup and migration workflows, see chapter 2.

3.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:

3.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.

3.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.

3.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.

For DeclareGlobalName, using @Arguments or @Returns also makes AutoDoc document the item as a function. This is useful because DeclareGlobalName itself does not reveal whether the name denotes a function or a variable.

3.1-4 @ItemType kind

Overrides the kind of manual item created for the following declaration or installed method. The supported values are Attr, Cat, Coll, Constr, Fam, Filt, Func, InfoClass, Meth, Oper, Prop, Repr, and Var.

The values Cat, Coll, and Repr are AutoDoc-specific aliases. They emit Filt entries with the corresponding GAPDoc filter type.

This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as DeclareAttribute or DeclareProperty, AutoDoc already knows the intended type from the declaration itself.

It is useful for DeclareGlobalName, because that declaration can refer to either a function or a variable. AutoDoc defaults such entries to Var, but switches to Func as soon as @Arguments or @Returns indicates function-style documentation. You can still use @ItemType to override this explicitly.

It is useful for DeclareSynonym, because that declaration can document a function synonym or one of several filter-like synonyms. Use @ItemType Filt, Cat, Coll, or Repr to control which kind of filter entry should be emitted.

For example:

#! @ItemType Repr
DeclareSynonym( "IsSomethingRep", IsComponentObjectRep );

This makes AutoDoc emit a <Filt Type="Representation" .../> manual entry.

3.1-5 @Group grpname

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

3.1-6 @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:

<ManSection>
  <Prop Arg="arg" Name="AProperty" Label="testlabel"/>
 <Returns> <K>true</K> or <K>false</K>
</Returns>
 <Description>
 </Description>
</ManSection>

while

#!
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

<ManSection>
  <Prop Arg="arg" Name="AProperty" Label="for IsObject"/>
 <Returns> <K>true</K> or <K>false</K>
</Returns>
 <Description>
 </Description>
</ManSection>

3.1-7 @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 );

3.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.

3.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.

3.2-2 @Appendix name

This is analogous to @Chapter, but generates Appendix elements instead of Chapter elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in scaffold.appendix.

Example:

@Appendix Supplementary material

@Section Additional tables

3.2-3 @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.

3.2-4 @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.

3.2-5 @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 3.5 for more information about groups.

3.2-6 @EndGroup

Ends the current group.

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

DeclareOperation( "NonGroupedOperation",
                  [ IsObject ] );

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

3.2-7 @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 3.5 for more information.

3.2-8 @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. If you enable extract_examples := true when calling AutoDoc (4.2-1), these examples can also be turned into .tst files (see Section 2.4-1).

3.2-9 @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.

3.2-10 @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.

3.2-11 @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.

3.2-12 @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.

3.2-13 @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

3.2-14 @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.

3.2-15 @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}

3.2-16 @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.

3.2-17 @Index key [entry text]

Adds an index entry to the current documentation text. The command @Index key entry text generates <Index Key="key">entry text</Index>. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. @Index "my key" entry text. The entry text is processed like normal documentation text, so markdown-like inline code such as true is supported.

3.3 Title page commands

The following commands can be used to add corresponding parts to the title page of a document generated by AutoDoc.

  • @Title

  • @Subtitle

  • @Version

  • @TitleComment

  • @Author

  • @Date

  • @Address

  • @Abstract

  • @Copyright

  • @Acknowledgements

  • @Colophon

Many of these values can (and for package manuals typically should) be extracted from PackageInfo.g. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful for worksheets created with AutoDocWorksheet (4.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted.

3.4 Plain text files

Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.2-1), resp. are contained in one of the directories listed in autodoc.scan_dirs or one of their subdirectories, are treated as standalone AutoDoc input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material.

Conceptually, a .autodoc file uses the same parser as AutoDoc comments, but without the comment marker. In a .autodoc file, lines do not need to start with #! and in fact usually should not. This makes .autodoc files one convenient way to replace hand-written XML chapters when you prefer AutoDoc's command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and AutoDoc itself still uses that style in files such as gap/Magic.gd. For the surrounding workflow, see Chapter 2.

The most important difference from declaration comments is that a plain text file does not document a declaration by adjacency. There is no following Declare... or InstallMethod statement for AutoDoc to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration.

In practice, this gives the following rule of thumb.

  • Use source comments beginning with #! to document declarations. This is the mode for @Description, @Returns, @Arguments, @Label, @Group, and @ChapterInfo.

  • Use either .autodoc files or source comments for standalone manual structure and prose. Commands such as @Chapter, @Section, @Subsection, grouping commands, examples and logs, chunks and code insertion, @Index, title-page commands, Markdown-style headings, fenced code blocks, and ordinary GAPDoc XML markup work in both styles.

As a concrete example, the following file can serve as a complete chapter written in .autodoc format.

@Chapter Test
@Section First Section
@Subsection First Subsection

This text belongs directly to the manual chapter.
It can use XML tags such as <A>arg</A> or <Ref .../>.

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

@Index "Worksheet Autoplain" Plain worksheet index entry with `true`

This is essentially the style used in the worksheet fixture tst/worksheets/autoplain.sheet/plain.autodoc.

The same structural commands can also be used inside source comments, for example:

#! @Chapter Reference
#! @Section The AutoDoc() function
#! Some introductory text for this section.

This source-comment style is still fully supported and is used in gap/Magic.gd.

The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include _AutoDocMainFile.xml from the main XML file as described in Chapter 2, and add one or more .autodoc files via autodoc.files or autodoc.scan_dirs. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged.

One caveat is worth keeping in mind. If you want a standalone .autodoc file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

So, while .autodoc files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient.

3.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:

<ManSection Label="Group1">
<Heading>A family of operations</Heading>
  <Oper Arg="arg" Name="FirstOperation" Label="for IsInt"/>
  <Oper Arg="arg1,arg2" Name="SecondOperation" Label="for IsInt, IsGroup"/>
  <Oper Arg="arg1,arg2" Name="ThirdOperation" Label="for IsGroup, IsInt"/>
 <Description>
First sentence.
Second sentence.
Third sentence.
 </Description>
</ManSection>

3.6 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.

3.6-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.

3.6-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.

3.6-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.

3.6-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.

3.6-5 Fenced code blocks

One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values @listing, @example, and @log select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate <Listing>. Example:

#! ```@listing
#! if x = 2 then
#!   Print("1 + 1 = 2 holds, all is good\n");
#! fi;
#! ```
#! ~~~@example
#! gap> [ 1 .. 3 ] ^ 2;
#! [ 1, 4, 9 ]
#! ~~~
#! ```@log
#! #I  some log message
#! ```

This produces the following output:

if x = 2 then
  Print("1 + 1 = 2 holds, all is good\n");
fi;
gap> [ 1 .. 3 ] ^ 2;
[ 1, 4, 9 ]
#I  some log message

3.7 Deprecated commands

The following commands used to be supported, but are not supported anymore.

@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 appear in the manual with a minimal AutoDoc comment #!.

@BeginSystem name, @EndSystem, and @InsertSystem name

Please use the chunk commands from subsection 3.2-13 instead.

@AutoDocPlainText and @EndAutoDocPlainText

Use .autodoc files or AutoDoc comments instead.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap3.txt0000644000000000000000000011547515175510000012710 0ustar00 3 AutoDoc documentation comments You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declarations. 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. For declaration documentation, the associated declaration must appear immediately after the AutoDoc comment block. In particular, do not insert other code (such as if false then or assignments) between the comment block and the Declare... statement. This also works for InstallMethod and InstallOtherMethod. In that case, AutoDoc uses the installed method's name and filter list to create a manual entry for the implemented item. Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces. Any comment line that does not start with an AutoDoc command is treated as regular documentation text and may contain (almost) arbitrary GAPDoc XML markup, such as , , , and similar tags. This lets you use the normal GAPDoc formatting toolbox directly inside AutoDoc comments. For example:  #! @Description #! See for setup details. #! The argument obj must satisfy IsObject.  As explained in chapter 1, you can combine AutoDoc comments with hand-written XML and classic GAPDoc comments. For practical setup and migration workflows, see chapter 2. 3.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: 3.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. 3.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. 3.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. For DeclareGlobalName, using @Arguments or @Returns also makes AutoDoc document the item as a function. This is useful because DeclareGlobalName itself does not reveal whether the name denotes a function or a variable. 3.1-4 @ItemType kind Overrides the kind of manual item created for the following declaration or installed method. The supported values are Attr, Cat, Coll, Constr, Fam, Filt, Func, InfoClass, Meth, Oper, Prop, Repr, and Var. The values Cat, Coll, and Repr are AutoDoc-specific aliases. They emit Filt entries with the corresponding GAPDoc filter type. This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as DeclareAttribute or DeclareProperty, AutoDoc already knows the intended type from the declaration itself. It is useful for DeclareGlobalName, because that declaration can refer to either a function or a variable. AutoDoc defaults such entries to Var, but switches to Func as soon as @Arguments or @Returns indicates function-style documentation. You can still use @ItemType to override this explicitly. It is useful for DeclareSynonym, because that declaration can document a function synonym or one of several filter-like synonyms. Use @ItemType Filt, Cat, Coll, or Repr to control which kind of filter entry should be emitted. For example:  #! @ItemType Repr DeclareSynonym( "IsSomethingRep", IsComponentObjectRep );  This makes AutoDoc emit a  manual entry. 3.1-5 @Group grpname Adds the following method to a group with the given name. See section 3.5 for more information about groups. 3.1-6 @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:      true or false        while  #! DeclareProperty( "AProperty",  IsObject );  leads to this:      true or false        3.1-7 @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 );  3.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. 3.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. 3.2-2 @Appendix name This is analogous to @Chapter, but generates Appendix elements instead of Chapter elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in scaffold.appendix. Example:  @Appendix Supplementary material  @Section Additional tables  3.2-3 @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. 3.2-4 @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. 3.2-5 @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 3.5 for more information about groups. 3.2-6 @EndGroup Ends the current group.  #! @BeginGroup MyGroup #! DeclareAttribute( "GroupedAttribute",  IsList );  DeclareOperation( "NonGroupedOperation",  [ IsObject ] );  #! DeclareOperation( "GroupedOperation",  [ IsList, IsRubbish ] ); #! @EndGroup  3.2-7 @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 3.5 for more information. 3.2-8 @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. If you enable extract_examples := true when calling AutoDoc (4.2-1), these examples can also be turned into .tst files (see Section 2.4-1). 3.2-9 @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. 3.2-10 @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. 3.2-11 @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. 3.2-12 @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.  3.2-13 @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  3.2-14 @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.  3.2-15 @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}  3.2-16 @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.  3.2-17 @Index key [entry text] Adds an index entry to the current documentation text. The command @Index key entry text generates entry text. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. @Index "my key" entry text. The entry text is processed like normal documentation text, so markdown-like inline code such as true is supported. 3.3 Title page commands The following commands can be used to add corresponding parts to the title page of a document generated by AutoDoc.  @Title  @Subtitle  @Version  @TitleComment  @Author  @Date  @Address  @Abstract  @Copyright  @Acknowledgements  @Colophon Many of these values can (and for package manuals typically should) be extracted from PackageInfo.g. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful for worksheets created with AutoDocWorksheet (4.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted. 3.4 Plain text files Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.2-1), resp. are contained in one of the directories listed in autodoc.scan_dirs or one of their subdirectories, are treated as standalone AutoDoc input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material. Conceptually, a .autodoc file uses the same parser as AutoDoc comments, but without the comment marker. In a .autodoc file, lines do not need to start with #! and in fact usually should not. This makes .autodoc files one convenient way to replace hand-written XML chapters when you prefer AutoDoc's command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and AutoDoc itself still uses that style in files such as gap/Magic.gd. For the surrounding workflow, see Chapter 2. The most important difference from declaration comments is that a plain text file does not document a declaration by adjacency. There is no following Declare... or InstallMethod statement for AutoDoc to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration. In practice, this gives the following rule of thumb.  Use source comments beginning with #! to document declarations. This is the mode for @Description, @Returns, @Arguments, @Label, @Group, and @ChapterInfo.  Use either .autodoc files or source comments for standalone manual structure and prose. Commands such as @Chapter, @Section, @Subsection, grouping commands, examples and logs, chunks and code insertion, @Index, title-page commands, Markdown-style headings, fenced code blocks, and ordinary GAPDoc XML markup work in both styles. As a concrete example, the following file can serve as a complete chapter written in .autodoc format.  @Chapter Test @Section First Section @Subsection First Subsection  This text belongs directly to the manual chapter. It can use XML tags such as arg or .  @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession  @Index "Worksheet Autoplain" Plain worksheet index entry with `true`  This is essentially the style used in the worksheet fixture tst/worksheets/autoplain.sheet/plain.autodoc. The same structural commands can also be used inside source comments, for example:  #! @Chapter Reference #! @Section The AutoDoc() function #! Some introductory text for this section.  This source-comment style is still fully supported and is used in gap/Magic.gd. The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include _AutoDocMainFile.xml from the main XML file as described in Chapter 2, and add one or more .autodoc files via autodoc.files or autodoc.scan_dirs. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged. One caveat is worth keeping in mind. If you want a standalone .autodoc file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue #60 in the AutoDoc issue tracker. So, while .autodoc files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient. 3.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:   A family of operations         First sentence. Second sentence. Third sentence.     3.6 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. 3.6-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. 3.6-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.  3.6-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. 3.6-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. 3.6-5 Fenced code blocks One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values @listing, @example, and @log select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate . Example:  #! ```@listing #! if x = 2 then #! Print("1 + 1 = 2 holds, all is good\n"); #! fi; #! ``` #! ~~~@example #! gap> [ 1 .. 3 ] ^ 2; #! [ 1, 4, 9 ] #! ~~~ #! ```@log #! #I some log message #! ```  This produces the following output:  if x = 2 then  Print("1 + 1 = 2 holds, all is good\n"); fi;   Example  gap> [ 1 .. 3 ] ^ 2; [ 1, 4, 9 ]   Example  #I some log message  3.7 Deprecated commands The following commands used to be supported, but are not supported anymore. @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 appear in the manual with a minimal AutoDoc comment #!. @BeginSystem name, @EndSystem, and @InsertSystem name Please use the chunk commands from subsection 3.2-13 instead. @AutoDocPlainText and @EndAutoDocPlainText Use .autodoc files or AutoDoc comments instead. AutoDoc-2026.05.03/doc/chap3_mj.html0000644000000000000000000014736615175510000013527 0ustar00 GAP (AutoDoc) - Chapter 3: AutoDoc documentation comments
Goto Chapter: Top 1 2 3 4 Bib Ind

3 AutoDoc documentation comments

You can document declarations of global functions and variables, operations, attributes etc. by inserting AutoDoc comments into your sources before these declarations. 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.

For declaration documentation, the associated declaration must appear immediately after the AutoDoc comment block. In particular, do not insert other code (such as if false then or assignments) between the comment block and the Declare... statement.

This also works for InstallMethod and InstallOtherMethod. In that case, AutoDoc uses the installed method's name and filter list to create a manual entry for the implemented item.

Inside of AutoDoc comments, AutoDoc commands starting with @ can be used to control the output AutoDoc produces. Any comment line that does not start with an AutoDoc command is treated as regular documentation text and may contain (almost) arbitrary GAPDoc XML markup, such as <Ref>, <A>, <List>, and similar tags. This lets you use the normal GAPDoc formatting toolbox directly inside AutoDoc comments.

For example:

#! @Description
#!  See <Ref Chap="Chapter_Tutorials"/> for setup details.
#!  The argument <A>obj</A> must satisfy <K>IsObject</K>.

As explained in chapter 1, you can combine AutoDoc comments with hand-written XML and classic GAPDoc comments. For practical setup and migration workflows, see chapter 2.

3.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:

3.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.

3.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.

3.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.

For DeclareGlobalName, using @Arguments or @Returns also makes AutoDoc document the item as a function. This is useful because DeclareGlobalName itself does not reveal whether the name denotes a function or a variable.

3.1-4 @ItemType kind

Overrides the kind of manual item created for the following declaration or installed method. The supported values are Attr, Cat, Coll, Constr, Fam, Filt, Func, InfoClass, Meth, Oper, Prop, Repr, and Var.

The values Cat, Coll, and Repr are AutoDoc-specific aliases. They emit Filt entries with the corresponding GAPDoc filter type.

This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as DeclareAttribute or DeclareProperty, AutoDoc already knows the intended type from the declaration itself.

It is useful for DeclareGlobalName, because that declaration can refer to either a function or a variable. AutoDoc defaults such entries to Var, but switches to Func as soon as @Arguments or @Returns indicates function-style documentation. You can still use @ItemType to override this explicitly.

It is useful for DeclareSynonym, because that declaration can document a function synonym or one of several filter-like synonyms. Use @ItemType Filt, Cat, Coll, or Repr to control which kind of filter entry should be emitted.

For example:

#! @ItemType Repr
DeclareSynonym( "IsSomethingRep", IsComponentObjectRep );

This makes AutoDoc emit a <Filt Type="Representation" .../> manual entry.

3.1-5 @Group grpname

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

3.1-6 @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:

<ManSection>
  <Prop Arg="arg" Name="AProperty" Label="testlabel"/>
 <Returns> <K>true</K> or <K>false</K>
</Returns>
 <Description>
 </Description>
</ManSection>

while

#!
DeclareProperty( "AProperty",
                 IsObject );

leads to this:

<ManSection>
  <Prop Arg="arg" Name="AProperty" Label="for IsObject"/>
 <Returns> <K>true</K> or <K>false</K>
</Returns>
 <Description>
 </Description>
</ManSection>

3.1-7 @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 );

3.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.

3.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.

3.2-2 @Appendix name

This is analogous to @Chapter, but generates Appendix elements instead of Chapter elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in scaffold.appendix.

Example:

@Appendix Supplementary material

@Section Additional tables

3.2-3 @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.

3.2-4 @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.

3.2-5 @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 3.5 for more information about groups.

3.2-6 @EndGroup

Ends the current group.

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

DeclareOperation( "NonGroupedOperation",
                  [ IsObject ] );

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

3.2-7 @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 3.5 for more information.

3.2-8 @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. If you enable extract_examples := true when calling AutoDoc (4.2-1), these examples can also be turned into .tst files (see Section 2.4-1).

3.2-9 @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.

3.2-10 @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.

3.2-11 @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.

3.2-12 @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.

3.2-13 @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

3.2-14 @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.

3.2-15 @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}

3.2-16 @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.

3.2-17 @Index key [entry text]

Adds an index entry to the current documentation text. The command @Index key entry text generates <Index Key="key">entry text</Index>. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. @Index "my key" entry text. The entry text is processed like normal documentation text, so markdown-like inline code such as true is supported.

3.3 Title page commands

The following commands can be used to add corresponding parts to the title page of a document generated by AutoDoc.

  • @Title

  • @Subtitle

  • @Version

  • @TitleComment

  • @Author

  • @Date

  • @Address

  • @Abstract

  • @Copyright

  • @Acknowledgements

  • @Colophon

Many of these values can (and for package manuals typically should) be extracted from PackageInfo.g. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful for worksheets created with AutoDocWorksheet (4.1-1), since worksheets do not have a PackageInfo.g file from which this information could be extracted.

3.4 Plain text files

Files that have the suffix .autodoc and are listed in the autodoc.files option of AutoDoc (4.2-1), resp. are contained in one of the directories listed in autodoc.scan_dirs or one of their subdirectories, are treated as standalone AutoDoc input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material.

Conceptually, a .autodoc file uses the same parser as AutoDoc comments, but without the comment marker. In a .autodoc file, lines do not need to start with #! and in fact usually should not. This makes .autodoc files one convenient way to replace hand-written XML chapters when you prefer AutoDoc's command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and AutoDoc itself still uses that style in files such as gap/Magic.gd. For the surrounding workflow, see Chapter 2.

The most important difference from declaration comments is that a plain text file does not document a declaration by adjacency. There is no following Declare... or InstallMethod statement for AutoDoc to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration.

In practice, this gives the following rule of thumb.

  • Use source comments beginning with #! to document declarations. This is the mode for @Description, @Returns, @Arguments, @Label, @Group, and @ChapterInfo.

  • Use either .autodoc files or source comments for standalone manual structure and prose. Commands such as @Chapter, @Section, @Subsection, grouping commands, examples and logs, chunks and code insertion, @Index, title-page commands, Markdown-style headings, fenced code blocks, and ordinary GAPDoc XML markup work in both styles.

As a concrete example, the following file can serve as a complete chapter written in .autodoc format.

@Chapter Test
@Section First Section
@Subsection First Subsection

This text belongs directly to the manual chapter.
It can use XML tags such as <A>arg</A> or <Ref .../>.

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

@Index "Worksheet Autoplain" Plain worksheet index entry with `true`

This is essentially the style used in the worksheet fixture tst/worksheets/autoplain.sheet/plain.autodoc.

The same structural commands can also be used inside source comments, for example:

#! @Chapter Reference
#! @Section The AutoDoc() function
#! Some introductory text for this section.

This source-comment style is still fully supported and is used in gap/Magic.gd.

The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include _AutoDocMainFile.xml from the main XML file as described in Chapter 2, and add one or more .autodoc files via autodoc.files or autodoc.scan_dirs. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged.

One caveat is worth keeping in mind. If you want a standalone .autodoc file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

So, while .autodoc files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient.

3.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:

<ManSection Label="Group1">
<Heading>A family of operations</Heading>
  <Oper Arg="arg" Name="FirstOperation" Label="for IsInt"/>
  <Oper Arg="arg1,arg2" Name="SecondOperation" Label="for IsInt, IsGroup"/>
  <Oper Arg="arg1,arg2" Name="ThirdOperation" Label="for IsGroup, IsInt"/>
 <Description>
First sentence.
Second sentence.
Third sentence.
 </Description>
</ManSection>

3.6 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.

3.6-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.

3.6-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. \]

3.6-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.

3.6-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.

3.6-5 Fenced code blocks

One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values @listing, @example, and @log select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate <Listing>. Example:

#! ```@listing
#! if x = 2 then
#!   Print("1 + 1 = 2 holds, all is good\n");
#! fi;
#! ```
#! ~~~@example
#! gap> [ 1 .. 3 ] ^ 2;
#! [ 1, 4, 9 ]
#! ~~~
#! ```@log
#! #I  some log message
#! ```

This produces the following output:

if x = 2 then
  Print("1 + 1 = 2 holds, all is good\n");
fi;
gap> [ 1 .. 3 ] ^ 2;
[ 1, 4, 9 ]
#I  some log message

3.7 Deprecated commands

The following commands used to be supported, but are not supported anymore.

@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 appear in the manual with a minimal AutoDoc comment #!.

@BeginSystem name, @EndSystem, and @InsertSystem name

Please use the chunk commands from subsection 3.2-13 instead.

@AutoDocPlainText and @EndAutoDocPlainText

Use .autodoc files or AutoDoc comments instead.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap4.html0000644000000000000000000007162615175510000013035 0ustar00 GAP (AutoDoc) - Chapter 4: Reference
Goto Chapter: Top 1 2 3 4 Bib Ind

4 Reference

4.1 AutoDoc worksheets

4.1-1 AutoDocWorksheet
‣ AutoDocWorksheet( [filenames][,] [optrec] )( function )

The purpose of this function is to create stand-alone PDF and HTML files using AutoDoc without associating them with a package.

Instead of a package directory, you pass one filename or a list of filenames containing AutoDoc text from which the document is created. Settings are supplied via an optional record using the same entries as the optrec argument of AutoDoc (4.2-1). Alternatively, you may omit filenames and specify the files via optrec.autodoc.files.

A simple worksheet file can define title-page information and chapter content directly in the source file, including example blocks. If this is stored in worksheet.g, you can generate documentation via

 AutoDocWorksheet( "worksheet.g" );

This creates documentation in a doc subdirectory of the current directory.

Since worksheets do not have a PackageInfo.g, title-page fields are specified directly in the worksheet file.

For backwards compatibility, worksheet calls still accept GAP global options for specifying the option-record entries such as dir, scaffold, autodoc, gapdoc, and extract_examples. However, this feature is deprecated.

4.2 The AutoDoc() function

4.2-1 AutoDoc
‣ AutoDoc( [pkgdir][,] [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/_main.xml 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, using documentation comments and commands. This produces additional 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)).

These tasks can be enabled independently, so you can use as much or as little of AutoDoc as your package currently needs. For more information and some examples, please refer to Chapter 2.

The parameters have the following meanings:

pkgdir

This optional parameter is used to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. If given, it should be an IsDirectory object. If the argument is omitted, then AutoDoc checks if it was called from a makedoc.g file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both 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.

For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package GAP knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package.

Note that when using AutoDocWorksheet (see 4.1), there is no parameter corresponding to pkgdir 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 written directly in GAPDoc XML. Appendices created with @Appendix are included automatically after these files when scaffolding generates the main XML file.

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.

bibstyle

Overrides the bibliography style used for LaTeX output. This is written as the Style attribute of the generated <Bibliography .../> element, so valid values are the bibliography style names understood by GAPDoc and BibTeX, such as alpha, alphaurl, or plain.

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.

Note that AutoDoc predefines several entities:

VERSION

Set to the Version field of your package info record.

RELEASEYEAR

Set to a string containing the release year, as derived from the Date field of your package info record.

RELEASEDATE

Derived from the Date field of your package info record.

SomePackage

The precise name of this entity is derived from the PackageName field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above.

TitlePage

A record with extra title-page fields for the generated manual. Field names are interpreted as title-page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with

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

If this is set in PackageInfo.g as PkgInfo.AutoDoc.TitlePage, it has the same meaning as this option; see subsection 2.5-3 in chapter 2 for details and an example.

For the list of valid title-page elements, see 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 recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls where AutoDoc looks for source comments beginning with #! and for standalone .autodoc files. It does not affect where GAPDoc looks for GAPDoc comments; that is controlled separately by gapdoc.scan_dirs.
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: _main.xml when scaffolding is enabled for package manuals, otherwise 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 recursively for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls only where GAPDoc comments are searched for. It does not affect where AutoDoc looks for source comments beginning with #! or for .autodoc files; use autodoc.scan_dirs for that.
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.

If set to a record, it may contain the following entries:

subdir

A string or Directory() object selecting where the generated .tst files are written. The default is tst. If a string is given, it is interpreted relative to the package directory, so values such as tst/generated are supported.

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.

The function also checks the following GAP global options, i.e. options supplied via GAP's value-option syntax and visible through nested calls. These are not entries of optrec. See Reference: Options Stack for more information about GAP's global options system.

nopdf

If this global option is set to true, then AutoDoc tells GAPDoc not to build the PDF version of the manual. HTML and text output are still generated.

This is useful on systems without a working pdflatex installation, or when you only need the non-PDF outputs while iterating on the manual.

For example:

     AutoDoc( rec( autodoc := true ) : nopdf );

Also, if the environment variable NOPDF is set, then AutoDoc behaves as if the global option nopdf had been enabled.

relativePath

This has the same effect as gapdoc.gap_root_relative_path, but as a GAP global option. It takes precedence over that record entry if both are specified.

If relativePath is true, then the default relative path ../../.. is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root.

For example:

     AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );

In particular, a call such as

 Read( "makedoc.g" : nopdf, relativePath );

sets both global options to true, and they remain visible to the AutoDoc call inside makedoc.g.

4.2-2 InfoAutoDoc
‣ InfoAutoDoc( info class )

Info class for the AutoDoc package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths.

This can be set by calling, for example, SetInfoLevel(InfoAutoDoc, 0). Default value is 1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chap4.txt0000644000000000000000000006563015175510000012706 0ustar00 4 Reference 4.1 AutoDoc worksheets 4.1-1 AutoDocWorksheet AutoDocWorksheet( [filenames][,] [optrec] )  function The purpose of this function is to create stand-alone PDF and HTML files using AutoDoc without associating them with a package. Instead of a package directory, you pass one filename or a list of filenames containing AutoDoc text from which the document is created. Settings are supplied via an optional record using the same entries as the optrec argument of AutoDoc (4.2-1). Alternatively, you may omit filenames and specify the files via optrec.autodoc.files. A simple worksheet file can define title-page information and chapter content directly in the source file, including example blocks. If this is stored in worksheet.g, you can generate documentation via  Example   AutoDocWorksheet( "worksheet.g" );  This creates documentation in a doc subdirectory of the current directory. Since worksheets do not have a PackageInfo.g, title-page fields are specified directly in the worksheet file. For backwards compatibility, worksheet calls still accept GAP global options for specifying the option-record entries such as dir, scaffold, autodoc, gapdoc, and extract_examples. However, this feature is deprecated. 4.2 The AutoDoc() function 4.2-1 AutoDoc AutoDoc( [pkgdir][,] [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/_main.xml 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, using documentation comments and commands. This produces additional 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)). These tasks can be enabled independently, so you can use as much or as little of AutoDoc as your package currently needs. For more information and some examples, please refer to Chapter 2. The parameters have the following meanings: pkgdir This optional parameter is used to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. If given, it should be an IsDirectory object. If the argument is omitted, then AutoDoc checks if it was called from a makedoc.g file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both 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. For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package GAP knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package. Note that when using AutoDocWorksheet (see 4.1), there is no parameter corresponding to pkgdir 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 written directly in GAPDoc XML. Appendices created with @Appendix are included automatically after these files when scaffolding generates the main XML file. 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. bibstyle Overrides the bibliography style used for LaTeX output. This is written as the Style attribute of the generated  element, so valid values are the bibliography style names understood by GAPDoc and BibTeX, such as alpha, alphaurl, or plain. 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. Note that AutoDoc predefines several entities: VERSION Set to the Version field of your package info record. RELEASEYEAR Set to a string containing the release year, as derived from the Date field of your package info record. RELEASEDATE Derived from the Date field of your package info record. SomePackage The precise name of this entity is derived from the PackageName field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above. TitlePage A record with extra title-page fields for the generated manual. Field names are interpreted as title-page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with    rec( Acknowledgements := "Many thanks to ..." )  If this is set in PackageInfo.g as PkgInfo.AutoDoc.TitlePage, it has the same meaning as this option; see subsection 2.5-3 in chapter 2 for details and an example. For the list of valid title-page elements, see 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 recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls where AutoDoc looks for source comments beginning with #! and for standalone .autodoc files. It does not affect where GAPDoc looks for GAPDoc comments; that is controlled separately by gapdoc.scan_dirs. 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: _main.xml when scaffolding is enabled for package manuals, otherwise 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 recursively for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls only where GAPDoc comments are searched for. It does not affect where AutoDoc looks for source comments beginning with #! or for .autodoc files; use autodoc.scan_dirs for that. 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. If set to a record, it may contain the following entries: subdir A string or Directory() object selecting where the generated .tst files are written. The default is tst. If a string is given, it is interpreted relative to the package directory, so values such as tst/generated are supported. 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. The function also checks the following GAP global options, i.e. options supplied via GAP's value-option syntax and visible through nested calls. These are not entries of optrec. See 'Reference: Options Stack' for more information about GAP's global options system. nopdf If this global option is set to true, then AutoDoc tells GAPDoc not to build the PDF version of the manual. HTML and text output are still generated. This is useful on systems without a working pdflatex installation, or when you only need the non-PDF outputs while iterating on the manual. For example:    AutoDoc( rec( autodoc := true ) : nopdf );  Also, if the environment variable NOPDF is set, then AutoDoc behaves as if the global option nopdf had been enabled. relativePath This has the same effect as gapdoc.gap_root_relative_path, but as a GAP global option. It takes precedence over that record entry if both are specified. If relativePath is true, then the default relative path ../../.. is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root. For example:    AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );  In particular, a call such as   Read( "makedoc.g" : nopdf, relativePath );  sets both global options to true, and they remain visible to the AutoDoc call inside makedoc.g. 4.2-2 InfoAutoDoc InfoAutoDoc  info class Info class for the AutoDoc package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths. This can be set by calling, for example, SetInfoLevel(InfoAutoDoc, 0). Default value is 1. AutoDoc-2026.05.03/doc/chap4_mj.html0000644000000000000000000007221515175510000013516 0ustar00 GAP (AutoDoc) - Chapter 4: Reference
Goto Chapter: Top 1 2 3 4 Bib Ind

4 Reference

4.1 AutoDoc worksheets

4.1-1 AutoDocWorksheet
‣ AutoDocWorksheet( [filenames][,] [optrec] )( function )

The purpose of this function is to create stand-alone PDF and HTML files using AutoDoc without associating them with a package.

Instead of a package directory, you pass one filename or a list of filenames containing AutoDoc text from which the document is created. Settings are supplied via an optional record using the same entries as the optrec argument of AutoDoc (4.2-1). Alternatively, you may omit filenames and specify the files via optrec.autodoc.files.

A simple worksheet file can define title-page information and chapter content directly in the source file, including example blocks. If this is stored in worksheet.g, you can generate documentation via

 AutoDocWorksheet( "worksheet.g" );

This creates documentation in a doc subdirectory of the current directory.

Since worksheets do not have a PackageInfo.g, title-page fields are specified directly in the worksheet file.

For backwards compatibility, worksheet calls still accept GAP global options for specifying the option-record entries such as dir, scaffold, autodoc, gapdoc, and extract_examples. However, this feature is deprecated.

4.2 The AutoDoc() function

4.2-1 AutoDoc
‣ AutoDoc( [pkgdir][,] [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/_main.xml 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, using documentation comments and commands. This produces additional 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)).

These tasks can be enabled independently, so you can use as much or as little of AutoDoc as your package currently needs. For more information and some examples, please refer to Chapter 2.

The parameters have the following meanings:

pkgdir

This optional parameter is used to determine the package directory in which AutoDoc will operate, and to find the metadata concerning the package being documented. If given, it should be an IsDirectory object. If the argument is omitted, then AutoDoc checks if it was called from a makedoc.g file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both 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.

For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package GAP knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package.

Note that when using AutoDocWorksheet (see 4.1), there is no parameter corresponding to pkgdir 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 written directly in GAPDoc XML. Appendices created with @Appendix are included automatically after these files when scaffolding generates the main XML file.

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.

bibstyle

Overrides the bibliography style used for LaTeX output. This is written as the Style attribute of the generated <Bibliography .../> element, so valid values are the bibliography style names understood by GAPDoc and BibTeX, such as alpha, alphaurl, or plain.

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.

Note that AutoDoc predefines several entities:

VERSION

Set to the Version field of your package info record.

RELEASEYEAR

Set to a string containing the release year, as derived from the Date field of your package info record.

RELEASEDATE

Derived from the Date field of your package info record.

SomePackage

The precise name of this entity is derived from the PackageName field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above.

TitlePage

A record with extra title-page fields for the generated manual. Field names are interpreted as title-page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with

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

If this is set in PackageInfo.g as PkgInfo.AutoDoc.TitlePage, it has the same meaning as this option; see subsection 2.5-3 in chapter 2 for details and an example.

For the list of valid title-page elements, see 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 recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for AutoDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls where AutoDoc looks for source comments beginning with #! and for standalone .autodoc files. It does not affect where GAPDoc looks for GAPDoc comments; that is controlled separately by gapdoc.scan_dirs.
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: _main.xml when scaffolding is enabled for package manuals, otherwise 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 recursively for .gi, .gd and .g files; all of these files are then scanned for GAPDoc documentation comments. The special entries "." and "" still only scan the package root itself. This controls only where GAPDoc comments are searched for. It does not affect where AutoDoc looks for source comments beginning with #! or for .autodoc files; use autodoc.scan_dirs for that.
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.

If set to a record, it may contain the following entries:

subdir

A string or Directory() object selecting where the generated .tst files are written. The default is tst. If a string is given, it is interpreted relative to the package directory, so values such as tst/generated are supported.

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.

The function also checks the following GAP global options, i.e. options supplied via GAP's value-option syntax and visible through nested calls. These are not entries of optrec. See Reference: Options Stack for more information about GAP's global options system.

nopdf

If this global option is set to true, then AutoDoc tells GAPDoc not to build the PDF version of the manual. HTML and text output are still generated.

This is useful on systems without a working pdflatex installation, or when you only need the non-PDF outputs while iterating on the manual.

For example:

     AutoDoc( rec( autodoc := true ) : nopdf );

Also, if the environment variable NOPDF is set, then AutoDoc behaves as if the global option nopdf had been enabled.

relativePath

This has the same effect as gapdoc.gap_root_relative_path, but as a GAP global option. It takes precedence over that record entry if both are specified.

If relativePath is true, then the default relative path ../../.. is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root.

For example:

     AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );

In particular, a call such as

 Read( "makedoc.g" : nopdf, relativePath );

sets both global options to true, and they remain visible to the AutoDoc call inside makedoc.g.

4.2-2 InfoAutoDoc
‣ InfoAutoDoc( info class )

Info class for the AutoDoc package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths.

This can be set by calling, for example, SetInfoLevel(InfoAutoDoc, 0). Default value is 1.

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chapBib.html0000644000000000000000000000472315175510000013360 0ustar00 GAP (AutoDoc) - References
Goto Chapter: Top 1 2 3 4 Bib Ind

References

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

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chapBib.txt0000644000000000000000000000047015175510000013226 0ustar00 References [LN24] Lübeck, F. and Neunhöffer, M., GAPDoc (Version 1.6.7), RWTH Aachen (2024), ( GAP package, https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc/index.html ).  AutoDoc-2026.05.03/doc/chapBib_mj.html0000644000000000000000000000522415175510000014043 0ustar00 GAP (AutoDoc) - References
Goto Chapter: Top 1 2 3 4 Bib Ind

References

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

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chapInd.html0000644000000000000000000001577115175510000013403 0ustar00 GAP (AutoDoc) - Index
Goto Chapter: Top 1 2 3 4 Bib Ind

Index

@Appendix 3.2-2
@Arguments args 3.1-3
@BeginChunk name 3.2-13
@BeginCode name 3.2-14
@BeginExample 3.2-8
@BeginExampleSession 3.2-9
@BeginGroup 3.2-5
@BeginLatexOnly 3.2-15
@BeginLog 3.2-10
@BeginLogSession 3.2-11
@BeginNotLatex 3.2-16
@Chapter 3.2-1
@ChapterInfo 3.1-7
@ChapterLabel 3.2-1
@ChapterTitle 3.2-1
@Description descr 3.1-1
@DoNotReadRestOfFile 3.2-12
@InsertChunk name 3.2-13
@EndChunk 3.2-13
@EndCode 3.2-14
@EndExample 3.2-8
@EndExampleSession 3.2-9
@EndGroup 3.2-6
@EndLatexOnly 3.2-15
@EndLog 3.2-10
@EndLogSession 3.2-11
@EndNotLatex 3.2-16
@Group grpname 3.1-5
@GroupTitle 3.2-7
@Index key [entry text] 3.2-17
@InsertCode name 3.2-14
@ItemType kind 3.1-4
@Label label 3.1-6
@LatexOnly text 3.2-15
@NotLatex text 3.2-16
@Returns ret_val 3.1-2
@Section 3.2-3
@SectionLabel 3.2-3
@SectionTitle 3.2-3
@Subsection 3.2-4
@SubsectionLabel 3.2-4
@SubsectionTitle 3.2-4
2.4-3 2.4-3
AutoDoc 4.2-1
AutoDocWorksheet 4.1-1
2.4-3 2.4-3 2.4-3
InfoAutoDoc 4.2-2
2.4-3
makedoc.g 2.2
2.4-3

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chapInd.txt0000644000000000000000000000365515175510000013254 0ustar00 Index @Appendix 3.2-2 @Arguments args 3.1-3 @BeginChunk name 3.2-13 @BeginCode name 3.2-14 @BeginExample 3.2-8 @BeginExampleSession 3.2-9 @BeginGroup 3.2-5 @BeginLatexOnly 3.2-15 @BeginLog 3.2-10 @BeginLogSession 3.2-11 @BeginNotLatex 3.2-16 @Chapter 3.2-1 @ChapterInfo 3.1-7 @ChapterLabel 3.2-1 @ChapterTitle 3.2-1 @Description descr 3.1-1 @DoNotReadRestOfFile 3.2-12 @InsertChunk name 3.2-13 @EndChunk 3.2-13 @EndCode 3.2-14 @EndExample 3.2-8 @EndExampleSession 3.2-9 @EndGroup 3.2-6 @EndLatexOnly 3.2-15 @EndLog 3.2-10 @EndLogSession 3.2-11 @EndNotLatex 3.2-16 @Group grpname 3.1-5 @GroupTitle 3.2-7 @Index key [entry text] 3.2-17 @InsertCode name 3.2-14 @ItemType kind 3.1-4 @Label label 3.1-6 @LatexOnly text 3.2-15 @NotLatex text 3.2-16 @Returns ret_val 3.1-2 @Section 3.2-3 @SectionLabel 3.2-3 @SectionTitle 3.2-3 @Subsection 3.2-4 @SubsectionLabel 3.2-4 @SubsectionTitle 3.2-4 2.4-3 2.4-3 AutoDoc 4.2-1 AutoDocWorksheet 4.1-1 2.4-3 2.4-3 2.4-3 InfoAutoDoc 4.2-2 2.4-3 makedoc.g 2.2 2.4-3 ------------------------------------------------------- AutoDoc-2026.05.03/doc/chapInd_mj.html0000644000000000000000000001652315175510000014065 0ustar00 GAP (AutoDoc) - Index
Goto Chapter: Top 1 2 3 4 Bib Ind

Index

@Appendix 3.2-2
@Arguments args 3.1-3
@BeginChunk name 3.2-13
@BeginCode name 3.2-14
@BeginExample 3.2-8
@BeginExampleSession 3.2-9
@BeginGroup 3.2-5
@BeginLatexOnly 3.2-15
@BeginLog 3.2-10
@BeginLogSession 3.2-11
@BeginNotLatex 3.2-16
@Chapter 3.2-1
@ChapterInfo 3.1-7
@ChapterLabel 3.2-1
@ChapterTitle 3.2-1
@Description descr 3.1-1
@DoNotReadRestOfFile 3.2-12
@InsertChunk name 3.2-13
@EndChunk 3.2-13
@EndCode 3.2-14
@EndExample 3.2-8
@EndExampleSession 3.2-9
@EndGroup 3.2-6
@EndLatexOnly 3.2-15
@EndLog 3.2-10
@EndLogSession 3.2-11
@EndNotLatex 3.2-16
@Group grpname 3.1-5
@GroupTitle 3.2-7
@Index key [entry text] 3.2-17
@InsertCode name 3.2-14
@ItemType kind 3.1-4
@Label label 3.1-6
@LatexOnly text 3.2-15
@NotLatex text 3.2-16
@Returns ret_val 3.1-2
@Section 3.2-3
@SectionLabel 3.2-3
@SectionTitle 3.2-3
@Subsection 3.2-4
@SubsectionLabel 3.2-4
@SubsectionTitle 3.2-4
2.4-3 2.4-3
AutoDoc 4.2-1
AutoDocWorksheet 4.1-1
2.4-3 2.4-3 2.4-3
InfoAutoDoc 4.2-2
2.4-3
makedoc.g 2.2
2.4-3

Goto Chapter: Top 1 2 3 4 Bib Ind

generated by GAPDoc2HTML

AutoDoc-2026.05.03/doc/chooser.html0000644000000000000000000000745615175510000013500 0ustar00 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-2026.05.03/doc/lefttoc.css0000644000000000000000000000047415175510000013313 0ustar00/* 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-2026.05.03/doc/manual.css0000644000000000000000000001575415175510000013137 0ustar00/* 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-2026.05.03/doc/manual.js0000644000000000000000000001011315175510000012743 0ustar00/* 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-2026.05.03/doc/manual.lab0000644000000000000000000001675515175510000013107 0ustar00\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:What AutoDoc offers}{1}{X786190217AE14EBF} \makelabel{autodoc:Core features}{1.1}{X7A835D9779307F98} \makelabel{autodoc:Adopting AutoDoc incrementally}{1.2}{X8081E3BA7B3EC702} \makelabel{autodoc:Where to continue}{1.3}{X83D6D8B481C07CD8} \makelabel{autodoc:Getting started using AutoDoc}{2}{X7A0D7AA484F466E1} \makelabel{autodoc:Choose your workflow}{2.1}{X7BEF736283D2A7A9} \makelabel{autodoc:Creating a package manual from scratch}{2.2}{X7BFBC6907B26AA95} \makelabel{autodoc:Documenting code with AutoDoc}{2.3}{X87A00EED866E22E8} \makelabel{autodoc:Using AutoDoc in an existing GAPDoc manual}{2.4}{X7FA614637B807F4D} \makelabel{autodoc:Using AutoDoc on a complete GAPDoc manual}{2.4.1}{X7F3CEB097AF47C1E} \makelabel{autodoc:Setting different GAPDoc options}{2.4.2}{X7D0DDF2284F2D24A} \makelabel{autodoc:Checklist for converting an existing GAPDoc manual to use AutoDoc}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:Scaffolds}{2.5}{X8524193D824CDE0D} \makelabel{autodoc:Generating a title page}{2.5.1}{X7CF22DE28478316F} \makelabel{autodoc:Generating the main XML file}{2.5.2}{X7CD72CC780874FD5} \makelabel{autodoc:What data is used from PackageInfo.g?}{2.5.3}{X799956EA85D3FC15} \makelabel{autodoc:Entities from PackageInfo.g and scaffold options}{2.5.4}{X79EAEF277DD1FAE1} \makelabel{autodoc:Worksheets}{2.6}{X801D4A2F8292704C} \makelabel{autodoc:AutoDoc documentation comments}{3}{X87668C487B1A2094} \makelabel{autodoc:Documenting declarations}{3.1}{X871482CE838C68F6} \makelabel{autodoc:@Description descr}{3.1.1}{X7F1D85188262A827} \makelabel{autodoc:@Returns ret val}{3.1.2}{X7EFF79F47BE24F78} \makelabel{autodoc:@Arguments args}{3.1.3}{X81DAA454857F7971} \makelabel{autodoc:@ItemType kind}{3.1.4}{X852A9FCA7AB6EC4E} \makelabel{autodoc:@Group grpname}{3.1.5}{X8677FE8F80C00B14} \makelabel{autodoc:@Label label}{3.1.6}{X7B0E20A27D64DF6F} \makelabel{autodoc:@ChapterInfo chapter, section}{3.1.7}{X78938EE37A532FFA} \makelabel{autodoc:Other documentation comments}{3.2}{X8152FEF9844B1ACD} \makelabel{autodoc:@Chapter name}{3.2.1}{X823E613385D09F6F} \makelabel{autodoc:@Appendix name}{3.2.2}{X83163DA586882825} \makelabel{autodoc:@Section name}{3.2.3}{X78AA98BA7E0635D0} \makelabel{autodoc:@Subsection name}{3.2.4}{X7FD77434802A3580} \makelabel{autodoc:@BeginGroup [grpname]}{3.2.5}{X7D3060C17EDBCED1} \makelabel{autodoc:@EndGroup}{3.2.6}{X7C17EB007FD42C87} \makelabel{autodoc:@GroupTitle title}{3.2.7}{X82FB96F37FAE8167} \makelabel{autodoc:@BeginExample and @EndExample}{3.2.8}{X83D6DA3B83D3436C} \makelabel{autodoc:@BeginExampleSession and @EndExampleSession}{3.2.9}{X861E2E778510CAF7} \makelabel{autodoc:@BeginLog and @EndLog}{3.2.10}{X81A2D44D834C0A17} \makelabel{autodoc:@BeginLogSession and @EndLogSession}{3.2.11}{X7BADE876794FF309} \makelabel{autodoc:@DoNotReadRestOfFile}{3.2.12}{X78DC644E8519280C} \makelabel{autodoc:@BeginChunk name, @EndChunk, and @InsertChunk name}{3.2.13}{X83C01F9B7FA1C973} \makelabel{autodoc:@BeginCode name, @EndCode, and @InsertCode name}{3.2.14}{X7D3671AF86B995B9} \makelabel{autodoc:@LatexOnly text, @BeginLatexOnly, and @EndLatexOnly}{3.2.15}{X8033B34F80A12A10} \makelabel{autodoc:@NotLatex text, @BeginNotLatex, and @EndNotLatex}{3.2.16}{X7EF303147F1BCC22} \makelabel{autodoc:@Index key [entry text]}{3.2.17}{X82FD2EEB788E76F1} \makelabel{autodoc:Title page commands}{3.3}{X841E3AD584F5385C} \makelabel{autodoc:Plain text files}{3.4}{X828AE38F80CB02E7} \makelabel{autodoc:Grouping}{3.5}{X7D7A38F87BC40C48} \makelabel{autodoc:Markdown-like formatting of text in AutoDoc}{3.6}{X79558A2F7FE187B4} \makelabel{autodoc:Lists}{3.6.1}{X7B256AE5780F140A} \makelabel{autodoc:Math modes}{3.6.2}{X871412737A0E12E2} \makelabel{autodoc:Emphasize}{3.6.3}{X7ED0330479146EFC} \makelabel{autodoc:Inline code}{3.6.4}{X838CCDEB7E0ECEE2} \makelabel{autodoc:Fenced code blocks}{3.6.5}{X7C0629B183765575} \makelabel{autodoc:Deprecated commands}{3.7}{X78CA9E5C7F494C19} \makelabel{autodoc:Reference}{4}{X782AAE4E86411FF4} \makelabel{autodoc:AutoDoc worksheets}{4.1}{X80ED3C2A78146AD1} \makelabel{autodoc:The AutoDoc() function}{4.2}{X863584DB8497D8BA} \makelabel{autodoc:Bibliography}{Bib}{X7A6F98FD85F02BFE} \makelabel{autodoc:References}{Bib}{X7A6F98FD85F02BFE} \makelabel{autodoc:Index}{Ind}{X83A0356F839C696F} \makelabel{autodoc:makedoc.g}{2.2}{X7BFBC6907B26AA95} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:}{2.4.3}{X83448D91868D7994} \makelabel{autodoc:@Description descr}{3.1.1}{X7F1D85188262A827} \makelabel{autodoc:@Returns retval}{3.1.2}{X7EFF79F47BE24F78} \makelabel{autodoc:@Arguments args}{3.1.3}{X81DAA454857F7971} \makelabel{autodoc:@ItemType kind}{3.1.4}{X852A9FCA7AB6EC4E} \makelabel{autodoc:@Group grpname}{3.1.5}{X8677FE8F80C00B14} \makelabel{autodoc:@Label label}{3.1.6}{X7B0E20A27D64DF6F} \makelabel{autodoc:@ChapterInfo}{3.1.7}{X78938EE37A532FFA} \makelabel{autodoc:@Chapter}{3.2.1}{X823E613385D09F6F} \makelabel{autodoc:@ChapterLabel}{3.2.1}{X823E613385D09F6F} \makelabel{autodoc:@ChapterTitle}{3.2.1}{X823E613385D09F6F} \makelabel{autodoc:@Appendix}{3.2.2}{X83163DA586882825} \makelabel{autodoc:@Section}{3.2.3}{X78AA98BA7E0635D0} \makelabel{autodoc:@SectionLabel}{3.2.3}{X78AA98BA7E0635D0} \makelabel{autodoc:@SectionTitle}{3.2.3}{X78AA98BA7E0635D0} \makelabel{autodoc:@Subsection}{3.2.4}{X7FD77434802A3580} \makelabel{autodoc:@SubsectionLabel}{3.2.4}{X7FD77434802A3580} \makelabel{autodoc:@SubsectionTitle}{3.2.4}{X7FD77434802A3580} \makelabel{autodoc:@BeginGroup}{3.2.5}{X7D3060C17EDBCED1} \makelabel{autodoc:@EndGroup}{3.2.6}{X7C17EB007FD42C87} \makelabel{autodoc:@GroupTitle}{3.2.7}{X82FB96F37FAE8167} \makelabel{autodoc:@BeginExample}{3.2.8}{X83D6DA3B83D3436C} \makelabel{autodoc:@EndExample}{3.2.8}{X83D6DA3B83D3436C} \makelabel{autodoc:@BeginExampleSession}{3.2.9}{X861E2E778510CAF7} \makelabel{autodoc:@EndExampleSession}{3.2.9}{X861E2E778510CAF7} \makelabel{autodoc:@BeginLog}{3.2.10}{X81A2D44D834C0A17} \makelabel{autodoc:@EndLog}{3.2.10}{X81A2D44D834C0A17} \makelabel{autodoc:@BeginLogSession}{3.2.11}{X7BADE876794FF309} \makelabel{autodoc:@EndLogSession}{3.2.11}{X7BADE876794FF309} \makelabel{autodoc:@DoNotReadRestOfFile}{3.2.12}{X78DC644E8519280C} \makelabel{autodoc:@BeginChunk name}{3.2.13}{X83C01F9B7FA1C973} \makelabel{autodoc:@EndChunk}{3.2.13}{X83C01F9B7FA1C973} \makelabel{autodoc:@InsertChunk name}{3.2.13}{X83C01F9B7FA1C973} \makelabel{autodoc:@BeginCode name}{3.2.14}{X7D3671AF86B995B9} \makelabel{autodoc:@EndCode}{3.2.14}{X7D3671AF86B995B9} \makelabel{autodoc:@InsertCode name}{3.2.14}{X7D3671AF86B995B9} \makelabel{autodoc:@LatexOnly text}{3.2.15}{X8033B34F80A12A10} \makelabel{autodoc:@BeginLatexOnly}{3.2.15}{X8033B34F80A12A10} \makelabel{autodoc:@EndLatexOnly}{3.2.15}{X8033B34F80A12A10} \makelabel{autodoc:@NotLatex text}{3.2.16}{X7EF303147F1BCC22} \makelabel{autodoc:@BeginNotLatex}{3.2.16}{X7EF303147F1BCC22} \makelabel{autodoc:@EndNotLatex}{3.2.16}{X7EF303147F1BCC22} \makelabel{autodoc:@Index key [entry text]}{3.2.17}{X82FD2EEB788E76F1} \makelabel{autodoc:AutoDocWorksheet}{4.1.1}{X809FE4137C08B28D} \makelabel{autodoc:AutoDoc}{4.2.1}{X7CBD8AAF7DCEF352} \makelabel{autodoc:InfoAutoDoc}{4.2.2}{X81F946A785BA3D6E} AutoDoc-2026.05.03/doc/manual.pdf0000644000000000000000000106750415175510000013121 0ustar00%PDF-1.5 % 105 0 obj << /Length 734 /Filter /FlateDecode >> stream xڽVMO@W<NPAmPzX%}wvzlmf潙yo-#Fhzt4(LI4bGc9O G.cCH%ω5H3mij;MEټ6uZ讜`5.P킔8NX(h-+hʋzQ$ f2,:ή@#Ha Jw`4`+lb *B9*d_[Sթ&2kjjz80L t?7!pqAҠ-V*c[W&+ ~'I>lE9e4> stream xڝTMs Wp&GtLU{IrBP]N=>} f79CTπ03D+08U`;]OǛ%%#,ĎmDH99x< (²}[#jC^/@`N$4Cɫfvte"&hq :#W 6C ӉEld6 vA=Cx!4fW3W/=par endstream endobj 150 0 obj << /Length 1078 /Filter /FlateDecode >> stream xYˎHWz?=5#&8"= ՘jaP2.2C/,(_νs} t_7oQa (Z"#,Be,[S5jv??n QbF}aчD(0J9>:  p""ai5o1t2 qۘ_M/OT jKoe({=XA.bz0|x WNx"v\ Zjؾ[ik=&$E1HRfvއn5ۇy[fS˽l @ϦZl3-TyZ6!A7)b.{hـ, @ZژZAd~5J:Y \"kF<FZ覫]Ս.nfs7CT!0MC@#1;L[$Ʀ~3ExGBjί#Gok*c?dmVY$Hm:ku8"'Q{FM i֧"p{r^QJ '0~ܝ)'?W⯛Yi iqYr`?sZ[$ySʔG|ut‹6nu3ūCs>ΔT/S LBh/{dȕBeVww7a:oYw(6jQW R˄xӔzpb US2cӣBL0D߿/A7oOwr*Blٻz_`3:nor_. endstream endobj 157 0 obj << /Length 1672 /Filter /FlateDecode >> stream xڭX[o6~ϯ0Eԥ ukzEm!dHTPXR(w>{{<. b{3 Fo{ E=S}2{FسzWEqDԡ؛ M:+NB؃Ōa*ӛgvw^Ѻ랼 )lC N/$ 朡>$CNWz"B2׃}Z~zvHt#쫲MwuUkC=)Ȋ\R2_K,늝YF:8FqğrG8rj*aD( L mD)j(hzׯoԀEyh}ica!?Kv_VM (H:; Of޽H9?^< ~3{:e#Ek(ys@`@8Ҭ(7: $D [W4{ .Wؔ"30HT?Q=щ}*- vF_70fՌr)X\`G戼:H-*wwzQecRG#qmUB?sfjGՌpcM{ڐ 9/$5 Fxuĭaj؃jE @ )ϡЍ+{sK6+wf2ɍuNI) rp1#~^eh3C4a9 )PRjQ{mp5༳F4O NYbjU\WRBPR,ݻ_jZMMuVf6&9Ld7#yAY~u~P%UXd5hkk.H6r rD#L8vD)9V)'u+@e b<:/Z?޹v)eVZdIݳ`eܱcV8^ p݅qSk;N@[K\aҗxHEyo;\8H$piQgJ&=tG5)AFS;A% J!D(>{,: y=/uaP0?NA|ަ)Ib.BsX8ꂩַ}?!w"S8 .>Uf^a]_ո7I&4gcJAR,RgQh:akTo34ۄ#43Q^m$1"GzaF 4t,LmmSu'Ѥ26S7"6 ٝ:}*3i@йEfLG-]eRm2:vuFXXN!1^}z(8->5ǣs C˖z:dZثee1wFw,(EgWH=lp# e86 Yrd|* bo FK%jb_#ir^E9ȃTcx!6E- K=i޵s\ȢyìiUmi3pp,qo{6` 5S>nǣrqa?)QŽ\Ͼ ͢wSCq8ױ"֖oHZJw'ame 73="|w$wE!A`z 6-W X endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 824 /Length 2292 /Filter /FlateDecode >> stream xZnH}Wc`]}1Od`8̉ؒWMQx֦ EO:U}H(Q Z$A RB;# 4, $<"DBo tk6J0a&`*y%!N,ax0)j P`Yi+L+煳@?% D@NZLjG|B ODFh :ag(IK*JZc15gA /nbS}Uʹqoy5_%>OtҒ&j(n׀:YMeԭ/0;`sF>RScZn(dRp2%u)A=̻;M3sLp[`LLJTbs}}4A*]"g[>tpSmsORIUlćl>ߋDOmԦ6 pQ?1$ r h/F,OESѪ"N,geył= [k7kd덓1}9ɇ=z|:;%P)wGS-qDqh{_絫Z_jc+j0'z &ɤK;3]i~cEI@EXA63F/mXY$lRp|ؠrRӡpq$Mz /1w(.v|brz!?e &8ůoy7j9k4X /*YGY$Y'xGvr+Ti p_|Шc+  O^bţxP혅c(1E3{5fla E|y»N{yE j>ߙmPCk7Ύ#$5x3aX 3,c_fm> stream xڕUMo0 W(*wu]JbԱ[^?ʒ8;%6bH\SVkuNR*VLU;[&Wo%G?MI18mgA-ˈ -SI2%stO ؘ}Lc0ֽM|| bL_ l`tE5Ms EUEo4a]δE[p9=ҌH)'p<MJ'Jyc5]H?h!ђD%A%վ3ku C(~z\9D2g `2_$vg}~,agc<ɅmLW!FYmkP瞤4Jnj>+7Wj+љu^BMr'2GH>xZ̽q>;8SP;8.:mWkmCD.^D.@T]"^7]H@5N(8zlhF Btt2JQWPp²SKPf&s 1$yo}F( /JWE)q\jaV82ybCDTX)7> 2Ut^ۚG5>: 1Gql*a HP45)ayT5sf>9W~ endstream endobj 178 0 obj << /Length 1960 /Filter /FlateDecode >> stream xڭَ6Bȓ 9 s:;HZRDLE`MXL\pCd4Mx:̒ci"+*bW-:(B~^\G Q-c9jnu ~&L{!ra-ᘠzS.hq m*_ߛz߳J2yR@K9;⧅zS;dVH3|~m #N_RYDʅV!1]BL,ezr[Z_om dS)pgl`tTHY`7?Lh(.Y'GI((Rɧh@,Q"GC3e4h3HD4X~pЍMy]L_ҹ֨xlQgXJJʿE(EN,l yOeN aA ,$|aNPS"@\cm1O,X$1KyTd> g -UP?r`7}A($^eٹ7`Ş[=;M$8Qv}Úc#mcoJiO/h<ڦoyO;g#(.:WsaT;j%"ηegN}śLwCy /c^Pf٠8()rZf!Nz׎ %\ߋc3󈾜0vt$dXQeo?mR \SptzU^ ̪!K 袡qN@}! P{A~?T8?&#H~sٕk̛5RGf='Jʿ`C;->A5j̸Eg;/[0l_] z t> o+}s{F;kK{/ߊ0*cK*%wA> !B0W B-Kj&ňN0cYw6Ib7ƛ{Y07 W9 4IdzᘗS@Uѣo&^|U,9t|xRUm54S%@ƻ endstream endobj 193 0 obj << /Length 3139 /Filter /FlateDecode >> stream xڭْ}QViGs+r(ٖJR*%"ߞ$Af)s}LξP"DRn3%`J$ʟwޫM|d߽x虒" 7F$hvg{$oW&gpG(u(ϲջrw3)L>ڝV#jvsZat@$!S Lm@" J > $A D$Q GaI oCz_Ȯx/Jm*ie#:)L.#II)b"vdB˦C*׀HC08ugvH\ < u!H.ɑٲ7H+]ٽ{7ٳ;Ciȋbk7߿v&$ }-ӵ~U=;E'"0 ~uYr.}/ViI+$SI@ !0!oO +?$l 4'9d i۲G* iw=liӑU 4JHp4g_;/|sI,|W m)>[S{LbY( 4MMeSwFKٴ0hW7sКL;sU M>ΕCYّ_Q vr3ntbSlYm+9{ vohyڧX6ۼ3cA]8nSyjDT` vY4:6y_-γl2kd~+ڮDBp{Z @em+|cό8DcT-}l]B29{_6m$^ٛq}A@+Pƌ)-AQ_qղ'-ҨBt|]hUZV4y[t#ݔh_ltHsm1%eHHYjS Dh&pD sH:OSYZpc3;S/d~J+<{sБ[+YOx~:gc/  G]Ds4mFy5Fn~S?hASiǢQ𱇂]U Z٬VT ʑ&SL)DhY*1H7"޴ApH!/49tDdN`ҫ)g| )[TʻVT`{'4pzuf};h^{R\ڡ¯rZtpشd ]ʘ_z{3NN+moN !}>Ϯ,3 T|x?̉ ?x d:;W]WfSd'1SC!Jׁae8,: 0k$LX `o(|cuU۶X|][- E%q$0_]ߖIGAJ ]/HG̑&ڃU=-AIQ2QBKe N r<0IYOsdY`[oZ΅PLD{۹ |feUӥ=$#׹A=[E΅@vUia ]NhP`~@5+<$9J"3wDyoP^W +C~a 6 0XBڵ"S+!RNxX5}W=ņ*"HDq¥ x*`+]V b :i'تfKMVaG?5Ps9*`c+ &sKQC~(L(Au?ͮ@7ď/*! 4Ìb3mB %R`TcLW_6H`bȤuًE@bb ;rD EOѤ2oiigH|~{FM9t3_oh!A~*kg>,|o7Ŗ1l G"LFTgZ&˷0? }"K|o@&v$0Dl&90`S#غZ}c۬I.7&+>TDF:K8UTFE  '-MC^5 &R[0P+$1`-C#]$5lSR& HnȋV$DiJWUSPq# \s[i2O4.,64!E:GUv'S-O4}h22Ҷŧ/~%inagxw8 ?ڹҾx1Rv6ŋgG'ecH{m*.ϋUWv|rz;?4s$ό,Lqe605tt|*9 T=Lo v13r0ZEG>Ciz0E7GqK ѿ(vϏ @WBNd-7Mz":V-U,ʅv5(069o`gFjݥWFלSe endstream endobj 203 0 obj << /Length 3127 /Filter /FlateDecode >> stream xZm6—2")k"m%7!e˖7x`̐3Pz~<ٳךb!].gQ2Y9K].f_˟Vь, S/K眅gpkh4d2Wg g x,d"MfvjqŒX@}8 F,iD2"X#"-#x”'P,p8(^ 0'Uʑ,Ց Ha>?4]/vF>z=u28\~BׯL^fy6YWBU'uS̚twOG{~_W'MoD9Z hN8K'pS꽏`}s*XLsySsx1jUp=7Yum ͐AV6&[`/Vazwu4ݸ΁=k5nɫ곒A'T@|[?;皥" OI* nt9 =+g5}6)eݬ<85h r<~7nv켲˲F5 l.s+ϔ8oVsrGP W+?t:Q[?hh"LyG6MrO k^ H]y z+^No2˽62ݭ1SjiW— Y\cl*֩JmZEپk& &Xw :$:A}= :F쬗F>efO̤ɣAJb#{M HO 1uw<}9QL"iX@a{d9}Qtq,[[* י v0RhNUq>*aqwN@tg' 5Fo]d}4bK@Q܌@R/:=^ 'yHX7֏O:R<ILKrpFZ6a4º0g"@Hb~޿BWYG6ۢ\&ܬ 8E\U XFB"0&pTVԳ$a@Qfq 8 b@_O»GTgv 4rN> Iԁ Oap0waט}hQx)tv;,ofR r N2їcHtg28 1ȽV4*ҁ6h}k&ۊ҇¶Q-|QυNLY$C2$PM ۔b} oZ^1c5~Y_|2E+aIRCg"× Lfh9'擈8+BS,h > stream xڭZms۸_ɇi&F7L?k&nM`s%}w_$g[!@bϳKGY4쇫7c>3,5]̄IĜ\ͮ_mS+oW?yŌG,R/%KE^\% \jĚ&]\$f~SB]Ůd/lUٮ4M񛲢Fg*j/39lk^4^lS4γm~We٭?/ ,iz-d4?n7X,L0۲ۍ6YSNV`LϽ=bTOZP{Bn414ZyMIbwUlsK){jmkBnqٹf9ŭh-j4e WQk/4EbĔ`ꮨ-s.wyu3th3-,NRqٯE%4Lٝ ~i$׳/gȐ5 ES$fʨdD3(=9⧈J4OkE蠒YX2)̇(XfOp8$-εPWC+8W'xX0e3(ye/YׇRgSAL}=_D} A! J &lQ3Tp,0I:  1 _?zΣ(FpG!*AnrCS[2Ld0ޓϙ1]0kK7LaLxzByqOٺFWl7G! hxSZvQmc+K~# : L*,VYREx X(݂ˮvemM*컢YM c# M.ݑC?1)u9<ғn'ǹW IUS:0f~8\ۦQwh1#>!3c&>Í&W4{ṇ6)/a3H-.M4@F 5-&.hW=p`"D0I S OY,ėʤsƮK*np*>L Įd.) r/?/?_N*92݌>_~rˋoΈou "]\]>B$F0ݘ)c?AlG סr֓Vz@[ē`*9ϧ8a$ie{`EɍZHֻ>=h(z4?)4KH,9qg@eL0=]7WFǪ4 DA N^5v~6}Qg\ÏrkXB _'r'6=4Gp8_1LPq{ d͕<,'@z%Ǯ-Шeu,F3ătv؅䂞H= wLh6vRJ꧋?_.~d6)őBλ wJO-!Fw~IiV3:z#o6 4rh~V<_BP%^/r$_<]]F /SR0- %S9h? e? r4㓍0aGN#7ϗ./mg?р endstream endobj 217 0 obj << /Length 3016 /Filter /FlateDecode >> stream xZ_۸O,W'J9aw;>H@k˻jd' %[ޮ#va"3o gp">3,1!ݭfDLxf"fwvVOw?Ō, /9Z5;8*tg 'ZjGF=Z0x6s1F6:E-]zSyVPF2+P۴7Y)к ,RMKF#U2 3`$ L4C0I™f.>^0 YIW8qkrmӱ}C4g$~\ilq(5Ji@'4C|5J,e0HE2::Hjja4XGKeȘLnzK"m2׺ߍKsmW)Q.-6oGN,.FORw# Ol |̜ ٣=Md쁍1*P-S IwnP{J65i5)Xܤ ʒ6wq vze p<oWMoK=d!lb}S8[»IPœ ؠD{4d(IiDh389y gO!y<rG"-M`|pJŗOZ>p 4W',I KHieaK:=<%J >3@®zZϨ|yGTvruN *R0pcFmr63tR/=Qte[Vu;llov X%E|A]y>)W(vHա ~tC A,hC-8"#6 D: "F(bR2Sb$+*ۺ*Z$f[jU B_t@ , E{r/lOy8&Up0 4@"hZKV.02Q{pwV^"4{Ed 5)HBc/>Uz9-9@hNR!Ļ^F = NiE~?L3}£Cj7'v320uV*0 RCYj5mO}g'l6mf|Eȧ RXnqiqlt6!!"mbE*myFMi 5`T- "q4,xvJ|˥[nXeZ",b6-m-=*:$NL0% P'r7^/LmFS>-3xFFY#Q?8M֋G_8=܍k <8:LNyTa1$YqqW : k8T\M=+ܬ]2|'qJ FOAPHx&"By "\ޟ᱌RKȡK=:v9:?OH Δڧ!W/X8dNd@qlCw Z*:#|N8=hӇa=mcC+W;VK2 6 ^o0Bhi`;a`6EPǏG063i̩2޿s,(b 񠢇f-ՎKtS ADlhmy!F "S^ԢR@2KR̘PrSgCdn表iWǤ8wys2I81"$"]HH0.&LhpZ]" (d t;c)Ir)UT/V8>޴ os[[f NawF|h&7S/$KBݭZAz\=_Veo^W~VAY3>>4|5Vu&ٞqX"@}ruקb4[/SI 1LJ&Xj q-VuV֩"%1 XX^(Y@x>7歡{㯻C~=yq vFoQeqS!]ز& MضKލ`B w'`fbxO7ɖcW-?Sb[-mWGhjmZ]_RwJ N6n6SҊrB9*qdKa-*-p[-UZW[*3Udzw|WCuaTv#e躒Xt8%+P _'bgZg7DNO^ح,=VG 3gA/z`|:A >D`|}GD5vU^I}=Kw]^ǜ|([ cP~on @.MP uK/j6v[K|LOM;7Xee.rw y 䕑9p]֐ ~pٖ ;a.l}R1gh[JN*HL |[drF3Y<2L|sqѻrOg p۷ߢe 8HfN N1R2LZub稺_UB\0 f]oN78zuy`sq Ik_ɁPNx\XMHx&$t26;᱌UȽZO씏> stream xڵZ[o6~ϯ60fxIi>̶36 XLbӶYr%y2{Iɒ";Ns΅*OXI) n׊HZ10Y'vuc1uFILc7_0¥jv&c8z,d!2fBHI7fm3ԤJ6v$'fL9|M=K+wMps܄)Q%'5Mܠ^{bM2wi;cc]q#ٰ^,ӯ:c;UP7t4llN,)$;5 DaޟO!ɉS$5T뢬ǘ a$wfQjq VCռL$rn/_ ?L[QJh)];~)RN0RQC"]o 7Fe_hI UV |J}Pk{ӻkO[o-%ع$ZQejGJ ևOMzPhJT8XxډRI)à\}CZl/cƹwyX"m#ғ Y9<ܖ6YMjحGnבb舆 A?m'9pv0K$-ЈwT'Q㔄#6^"9$ Lr+ľ݂J)Z?=9Q=6o\}BJQ" 曋`~8 MFW˂O#ZAN(~DAd!0J"~H XqeQGL"_dq V@YLpr?]-ij7lRإP$b $Ώnݍ߻k]~O/tcbKB߉{G$G YFrzBlN 1 9ǥ `M+c5$SNCL;Վ!#'lӞ7n5^>IRNٵYϻ# hYUj,9fJlׄR`GY>[sDS xp]BX~|K6̠\b2xj)aJSHt,*Gۉ'znbV;+ ^(XW@=ާf^lf^:Ȁ7>WyCiUN!!p1[>̋b9F  ? @tl3qIjf4ĺF]͙`9A8"!Y*I,H>DÄRHFDP7gGK)s èDt|FLóTraAK[ `/.>9xk :\MAs;!<|_}70]՞lKΕ0vmi#2)]MQזDQx3{8b )G\>L870 W#=DDY^/BF|:,>ޥDWAPG$_eF I vTB3HxD Lש#0lZ)夹Ber n@a _hR ۤ]!ԙ}fjqoF!X{Ei !6&=b4[4x! f"!'u%w}kz8β,6k탿ekKs eo\gVejcA#%jFth[ [t 1>Sߚ-wݘ009yZCĽ/`Nu88ExP  T5]D(;VGUu^jqp~6Owcavh_N14w. @XIOX<鶶]Ѷx/iTwSw.ٮu ߾KdF<#+&;*X?e-Hٚ}A %b$ u N~X]V~_"g @Xx B+8l[0}eQ+4b<  %tƝ-ڷ66.r9ߋڎ I\[,MwyĢ&eś1Fa0oE:FY:ds++BOLxp ӊknh@mPM*h O^c.É̍lp\iOjt#://ʝ̝65u km@.}WD=koFt{I)ϵРԶoD9hIv#1o98h/Tb/T2ľh1R'$c,eQ8p^g5U֙9$(n;3ѣ~Mmړx<3l}jK xz+#`N> ꬦtabnǔn(of6~l3[?6qꔚLrƾExrcOX(H)>ueJ!e/@oӴsQ30Ә_i6f2 2m=lz_[e7V4S`+6؛1m뭗Nc>('/%,(vuۮ壅 ?,>.sfZɑdS# /ErةƤ}儣jOK3/E@fQ2&b]6]ә[WQa(jo.k? endstream endobj 231 0 obj << /Length 3327 /Filter /FlateDecode >> stream xڭZYsF~ׯ`%ќ8Vqcqu*8DB$V hU , ctɫ^ $$qHfÀ0#1bߔ/_*>a46#\ MdP{[saH(oׇz]\Efb,"TnqLnn|A,r+tYV+r%{9+~֣dZn,!pvnIycf}cѐ 6""hWF)ρUK4i rшH&s&@ؼ,&ɊT+>vT@ mR|'\̆qATg6KCԥJ|Ӣl&q:c453y\gyVdyg )̠N|:cSlMDse)%SDoq5E  ?]VgpOU!bk00cE<pW$ ѴJ [RepUQգ[SJ+B%ePQ1qkvq:0< IBEd_2ԛr[5Sqj'njnheM[cHj7|XpUG@1ۛ*]7MmPBÔ121nV)axS!h˛v.M*!}2*r%F$+$$DQNB+m?d@n Swr .j;P: Ywd :a3%CT2WRjO6!_g*5 #c#pq8 4!ք:ӂRE#>¿pX6U$e`W?]{Ƿ/W^/M+f_pdR 5yfR xdj ?*[o/P/xv Iޝ$T W# P-EyuŚM0WA6@lQTU%Am1A̚M5X,V6RxPep=?\HXgn-Ja i$Bڮ ]!Xg"}3=mlws&o;OAd4<6KSȼD\,JJI4)'BNJۺ24hU|6SU+ ~(,dt C6Oh,")=ܡ횃,d6,"FQP06L?`QƏښkZ;5!$FFF$EEȸJ;p1ւH| < "L /3^Vש'~G ؅m| {EwfNg6%Ef{P,mdAq!qH"$c *P UNܧZOQ`:\<7Jij)(u a *-RHm 3D#rz0px*! HsSD2nK}+c 4(8pC3">yJNKmgfsvDr6Zv] ik3aL, $@Qn?Qw LR[ͮ5ΎR7Z3ĴI%fSV`t= A5<49M̜IrޘڑB6~x7O/b ;̂}qrqu :ȂŐP,'N'+ HwzJE"]U'>CPN"H㟴 0jFt{h:G;( -}mgPb<Н*X#P"ܥdql!} elΦDYDJYD n/0t<,);y8=S "vC{5pb-כ:Ϳ9ij)ⱐ<''CB1򋋷W~1RZL!᱐}2xsxE[\]fkcfԯh+~H2~,:6¹,C1A/ZLI#ƒg3u]Lx",;L P;Hiz;.V endstream endobj 240 0 obj << /Length 2542 /Filter /FlateDecode >> stream xYY۸~_K* A(ou9T%)EKZ;n4@fRUf5F_h|ރǽ|}(%ʓQt{Q(X"~}]:}Zz'^ &nfP[<$J8ԴoLj1΄fpl.u>_ +ʒHy>ѨirU73}iQwk+Zѭ6'ݫ-eZ:ZۺnzQf˴+X`.ABZoVӾ[Mk,M޶9 MC[~^Ǣxpiq1ﻁgcSpy^h[UtLK7Ņ_TN@ئmGG^!ą09cW9'"Ǚ Gc8@K/QaVDXw۲xXwhH&m[0lTo'+7/}n1z狀&>ͻ?9JQFKkO}Ms֖͒sT1=L`[T m9G1R\sԫѯ(zZ(]|"d>C?\d+ I5U}ZWTe릮vXk6Ln:`$AH'.)<\DX &GN(8(TȇUf:"e\=Bg;#1"8Ozd+uqiBnu}۔/ބN {x*<'w _+4N唼\C-c fJ 4s4f $?YcZTKVi; ,!3_W9hwg8dLGLpEXE!n = LQm= a .{I Z!qY|G+zZ`f#8ȇ6m"tWp `Pb?e4ޏY/#2.[j>ڤ?@Vx~ʞ+bmd+Dpk"uyY0=Q/0ABtA鸻?h Ar!8pjiaܱ.DTJQ%,v^P#Ոs2ո VfkL9ήXtYl6;3謡T|\Pφ%0/g"._N;:";LEHʈ-HE Y*@pNe7Yi&g_ /s~Ps3 KXi $b?g4G*H`vFҀ\,F U:,  ,! ;CMk-͘-l@UHDQcmBM#f ){*㼳~dx$tcP`:+P yE+Xq\V`xx0Xdk0}ZB˄ VFtrmW+Xç%Zp ."Pqf[C=%Oj~6Ҍ1@Ğ$;Ћ?Ls9uʢT&ǾHE *)bp^e y{2_b3(u*&.Û3Y8!$XFDrĖɭ@*riU.P_0!D1H0nVbyT`0;BA "*{iX/x֛|UӨ}N)W6RJ!YƵ2{ds+]xR&9\5isw28ߤ{9'ҽv]hb[L[ UK qz8qǺf@7tXı[8]Iu0`l;o6 %U6*|W%(l{;Zװ[od" "4\*əSS#86;ic0sš4 6iԇ7(vU~/Y$(~u4}Vis̑)'CeP\yV GPC9wY8RN/Vo[I3F#CA~rG+ڵ,{Ui|O?>BPG{~0p\mޝ= TBCO?>2Ǥr α6I`i_M(G͢ p]Mې endstream endobj 254 0 obj << /Length 2662 /Filter /FlateDecode >> stream xڭZms6_'j&BJmfΥ|'ssCS1EH.RV }0Mُgo.c6IN(\Nx$fD39O~]Χ\R DS F@ͮdQOzW3?d&Ic~e(Lu5"iBx"&3&׋8Q\fF]힭8a4ݦIec!'zXiJ4]np+pݙ0dUz5֩coZnUԥ2{O`t5iDl@alݚ;xw`c;RG*7ʚ3orcrlreL%^5w3D{iq_H΂ n;[趩. sIl$Y.g]f6A^)WEMN){(=9δ1nXTy ^D!Dyb x~Z/TO>Ml8)Aj 2R ĐaUP?q8D͇ {=f^zpqVA'Ȗ&.5 l;]hDYvq}3 #@BNӉ(!˳9|$~KȚ FQN>k`uR2"BM  #D'{$$.b ^'hRAClGI?9E_:|6]j0qٙ};A H$)a?j+5!G?y`D"߆quܞw{YN@$!d/<  dˡz<'bT䑚P 4j7z"u s6c|OUwy'j^B d{IpĽoʣ7WG8Y}(*DD)#LxEg}w p*(07q3"Մ%YmuHIhpź}D9IA!/I^@Ox#Y-X,wj|Uis)AV'uWU_rJ( I_Zld{> stream xڕR=o0+8R@uSڱ!@Ȍm$ Kt'A ǻwbdKknfH XÐ O h @?b csZ+NeW"e$԰ZKKP/N.pI'Z]X;n]C:d(8{9F:.S[\mǍstӦ d[D`œͬ@E0 Ojw.;VbbrSzAO#djJ4^k i{R%"v2 ]<Ȧk PJA~v}\1,!__Zʦ˾b1LT4ǝ;D_M H/CEc endstream endobj 267 0 obj << /Length 2480 /Filter /FlateDecode >> stream xڭY[s6~fJ۴lI7Jl&%RS! 8$UDoN˓?(#ttRôԑќIay!:_wEs::$,U7 y$K$(2.=Sě~]ψv5O2r]nmŪ˻^;%ʹ**:2DK=(YVzM#5~H1pdC1ͱkn0c*et  Vm[iK#nz]y~N۪[,_8 J߈Hpìv7E:-^H{ls :|1-~ :7Qzi>ьFg;gY.v碻5l i11@ª GRigyLw-\Z=YK30i?vLHyX8^NC["~KQ udUdRM]8, y\&`*Nv4Q:4)v#"T'^Guh:(a~ʐf;*Tx JDZ$ve[p2ћV~DD( I ՛nD/)>*՝;n)6?|1!]嚇y]: 1(fLlOu0`Qg؃^/ܵs5'o}&h\Mt咘pi5B>aowx^,eZm糇K7ʹD;m ͞7c847;R^GŞ@bq>v>l8lԡXb E#.Hf8aQJRm)^CZ /KX0W۾OU![lR a%XF$0܇)Nlv]_EdȣMiG(˦uUc-Ӟ0fdwPgO&< )$0 Fij`"t.(hhPi >FQjDߜDf'7QuP+P=)$y CùG<' s`)2!JT樓۶b(*L7nλ-_7+g}^5,'F'kzi}౶@ġ-ɐrU5}`6Ux<U $~+}1&p2ז.RܽV`˧5w 9I0>Ҷbm)w@=)X!٥CJu C]:2pa%RdRFD ļpUm09Tnn:GR >ϝX[Q]Цʤ_{=gn4kt|v|QWwjw8&oO@i y;K|4)ew['r endstream endobj 274 0 obj << /Length 2899 /Filter /FlateDecode >> stream xڭZ]sۺ}Pi&B436ۙdH]JbOSSAC٥zotq\fFs.XV..6CS)狟_GBpfR ͍q/yh$E^8ܨZF,V$`c|J"sBT;:}*hvmmk[ bQHoͦ^@,7|ؕzʊIrDoYqM}yVؚzm?iFJ,;ZI<t7DBw&#ƒ#4ށwNE<Htz&y]𐐡9EJ? _*BЋm @vaCNW6MyLx-lmrdo SBtm6&rҷ +hdǧleSѱ8ë,W7|l _bs@>{2fUegm#T&GiJ9{@hL&cI*sv7uliM ~T Tߗi[5={<+8)ĤiYO8tgFbt4sbM(ٓi~a%@>\y;घnY<>wŶ|Cl>=-쯀G(> )gJBb9M%Cg&D.Ia'c-rHryfCq5BG1׎:: p(`82OHhZV,eh\*bB1Tg{4AXOiuSp:C*hq)lRP+T*ԘߚDu9v;N, ZABO5RTǶDWޖC>ël=gh=ZF&R@{yΈ8:4|1`=?BzJDڪhΉCXo<9ʷfAz'&_ G-6mHU'GTrw2Hɏ$fU10-]kn̘Bˍ[GqxIWyDz౑Vˎx7M+|R%%U=`2: Ҩޣa3,h0a PM?)8RG9 ij vQQGx$VKiEi>)W}D<>)痥K\!ff /_."WFuqWo<B6ʚ,wU/$DPI )\hȕGV1~#Oueq;f^`s)"}!x#:  hQ v9`],ղ(*}c sON MJhy1zh ZGBa#r!C1~Ќ^ݻu l 2l]}Lh@ a#Wo;5vT-FC}*=8 ־/~aOtwv/63i77rC"/_|<@y8!v(j}2"ܑ @k(#UL~ TR") }3(8Ha`| IoC_ [w[+sg=SG)Z%xO<⴦g% ={ԯqh P?6mzueܵD1zPB$!D uDŽ#KܡvsGsc4{\e0S߻[{3[zc/q)Uv~w!%ծ'߷'~yu] c!35an&%&tq%]\; -?Fh( DGնEQ866%Zد7Sv.+qSL? ?R^l$g endstream endobj 163 0 obj << /Type /ObjStm /N 100 /First 876 /Length 1993 /Filter /FlateDecode >> stream xڽZɎ7W8 A@0 Ki 0FjEVI]Ӏ\*H/^,dJZj"k%\5pjX+ڒ9㹥}CRW33H{t5:hxPK0&Ky3 vN\*n 3MЋ%%6`kz+")[(X#_@#芊T,A,<j|&0暧GNSGHup8\1e8Se8q94wuGdkɈRͅdڇdEK&XlH80{z'DwB-b.3$6ݼvv#/^36`v# P|nO@J LC1͈‚U3!M Z.((|,"p dEpNHPHkUf>%S`hPsqㄨkjCܨP8P͝d<[jR!Cj|P0cq"WBc>_XBM>t\eQ/W)+r,)jnM 8iG„0۲E(.Y}J 8EetQs2DhĶF9zzUޏpjqH9TPqR,,C 26R%)qy+@Fu!HV-v9Mۣ1):g{qnd ySM4DCla dOw– Hf`^}Q=:@ 26sp8MmHS {DmCvfY1{"zPQ}7c"دB;-1yQ dRODIHd6n˲˼1]s9͎(q ?XnsU${m(U׭Z@8m0J5zCQN*<&-N.Y an($b,v_sU; gu?SC"(giGƥ =|_.l5h^#KtU _Ў+T8Y=mA;"? Bj endstream endobj 291 0 obj << /Length 2094 /Filter /FlateDecode >> stream xڵZ[w~ׯ@U?瘫/6}L۱뤍s[sK5H 7$H+:e0ٙp6p;I2$eTI$T)I&*4FD\nQ"7M߂sVxTf $gjfCg۲iE"{nVe (t]x\}{w+HSf#)gկl Eg'(l/W?`*QݔH QsR H&4D# /%9giIe6Lp$ `CqǍ4ֻm8%Cj^8qh.ǺZ[ ne]u{nFN܈ ∱6Ƴoh$h )!;ULe م:/zn\K|=.^J.n\򹸼ddm#H(IaZttϦ֫KU57߇vnΊr U{/G@y͎yngA&U4"sN'!Y0eŘDX~"BHN:j`D']PF5lbsfwݛbݘjVM?t&^:J(xHW ( 58(qzHuY5p:7_ !|/VSa6MAV)Sf94RF T3tG#ivMz!àG̛j6fvщ^2qgץ;nw-jğ'Jy/d)C9!s9ٛĠ '1h/ codiN 1r pN0vt ǟbY endstream endobj 299 0 obj << /Length 2302 /Filter /FlateDecode >> stream xڵZ[۸~_/23SfbEZ ],Y*K=y$k}Ȑɣs?B&?C2CYrMDHdrI>C][~'f~`+N I"{-q{Pj )BK?QJӿeZsEM[we3C6~hwؘ2M5n^ 3[?]XCyɤՊŽ*o6rgUgz0~%h$Fdq(#?Ì+}U>DVVѲdQ`!G$`*}Zf,sz%T8}۶|T~P"կC8݇5H{>,r: 2P|>wCAh~G+<s:yuǻ726yRD(698)\g؄%&O5g`k0i^ Պ7T :XI8:q_=Ȃ+;?Q~ɻ,+=a[顮jr)9rǽUt A2>|Or"O(Ks}l}&~"n˽dc*HV~%AbGPF ! gӊ$M){pa&C΀ޝ3<>VZJ`~1BF÷Zpf;?&۶[tGoGϟ*\ЌL/%kCB!:SNBz*s>X0z%<;=hzg4}?iUfhV_O0}9!R48/!^<dbXZHUF$S]}\J {IHi L<3HO7xFCPi\F1)4$,H.!-s 5' Fq̀! B~zw՚ݱFfX:tD+"5qgrGP VQZQhXDB̯GJCmqeX{껄F(t*:]@"2Ո$ŧÃGWCmeW'u}$q H~M3SYQp0ĵ!R9[0 |!l60CW(TPWy~ f`u_ ˽fګ%܎cP z:,,#foA-. &~v\jMA:4F:BCnYkPԫ6:db8BćA0 endstream endobj 313 0 obj << /Length 2141 /Filter /FlateDecode >> stream xڭZs6_˽36Kkqw&~s3Z%铨K.H)V @p]v[94g4껟5 q9Felf4#a=Nrzw?+1JuQ^0•mASI^1 > ׄKMWh6w3Jٗ 8ST>^!('VqJ S*hƉ@1Kd#4&0FU5S*';4x-hdh1׷ZE|q|^nUbw}&*>o<b.mqia`n|>[-ۮW>:rYӆ2r[Q5TWrFGlW *Rj04H \uKDiCbxh " c.*5ɟ*3ޑH_5r] &ZlZ[dqqT֧W J $?;`AŀLYBrѬAG pft-,z4-o>Ox&EOZƔ!V bBd8?Ӎh0G$ӇxXV+?hQG{ϪF b!4psm ؤtr +ǰI)2)-juuWi?ptq;\9&k mtb?>98m ñ/㺢*!cJZh v{z;c[w j3"IMmf;8y *Sn> stream xێ۸}E*kWLEhdQμeBckf%Ww6sHJ͞QH:<7+]<.w7o>lՔ-\Di1#f9zw嗻|P|(@s;9M74AH +mX ELGpw._Nxb/%3Qq3Gij"D[l'f|Ȅ6J&R?U^2Y~)M6Y'E9b}((k?,s%I)M,Wq,OaRoV sFg5ehZԩT/<; Bh28o. [6i9ܕ堊o}wT)8¹/tw?BX =g h ۛv` E/h0ƒ30 cG3;v  <.Ǩ õT \)debQ}zriʘbWK&$*SyI]fkޑݯB3nL 5눋ArVՠrO\[" }%N ]pFXl<:x.h>}v*'_J>b๨(׫t|mƹ=V}eTJ͛1{(ʯb+RӸzh( )K&ķ*â\Ea`Fp^% s?toF◜ycv <L(CbdMZOy䧯b;^b\|2mXn|, KA 3ue5p#;-AEZp!N2Ǽ7HҦoQ۫B9ctTDO)RLN["6ΐ]__L$ Z QSVAOzT5I‚ /r7ԇ2wQMO z^ѷGB! pmv=WҎ&E_G@em+7OnӪ T Og\]D>K˸Ah*8WsyhV<akSS;&p> Ê~%O覿M\UlZ6j~ɶxFacZu菰~V‚?ԡ7DO,gZ@a (TE +9i\Dod_]A$0/!9rɒhאMF1EٵR$)RCK^K$x]t>#3$3+V:1Z_+aiXȯiLDJŖp.fTO>_ ׄJC4dNOᆽhN3A%P_", Q5э_Dr0m endstream endobj 335 0 obj << /Length 2583 /Filter /FlateDecode >> stream xڽZYs~ׯ@vBVY903Q=x+n,"! 1p0ZtA"-<->ѻW*ib4e.ZH+F *8{mo%%_0¥jv'z?.~b0\4WI\_}DQ"L=ڝ L"cbWMCP@LX2wMYz7 S%Wז}A:FFČH3(Cq HIP}ԟnB(&p'2i>==X }\n~'Am9z2c9M?NKzըk*h;1u0VT.a.J'$\G;'9q > zB%ϽTOAFXHI0v~c6&tٜəv!/-rn?ƓK 2&!&9j[U |v;t w"/՞el3O!-Wxkt%\jfʸ@:*-.?>d[J6"Q^dn2o\+ _"ANqsCoi8{lҺu3#*o6E9 i_Yp>k*mZ@lfy&L˩1D>!XK" y&(N;wSdTh<[{W=WU8HYg {ټvO3P. U^0彛Z>ulh4te],,Y7≢֯ xcuֿ̐'&0DgUuMH:!=3H/Ffk]P6nyǨlOYch8" nlĽupۭ PxALS4^Ay؃s+E!a]r<7u޴F[pE=꘤>HOX ~5M^S:lqdPi~ b}" w}^^x0q{K6]sC$UN>O,z:bF qTA]˕'mCc"$":g=P鐱U3&0TxM_#I ۵7)t\M:Eqwd0NuAGM6\ oPЁwo~9 jv(GRuڂ"?$~Kr".;KUw ~HI*}7!  c^Xs(@._yGPI@BYLO: q`D)Wd]W i88+:pλCKDO @zg(fXlY2-8 2 PE{\t)W?ILlSJ=Ex)8}NA)f Mtz{;wDtb tp␕d'~C{0@KAeuf[)T6t(lOP6P3[D&3;ʼyͮrMoҗ4ԗӴ:0ÊfAACKZnkKu? HaOs% Jbj!:`v]x$ִi}T lfu C4w21B@Zppjχ`lY"u}gMPh{tԈ?$?qJE6.rjAO AsÎ1AO V:C[޶sx`B3^[dhFEqP]Y: Ci’<(}XBIt/<.Dӌ( -ߞGlbAX0\D. U_dEv D`]0 UhczK*>t~öD:Th|PT 'wIW]J9K' 8#`Y!B,9X  endstream endobj 347 0 obj << /Length 2051 /Filter /FlateDecode >> stream xڭYێ}߯`D+ۆJ!I $peX2 o\\AezTUWɇ&/D)$7 ӊH&Z1 mf8},sPs LrDs#hOV$+.I%].tYnww'fo)e{l ry}߇K0`W뛫_K2xpM %ܤ'70@F2']!W=  .M1i!HH0"H\^41(l"+||J2wهwGzϯ="m~~ی};jhCTSApMSBtqIk`mJfDy"TȽWk$uK%|=@pum .$f7BWKyhsیByB*BSramAWDaX@& 0Y]Egqy_PEsB٣ і=ҮYVv" )@¸8qN>+>eXܜVAC% hw#* T _1哨&|2.*I8|T|_ө~LD/&ƲK#N'tTd/2EQOG'7Ԁ5WM)wvcB^[اA'0]!v g||=l5Yxe/п z!4aT^9V٫h^b r/!^ӕ w~ ~p~~4:5hCM<#*6\O)m ϳl-f=Q.3m[MG2rz:R6]%N)?c­xsK\旸2vvaqcwthmG ,z [,#뗡M{ɦ`D3y|jχDiY۹hr%`>&;N@Oy bkY:$^T endstream endobj 360 0 obj << /Length 2169 /Filter /FlateDecode >> stream xڵYmBK^ۀrf/mN({pw1s3Se.= Ɣr|[ͻJ2Vd\+)f*S"YիɚMO>r%8+xA`2A ^I)Q IPPM\4(f2 nuWT'D~/,Off)ą$f4} Rdʊ\ϋiНM*Ȯ7"OvQ,0+]:t#r'bu=7*gK]4zW?lZ{MjN/1^%E7Je<eWӊ ~>X,׎GdηP'd`!8jAF,PqvCid9IXQߞ[+߾A4DϫA?$7$yzC3x `+F?7Lt~f;H8 W?閊tˌGZ8X:!i$ Ï#} t5ݎ$ƾ $P$&wYBhcfL%R8hyK.qC ޥ<1 ͳM4x¦GF]k\GgCR)E4>Cm2E4 ,.xƌ9TӵM x ԸW)lTU.'pzdbI/| /)NwߛB}D1DzI`~y#8"η<2Lִ-;57p# ϲHֱ7]=+ `bHl[fҠdnw22{e,S{y|tz [(ݾod$E!USfsKńG#aģq>A5no^8Rߏv(+v>84G@ЙV; ώ{-rB}(*s v^FɁ8~S$ֽl!gA*[?*֛fjkP">sXJW#m -9 r(O F$RLؐѨ-Ԣ9mS~>(\#nJx?= cyNpOcUnN+(+ÙUp.;]I@9mĽ\=6t, |DFeqAS~u/Mˡ/xUxV[$tĸB) 2E o^&gB:#Ʀޕc}tKEPzvRc_%A9ꅠogŸus;1oO/P 6>8xCETfD4y-?W%cpPKK+o1NP=HQBм 9C4PRیt¡V꧱`b_%s{l۴^jc>Àn~@>hQWGkqI%'|q|"$' _,tU t͠+kFx?| lq -:|Rsux̴n6AAy# ;!"=G 1VK3o-QstdɈ?X+(tyy'|?%jCpP yM0{ax˨;]Y zk]7UP]`r.m8B.=vBMݭ@M&|y[ή Dgij?un\(0>NnO맢mY94 _f\+5ۆE1RQL\[*uOqdrb'_g9Kt>tr@!azY U%HzLx3S8"_7B;w_.$uJ>?!W䍮Lҕ"Ɉ52lhw>]`?>GdLuB_j8QYUrJ`nJ` D%́,Ws(ɵyJ~#PʋR!TI %]C?HBv :ݷee",U/8Cc</~b&tAE(z/3wo" endstream endobj 369 0 obj << /Length 3036 /Filter /FlateDecode >> stream xڽks~|(8cM=Vb[u&I-uۓ@đD  ZR}w$H$ݽ}QoQw!"DySG!QE!# _M5}$Y/R4K\tF-|[=pyzc!IJ ~$I_FRhCO"-3ܗmzg䇴U#.N&l&A-"r+Q_1ߵivU<7\Q@8sQni)+;-,qjVe7攒81DAi vN?vsx0HߨIWE֍LegʮVDm̛Z-܂ ~5{jN?C8}s=:Qo6/ 3\51v5 5R^j27s,]Hg̲!|ÈA'((Tڡu],/gf~ˆ$EEppj#3R^=/ϼO#H"Ip]8UӚQMKSDojUjᡮiZ1 AXR,T=,Jcb ,5ixX;Ɔ`zbXöp*q`.N=A5"OC:,-+;4qw+BȠJHHculڴ(>v^ Js$t[meE, Fе9ZZ$+;k ~cnU5CqU&¥aFڜhvFTeVVd }쌦bO9Ai 2 X ʊr[1CpEixDଧT4햀Ң*20X[& `Y=jacr0!>'s$װl@tX| kurB) b3[cHzKŤ9?df3 jּ1I  p0HpQՈ U D6XLխ`$p[p4iΔC `B6wבqJ1v[M1B)_Dی<&_ cchz&a;6ąBKK LrRV IԌW[N[IK33f{;rO|UJ>x"c![E 3  _̛,>}^~Iu+#<»: A9y@H#GC0)Y@,s@8$BQ|d gB؃+!C! BL-> Nתiwhvɐ ? lMƻ,0?aaGcKH@HrǿYڐ5}=q%G$aOP3`84@Wy.C!'G ?[ug9 Ar>rTR _+{Pu0{.{!gidR(#sh~-dA:]Jp$c~FhD.l31, Ayjʴk,DxUJWGbN"K i;h3=wn < I8Fj\I.VOuAzl9R[IrkK<.`kfQy~ !{<C᭑$:sw N/)] l'qל 4-zk@H_5FutU>P68]c+&[yU-1m]eߕﷳKA.շuIp !Sa- B艜ĂFIPBuk5%tk|NZ{Ind6`GFO3ddTF7sdE~K>:hڑdZM58\AGCZc1D{m[~v ݼ9/yu$8|\nLkݝuoKUF ދq<[b >EZpjg̍4ӭcoݢelqb j] .&1-o0}sEL6``.HĄi2\/TܠpU8K‚4\-zr nZWc1dGt_*-h2 5xG0ml@~v ' q f@p'ƶ4 r#nal95 endstream endobj 374 0 obj << /Length 2555 /Filter /FlateDecode >> stream xڭr]_/`8 W%ڥMv8L\3b|P͠O'|71IYr1_Ld8&i"X.~>]]N},'爯jS&LDˆ[ *ӷ?//  )*;3`H3&l'o !gW@2҉t A $z$5㿠~ y,{evBYF,5do;QdZ xNI'} Mݶ[|LX*7ʭά@F[J!K,ztAŚiet%JAwR伕=9 ҬJvpiH:U70neNA,uI%O ȇr87}E#*'<>nA` C5@wGo#tlTUYaӾRul9L2 c|YtFμ9}a537m *∝7q;pjQ7k~:•1[T#B*] N}9!2D>䃿}pmn" RT=[*5(*7m٬7T bFһѩ%bCQsj)}C99a荈=uP ޾ӆxU?@4=S_?|\}iYh3EwZz5z}$NL8ܺ]N4`獲C`z-)OwR 'wRQE/XmO!NomO_p4pL]#;feO[ؔ!.G~VHC,hmX,%ʼnoaچO$Flh7mH3VzۚR{]bv|~*hv׵5X+\Kfî1БTO/PojgAvY[bց`jA`$|*!n9sgx}V]A(5kITT>ޔGj^*{ufshôM1z9{&p$D^y9?0xPn1>>#]{I@A>@2%4fi|ϷJoМȡ,P*A~xRY4LY|~EjiueJ4('ųwUmQE;ԎXe4ʵ1 N'ty6B@ uy\^G'ƅׯQtZgs(C b/Al,W^C"0ߛP4e"N" 4{~ioOs(QCv8f b^PIG_@0d ;FxVi[^m6Tv84%$軄IhLN"S(6M=K}pם 1 endstream endobj 379 0 obj << /Length 2195 /Filter /FlateDecode >> stream xڭZo6_/vf!R[`v[lwqW`V濿iKV@Qp8 l]$Ep{H1mD%" n}[\vN@p`R+f)A+r{+C&YȈ0V۫/` ~ 8SI<B:഼$2RD]zfZ1tIET3`M}N'>=YWsg%uBxEÂNĀDx"ALIgws,mڶPրl-roA۹csh`;; ),\|"ڦ:}JYSm3dyg =Q< !ټlQ4lYEx""e%RqGH4"u{qț+X8 ~HvQX+ٖFiu/l nAUa؛)3!bHvk XY; ::- Lʪx?ݴuj94p&٧,5iTB!BI*"PZ.K}54>h>i٧vUfkg+ jˆƆt+(o,ޗ}W5M,8ʄI% #IppsRs9[ԠI;ȳijymݔL|eI*)}R~F}EHx$dO_x h3D"4tXqɿ8X2%o;D6I7yi,fJzИqnUVIg^tNnWf}GѱtyRkfrMt\i [`+|Hk*֤6EDF>ROTfSMv kg>:0G2/hh;WվnNpt@-pYsG`I"aXRAPO_|wWXXs3Xx!*\ek\86!.q֓FB׉m/=VC ‘3Y!np a9g,C8PRq~먄ip>fFycJe]aNqv/c5i܇̖댴h*AߦyNσ,_Ɛmm{<@6> stream xڵYn7 }cI#@.p[m<8΢ x_{8k^ؖw7f(^%J˅B \4<-P~ ;!Ɠ)!'j9W5ZT2p0Bx8T&1ZAPI}j &6 F+hH ̈́FFJIl%P!ڼa+è1,PN0G\B!eB q0`)܁7civ'L<@}@gށή7^A[>\0 97Bb> +. KFkwVq> bz"3@+ #+4U N`Ԇa<"/ϗW?jyqqq0]],2$Ҙ.b=HX92]Z/&pQ^犼 ' ) F@_ARbBȻd1=X+ndjMZ$lKrذx`IS^i %BLXXo:_J_^5릇,$-$Mk; jM/Pc#hFKL夫tom~κ_$(Y"TKtYP+>6ZA&}XH}X*pvaqF[[m̺d|c^VO'q^T)FbmAb+9Mf/{JQH4\%GdO5ipY*OP< ޔ_>CbQaqz m,zqeU9!w~Hk;2\Dv+r:^EdsXe*.lǡ.9bS&}JKRr.(m:zOwi-#ocwuGFbee(+Q5I҅ 6P'V vaY5>ٵ~Ը-=,mC}V*߇ե_^qu:ai gkj8a@U%g+'mi}F>p%85Ҭ3wa9[lr8LzڸeUZ){+MdF#0yBI%*,>rDŽ*đK>z>3zqXՎ%oP6_d4.V(ׯ>ڇ7s]\\g~ꀃ8}*wAsIQ[?z endstream endobj 388 0 obj << /Length 2198 /Filter /FlateDecode >> stream xڭY[s~ׯ@S=+.NqZd6m; p%!-+$!Z4 rq칟 4xw˓! "DB8BF&y~ݪReӟ/xyx(Ihb#\ f(yD'y!'z&< P$$HHGh껠N3F)5m3dQuu|4qń=牢dii'M֭,rOw[ՋU9Ipzc;nh*;~)o7]?Nh hH;C~8. cMTιoͺ"o2 >oEagmMl s me[Y XB"8ȅ˻~z"$"BOXwwAwA˩Oy] ](7bԤ-= 2 h;tc=T]e$&GV2ؖOO ٬WtDOx:J@e_— sja,Y!M[/jʴ+UQTSC^޹JjG 6kcDK~|e[XPuPJAL6g@tGNV\MVa;uuwIꀩ9tBx+ &L919o z3jU]73bYWOb GbQL\y19xB/\G@%.xv%lҵb&mfx*FQ=AgnAgkPM^]P1w yBcN-mWuZϹ նV6 7Tl)`-ynO!nP=*ـnH4V|= _88Hvx~}Oc;*@|dꔁS֐8H:&8 U.t gAÆ&QRJM%F=ٸq=]qH /\H9,]:f"V2_.u_1sp)>yf@ dU]fYs">9<b- vִ?-G ilmQ]Y]uY,@)ٕEDvsK.u2hwp?ZoqȠVс b9mbZ7L<ō`ᅀ7A񥗰 s q}}apztX{ǐs#{;X]8M6fzNb*RFq^؁ i{_AC%]U S oXP|M2 endstream endobj 404 0 obj << /Length 1669 /Filter /FlateDecode >> stream xڵYr6+d#MmG;$<&Y8鄑`STI*M("EH@B 8pKI"$Z\ETI$$-Vʟś/F?Dz$5n/gxL"b"R".iL.?h0bFG_ꑩ wg{\GIx T"̍уbvRsh-F{L NŸp oѓwKP4v߿?_tOkL5'hֶ:.}C|oo>oЁOkHN*(mK}CkS6X6Iԧ*'Zr#FtGF4RJN1xz~A2Or&-zH3FCĈaı'ϐfw,36[p[@B26! xb{`F PB7I9"_m6U7?\u>GIkߕoͶV(Bb; jHanDCB(5;#)C+P }ˎ/VqV:ư. `4߷EUASk+6&_P1?wyzO u cH=?ioJh'h>FDJ=U bLű5X8p>LhHQ2'Hs I|\ol]Rw`tyC\{;vNǿL$" G1b:6 [6<{n7Ŝ]ƕ]32O8[.(P4GG\-iܷ§v `qW%.¨,ٜٷ4/,: n!q̟VJl^; P5'3%P=+oi}vY*]l1 b]9s9v]A],[/44%jxbeX7a$0i&uPg&T (h\O)^ض*DNE:;`9譽@xDَ;sKO0x`P ܚ:BQvȞe xih>I;ۯ@0O@M642dhz\[qgCBl+cLt˵n :u\EX-  o66.°,Xm_*L,Iמm;vyT?sС> stream xXKoFW9Q$'&L3vTK"L I]MRgr؃V?ՃFFh"N\E(D iňYtMvru%4~.:] *I&Zf$e}[VEr!I"JL8( {ݚQJ{YZ1c.f$Sj+E6^Wgٝ%Cx(h6 B$ۛ!l[QEc"ñmQlw~VLwuӷ6_gDd80LHPܕ ynUu58ц=}-2ADA Y$nTۦ[E#w͊&5},2ӄ'z=>d"Zr0e]~m?o]Q퐲QfRG+1RT {~_Ҕ@gQ2X:/L! ƑOcG"ABZ﫮ƽ2SL gqmS=u*~Z ` Ϡ a 2,'U\]zS%T,RAR KMg;=~v$4޶GO"v MxU hRlTLNwǦ) .ğ [*ς͛6lE;s9:p22Sq_O-!$ A% g>.HJ\AZRbx+%&<s2jXXtڶh C#vo8gV}(Ei1FOqw[Q`Q`\\c]cb<2&Qh+ N53*Ks.r$r| ÚCQ͹^Y&84,0q9w릫0}iZC/zgQ,m 71I۪#@CciJ9L|TKQq30bAA; AEWf $"Э&yOvKUVa;[9~Sh0dDFX$FO~"pBTΕѧ52iS/cߋnqxO@Fdib)hQ<_9E B&/$>ug`I&Vߝw8/=>|RKNbX@!p;w$.Șt=l %#rHɲS S^)۳0i7j @SJ58ysõq7+NCtř O 4&ė jgz/K&_cq:P _:?M T;M<ς_Ñ'GҬaZ ,1*w:7eNu}Q8k6aǻ+6`*- wna|#Ģ_1|n``>Gi-]% JXPޢGP6dluYc/w_M+jwF~=i.⒟KP4d25y !tAF?JBi(jn?)nWC\@=Kh zlۺga+5,3ov cj;<ް!3B&B㏑|=ȹ^u*?Lc?[ڦũeSMvo…EAPEnkb,pvݙ<|(5S =H;M:ew2*k endstream endobj 422 0 obj << /Length 3029 /Filter /FlateDecode >> stream xڕZKsܸWL퉪` YGފWj7 a!nt/Q`0@./oݤr"nT,eLvчo>6ƨE_KN-qӛ]'q"bwڈ<5쮮̣sGY9۲ѿ?ıg.`]u=-( l\߭<6³Dk!ߵ$ m xjaE/u@pt-6pyQxh?5{W^" hLA=t$If<;,q~3)\-`G`m|f:ΣCT\RyuJQwv[ X4×x1"ˋo 4docަAoz  @%H>+iBGI-q*5o+{E u 96W]ϹE.6{`*'-iW08ZY=|?xIr8xjόPqT?0Admk1K[-csk8!#o`ktfFï 8_who(mv03ZN UhCyKý`C`pQKAb0p܋Mh*x*0bATJ& 8:Q\+vdE#Fa^!p%AhlvLL{s>{V&ʒ^xY-xXq88~%|kYEE7la4Nmq2)A #pBXali0L_zuĦSc:8%ѯ(9Bddž϶?fӋ1ibdBXEk3Oynp"֯V9\o9OjylfiB*i\;ܷ4O?A6;9KFH<ňO f^]Q 0[{$x^"5D5D"K X4D8+`[O[aA+Φl562Ba('ha戛e;M(|<`[v 1GfPgcy,*pt $s|.#+.\4-#t IZm&aލFqGAEާ;s_L w5f}Sq!*dck쥞ĤֶW2=#M;ͼDJ^Y5v8_V28.G̏CcE`*@k(d`9g9$PMi>XR9 <-!`G.W:=3WA8>t[26=K>@/,#4+_fk h:>մ"X<`>P ֒GJ [ :nS%HuBۤ$TV)D?$h\ӴJ!=$Z%\|yF>lc !Z6Laf{J&z.@eR'+7t;Bs *e#R%87S2y5mf;cw{F_ ͞VnhtF\56kCӢxeF:G8{dy(^`N=FԷǎ4Ko soѥҷ ;DHD.^]ܭƙYP)5;g뺦"iSO/FSbԿ،.@Ue!Ѯɛ Bzx:H嘏jd|o@廊&n7Ɋ'Ni2_nU%Rw$NF{)C)찋^^17lR G4zZf+2űH QW>t'-C:&v\;#9pmQ˼Ϻ wGjޯ<7O{ͣD25O >|'!zM`%)fYa0ԭWh`O*DrpB.]jem,kjCJcG}enR35r_l]bi{T1&&ѿ6ZJes-Ў6+*p"_OIx QܢLrA^nD4W:\yTa H[.YC(̼K,̔ a; Ij##P8[^ەP2}̛Jj4s =pOiM{3&?y afrrng &(w>r bR />r0)/0"b)\dE`_'"5+ڪ(>5|2PU&>7L yXhMȷޅ#P_KUSE M[Bg`j*_6 yGq_*- Q! z;;Tm*~{XJY08Q09}e77yJ }L /\\ob`oK_o&$ endstream endobj 430 0 obj << /Length 2765 /Filter /FlateDecode >> stream xڭZs6BjF 2\4C;m)STX"e:~"oٛo1 Yr1^d0F0,:-ZϋZg1iLjN%qg*K͢@Ӯu6A1KμF^"%۹YM|x1\5PbR2)JY4Ok<> MUн .PB(r ͅM[ C혱iM >"DA\uB֏*$mCeU`c-1.j.+Zp!nX֜CMۙmA)e,V` FzT[16nP8P;2AB3{l_DAĈieEeѥYsCpvppxX W44sYU/`DnxSSZ5",۪t7&6X:8 Ä)h! TbmEQq@&SbTTgp\s0#2t1WDTx3֞Vn3ǀf9!j:fuU]ޮ'А)?jL) ,RVR4Ht2dq@=6| {,)1H3`|<Ǧ0f&[Cר2drMm  M*$H Q.Nqo[Wi4 nvzuc6"r^6YݚGҦ*ܰFU;  zn/"B=GpuEWHAIhf X0"߃ǐ e}9t((T4xY֐[")'t@"y{܈ {ܙKv -X\)9@'f#il#]'mV& ţ i| 'j:)ADTd@3} P}86!@^ ~ŒFˠٙd|&&3wl zpD G'ʏ.)Bpa)g͗!, ~WPD+!-hQ;!/ R}nDQp6PFCeC; MnrI: rs|"˝ٺ BgyiDd }AZHhl@q DžNr! w"?¦X %@IF Vanog~!i?{p`v[oq:{_x6qN G0pp&._.>_ta(I ލ#=,Mɨ!{No'OR+$TșVҹQA$ADE0Jo2en;mwb qH [(67E+Uq493.X'QBj"'bŠ޷.?^_]40|~38^x<! /A\ p) pCy*ѼMN0HN$tE(#t"m2)ż7eP >ad`/$qjbFP/_LI+!"YgRgw,6Z,+n 8RS_=dHH̦>Vm֣pNU8~pޢ }l'vr\O< / endstream endobj 436 0 obj << /Length 2768 /Filter /FlateDecode >> stream xڽnH_AJ@,؃,L6YdZԐx[UHd/Y@\sq&RA,X`t0N8R"U6XC[O= uHeJ:4͟4]H=(-]06I׿]{7#D6 .gJ߽wRrV:"6jHhM^S\Y-TtRbE5=CM}miݲWℙS9(iEE^\_^Y$,xky*,/=+\˽깕gIf \u8s™[p]W;yZ:"ԽZ7iQ0}²IipX$\/ONjsY^VZj 7 b [ZsoS@3:2 7 v7qe`gv@-C#Ebt'6f =!(add|$2c$Lʼ'h厫NQgo@Z>=z.cƕM8X 5&y_9$b׬$˱^f㚶vm[I F##ZmV i)HW(yB]niEDujSd,)"2}"ؓ UMZ6tu:m5`.79[8?K2&ZsZWːߦQ1Wք/bF&d*hYqpLg wuނQɎ{Ԟ_J*Krkաh W Ap$rTˁlp3yMn/TkS} `j]ڑ/-G^ }Eϲjiq.S"L8aTn7Uv#!͵!$EQ ,V"L'V$#ffnEA$Ox0aߐ] xhdCqw:^rA-0DCzAAA x9yT`UXYѸǜ+5عr>/i,wA6ߠ_8Ók(ѷ/n扜 \t^IdpAjfF~ ЅЊ uNXؔ RV7-ΗLZgtN?9tq"m[@+F7kIiGߪ=BVIb<#O شGݢ0@NN.S}#2)Cc?%eغAW||ǧ8V,P0Uxli"PaQngwP`D04`[\y]1leթOd!ftDT:Rm$Iȹ6kU)O.Ɨ{]CZE5{5 (HCgVIp(%[h0bB vCA@O&Q@QU_h7X*1"7HH6os8ݼ(s޸HVS&cɂa0q%itj?1+Vc\17`WnO'n uqH.۪ D r?Zvi^|*j75_p$6M,X}kb>)q>h|AmeDʳQ:ʳmu"<]>g=mg)ta7B䬪9EdUo>]F.87U-7nzkΦi֌*q@VGlZot;?Sǁ^jMDv Ol=Yb3/"vnƇj秆~'wB(5 RkǻjtnFX4N<ŋw iDC%a_D,m{WcT*y}W}:ӱoA)4uHes/8@^qͱ }VPd|,2F ;i=9RGP'ЭGi's4P:*oڨgpԘf52:ٓ09׻~Tp4((]X=vPݹ扵߉&w&3r3$0&(|v'kipb]8}n/UUn|R D ۸^\ endstream endobj 440 0 obj << /Length 2647 /Filter /FlateDecode >> stream xYY۸~P&/T$ciqb*VnmQ5bϿh9v'6&nQ.nr_n^zE$HnG0QB%7u۔כzk" J&j3B$""DڕNRZwK]/]XG}=d&m\x@#X M'k~?U}v\j}Y*e+0gS|[g,XUhDE B~&MzmWKsI"!rY:+%[+RXk yn3[J_/W^ Q+w7r^c6HD, =0Dck;hNC)7EDݺ8}eᖦkkc@nYVCY~o.G4?2>w+~ źѠ4 ź˷3KIc /=X E2hjתx*תZtx-8/!:? AV6P-jTk yE uԆ6CjZfj,$戭Cf%qh+'YsE8Ηn?FeqWS*kAe!oGeGhT>j!\e\v%+D*2DKTj?jdܬӰ`m jA#4N'Ѣj~(' 57Au&(H@L |K"2`eУsB)؁~n hvFlAl'ˑWqE+s0N!w y`O]],!~DYcK~Iݯ=(EvJUFSn?9XKggּKOk<^ܧc;S^f^n >p1Q;:';.&Z6EJ(iƍ?AJyoRC~d R IZCG ;8.#-,6s,7}RI1wxK™\p kI;jqJ~qNq-)pTBb5=ܼ/E endstream endobj 444 0 obj << /Length 3021 /Filter /FlateDecode >> stream xڕZYs~_KFU/Ij;q-N83 rBrVtđU6>nJ^<\ȋpX]$"K]$Q^$wۋnN]\#}dF:2ͯ4.z'ŵ2kZG횢zR]~ kU6u5u/CTkcn_MѲǢ,ifJrfްaEcqǹVFD6#6rumiդxn~?I ̙}슺cy'R\yn67OWq+yQi9ZTDqqe_s`lf RةnAf׀D:պKWxOFEBT?UOU$@h刊HH[RrʎH;b֑2z[סJR R d=]^nѡR8,qo׸k\qޱv~pk$зt;tITOvƯkΔQ4=_JlO==yMc/Ђ+(m15 WD=† @OS ,Z GkןSLXP?h.5EˎhWeMjA- CV ?@yd.p++WxQZ_i:u4_0cSKw;,#1 1d]MTnc$N4QqAʉC/ĂpG|IJmNg]lS|Ѻ"-I_H$q $Oh 4FyZBF{syc 7_ 2W|) xA@EEG vRA.GF$9-ʫIY}lr Xe,t2 q121B+]o1?fB&}`jh!H&mѶʠ4 ;D)K֖8y[Z7f`upHv|ƎeajY'('"ǁcl4,k$ѾIM7y af~z&:qPpa6n/3{ϳBxjRqA_I!Z;*6yITC=cf+N~鱲C\XFd )8a"QB(NayQ#]o#UصzD"Qޥ=1= PHDt)$Q!1$*(8@,yuG Ku#zf#Ouu-<-9 ~ۗ X,wtՖfʫD|'B17\ʭ3B&R\OXvOX!4 4{n[煡[Ɯ3,cy@˧BFs(2f!wzgolnMvMg<Ni"M [(T1j-2Y)șFsqǢ龨a|21K2f3$yˏI(.@L۫Y:$c|8nL<H;6*#a4u+ ;'1%h.o<d~! mwZx BsPfj)qF϶&tPv(313qخ Yj̓ق-N5-5n%1cPdcEHBH"[9Aamno-c,`+ w5e-eȌ8 ~w0uσ?ɒ"+Fex>Jj|\38`}rαCTpU+'J,n"x % sw8dMm>4 Iظ󃇲^c.1zҠADE5 > stream xڭX[o6~$˫(vC.ŊaڼEش-T`ڟ*^`dunZۢ39b(! |1)"3`/]`+a|Dw~PgS$?emnV"*SwaPsy[?+^nK|B(W`:C#x| ~{e r$9 "yY|o"x8n[7X.pfg R!N#G_[`J^ByePv!|mS6XhGy5{(>bL}*,vJFݪPv0CJbc+:]Ԣ$M(S%P-`~([9-;|P:&H9OM̈́aig_;3,ݴib>CAٗ0]>&L&BTY/v` $tUT[ 8Л Xb&H`AVH ]-2 i=yYqXlRqv/)G̃tR9M(""ɔ=_BP!# >)딀dIaFΗ_M0I.xgr;9t Ν䒧@<_D@%H%}(?B\ _o,o"зx6>1\ۼP4ivήQ #Sw?uH-<bQLh=&z0@!8%>O8 AXN^Ϣ C@u3}Xw\BaFhO0 TC/?1iM2o{}^)2n<: DSH' WcA~ G[W8B_r2m8g^ܟ6=1NAq;5xL WjZǏ ai%'̉L?u=Qn7U֢~ӴP nVJޅ˾<^ھA0D}<_bSrxB P43ǫSD,@X ;fq zLydʃ% <P. endstream endobj 456 0 obj << /Length 377 /Filter /FlateDecode >> stream xڍMO0 9MnC!4*8l;6[n:i UT~umt%2f0 kb @Ȉ[^ڡ*'g>^^|F1}92W n1{jB!ǥXR]W*l lYr)`wJ2%tݝB2N^-QCDi{, \E!T P$_|IxK,`奮 јiL{l @f?$7lwxIeK)xma5C)ݬ:v0;^uVLyWOٱ}y.EX$*  >} endstream endobj 515 0 obj << /Length 1147 /Filter /FlateDecode >> stream x͙n8\i9MVUQiԽ5!( pf1Ip:U k5_l}^O.. Gl ifY^G?7^9PC8ژ"`yWqB/o~-OťqԊJ -?/1p^q|J_X=&U8n2hLбV?MQMKk|.0 ~jڭTؑZ 4|з*^J,mKD/,( PƆAU%tIeDE>w)\nd@!vTT\\T*QH]UwLUBQ@|MgcEVo"ݘDcP[ўUoTu"i5P{Oytrpܗ!FD+Pt16Ykky ( E'MV|fR4] >f "9:!LY»Ys{MV%Sĭ/PIm]0=~$> $4)kAay-UVCN|xx ^uM&GnF$wYDhSxsB* 9LľZ-T^~w ! UqT"uNqnڎbdpml_(0ɶ*Xȓ>*ⲘTJU=Y2&bvҝ3OVM,& 3,Y [ڙ&]gڪN3v{[XߔzJՔVu3$^&a5_ڇ/l;0g9z?ۄb`C&~K0ko(PB'[CqX?lS! c^> stream xڽZMo9W8sX6Xŏ1g0 I]#A2R`H}_(ْbcfTWb.X#hc.2Zr1&w GI|-N 2:UIN,䒰]!r5V(v-AE7):bߘMP7I `J<"$*ncՂq @`YExbc4~Xe3h& ᪐pM0> pD8ѳDx7ZP\! bJ&ֻMs*PzO៨n{1E/3ERANJ ŗpLJsht g- ({s@#] 9\ $fML2E`,P4$;"Us3H l1B&:l8rQ˥- WȮ 2X.|Tx)q&@h6Km P|P6xU&S\d2b3P >@fb\N"@,q7$Mi76X6vcMKYfyjr{^Ͽܛ^IiϺ_`|E/}vyws5?/ \-K}.o]yAxqGEZ4fAT"*jLh$JЃd>d%{623H mnY;44l獌6HwqsGOd4tJ}t<bƋ>OI{=gݫͻMCx @`7`S\~\St?ǖRЮ)E& i?N#Ӿ*'(""b[I%-<u8`>&1d#c2F@/@ Y]*{xs\xvwCn/F&AdrٸJ#cQOgx~f Vp-ުQ,|Av@5G2ǖ&Hi0I숮\0YRo9scA ~N'5.OC7 !^:clLrbuhkQˬ:udeVЭJCd/2XSa5bȉ:rv`˵]݇Sa$O 8^@=ZڣL32'zI^TO s,rbwi*HT!q}zFp-ES_6)ض&uYAws|oj]g|^]z\.>oW__<[^u_Ϗ?'KAsߎ&O,:;X>K|2HqB-5Z즪=}HIaOuZ[kTWWRJ A BLvʂiol@ٙI&2'9.j )Du >Nb1n CET!MP-S6Հȴ4D'2CTfCL4Uh3,Z挊wAEF@#Z ]j'u"#6$;(/[\r' Owbks,klap|e  a `%SٰΜlId'gq@5  F"،S%"pP`&<KL'%{ǖ,/=9E/=1S9M cIKn1?< > endstream endobj 519 0 obj << /Length 165 /Filter /FlateDecode >> stream x31ӳP0P04WеP05U03VH1*26(Bs<͹=\ %E\N @BA,C @"F`F`;x#! `=`pN`#1przrrc endstream endobj 520 0 obj << /Length 163 /Filter /FlateDecode >> stream x31ӳP0P0UеP01V03VH1*26 (Bds<͹=\ %E\N @BA,C AL<@!BL4`u?`?PAhrzrr{` endstream endobj 521 0 obj << /Length 105 /Filter /FlateDecode >> stream x31ӳP0P0SеT0P5RH1*26 (C$s< =̹=}JJS. @\.  Ĺ\=_, endstream endobj 522 0 obj << /Length 147 /Filter /FlateDecode >> stream x51 @ )i»n^d1[ZYZZ(ډ> stream x31ӳP0P0@P!Ő H(`\.'O.pU()*Mw pV]zb<]?`XAՓ+ & endstream endobj 524 0 obj << /Length 185 /Filter /FlateDecode >> stream x31ӳP0P0SеP05Q03VH1*21 (Bds<L̹=\ %E\N @BA,ȀI;0Y&!H? d" H`Dڃzd acP ;00"Ď$>&<&{1 cP&\=!M endstream endobj 525 0 obj << /Length 150 /Filter /FlateDecode >> stream x31ӳP0P0T06P0"sCB. ̡Rɹ\N\@6PKW4K)YKE!P E??0`v!?cA@=717C`?`\v  6 \\\!:? endstream endobj 526 0 obj << /Length 207 /Filter /FlateDecode >> stream xU= @iVbYorR;-Y1#^+w;bBj`u;hƴnuj 11]Ae<P#PC\D.!B RF3 jweng"Ӏ9r0Ox)uȢ"Kh&bvY}W%o k-aI26p endstream endobj 527 0 obj << /Length 245 /Filter /FlateDecode >> stream xڍпJAY8far+RZZ(&&J+®Li쿏O/2x&'QZ yuDu&wW+#Ws+WkAu)RQH'9 62yH8U7SIMv:Qm9;D#'^:1G&s?ɴlq7àZmtj 26曎l endstream endobj 528 0 obj << /Length 211 /Filter /FlateDecode >> stream xm @\|'h$A:uNձCQ!GQ|mg+f?߅a?K!=޴wҖ8Kp/^ endstream endobj 529 0 obj << /Length 243 /Filter /FlateDecode >> stream xUпJ@/Xfa4Y  +P$Vƾ)S,Y'?pcOl-X^ʻKﴨdZrh]SSQ++TlrD_&~nlFd)Ej4zWLnB>c'ŒD[ ȽLwD #TR ;你^ ]`~E>_''J4Gx endstream endobj 530 0 obj << /Length 257 /Filter /FlateDecode >> stream xUϱN02D%?NDBR$2 Ā['xx f UsPYwtgOz'S}]W398"qu͹flMsoOuf/J]\rД>[G8Y򔯈 іH !dSK-D(Jm {.E}X _! g4S?n%FhP-/6Cу_)St\+ioBO|k, endstream endobj 531 0 obj << /Length 262 /Filter /FlateDecode >> stream x]ϱJ@=R,L<}@r'BBBQ.{OWYނER3{+D_>fg?*VLe3 91xxE ѭJs.J?A>W DKuʥҊL`@(#@zjg{N+fW{OOn&QZ3 xŜ)S`U8>> stream xMбj@ `Zlpv!M !dj;fHiț42d+dbG9@5Tp ske 3#{tܱW=[v< Yو n8,6rXI|ljF=M1Ɖw>.x` endstream endobj 533 0 obj << /Length 216 /Filter /FlateDecode >> stream xeαn@ P#$/|Hר):T+i| چJwOl)ݲt- R-bՠ{!=)L߷tH^ ߰ b a^LaS<tP-dw55qXC)4 5XMW*TT΢)J̆tXT)sB;bΡZ}]7OYO >/t{ endstream endobj 534 0 obj << /Length 233 /Filter /FlateDecode >> stream xM1JP?"0;B<6nXW0ZZ(nH3L"F4 $̈&`<@&/iJL}gjhGB _i:o~oo& endstream endobj 535 0 obj << /Length 237 /Filter /FlateDecode >> stream xUбN0P{>Zסh]O61&&KLksMد%6`mC āseR0gx~\4r#ߒo endstream endobj 536 0 obj << /Length 211 /Filter /FlateDecode >> stream xu1N@E?raiG\ WqHV A $RDT@IDZGۣ.SD*)??ݭVtYjS뛓Tkmu!VRmK>]ӽri"F`' (%xnxc1; ]Ṃ1aO XbL8qhGr,2HAGFN"BZyVSQ endstream endobj 537 0 obj << /Length 256 /Filter /FlateDecode >> stream xUοJ@ [#d^@īL!he!>{{ 2E8_ 3͗ǫ*Ik:4_bIqVIZҢ?fcQ_#SXlFSyv3H#n";M, (6234|0$c:iBA y &=faL]K0 Qܺ&3Ҫ3]{ (xV endstream endobj 538 0 obj << /Length 217 /Filter /FlateDecode >> stream x]=N0risHSYZHPQ-|!e(Ì$?kpq~}=gKz~ A۝=N'Ӝ>ߨ?ܰ| ?x`W2NVH$#i}Ii rQmtEY٨ Xt?~NČ I$덂v8Dۑzf endstream endobj 539 0 obj << /Length 260 /Filter /FlateDecode >> stream xMбN@!$2//gEr&ZY+h{RZFN! l#j#U!%ph!rۆ[V_bJ^ߟ8^ ܕRsh$<~Vv&0c :Űݻ'񯃕0^Oz%m #[yL?;;bAnm,qpypmCN_ >9 endstream endobj 540 0 obj << /Length 214 /Filter /FlateDecode >> stream xڍ=n@F?˅i|`wc~+KHT)"*%>Gpb#23z͌}3 l^xdxt{C'5=]> stream xE1 0!y4%mu vtr'utPtm^G:v(I#?xH%F3s1&)^9< 0~clk{`_ X_#Vct@i2eƴ#=Q5Fx3Zg5NIM8(E UO'MGMKMzb]M vQ endstream endobj 542 0 obj << /Length 231 /Filter /FlateDecode >> stream xMαJ@ )#d^@5܁pp` A+ J--N,emea.g'874cZ2tBiYM':_^qc@Fjl[zxf{wEwc#*m<|#$pز Cab9I[P2dˠt^9It.UYu2}XA.)-0*D8|p x=& endstream endobj 543 0 obj << /Length 236 /Filter /FlateDecode >> stream xUαN0`? IeUtTD$Sadh-10}(y"kOvuW|V]=٥,+|ٽЦkYS%˼凚Gj (RT9Bco{cR!Doz> f[1?GI~5M8pCcap@W Vq~ endstream endobj 544 0 obj << /Length 216 /Filter /FlateDecode >> stream xMn0e@ J@tTjJeb@ #]- !{NﮚO_ZbiUIʒj}%jYJN]Cοɗ+{;ŗkxL{ 8D@1078oZo<>BB3 ) ̍;%=ԑ>Ttye#nU4 endstream endobj 545 0 obj << /Length 256 /Filter /FlateDecode >> stream xeϱN0 `W*y#/mp)qHt@ XIߌ8FL9vlAz(b@ w*ݤܦ~$PAJQ/O+`SVl)ZVbmX,'Hñk endstream endobj 546 0 obj << /Length 217 /Filter /FlateDecode >> stream x-1N1E?Ji_s]eYj$@")@=#l"''{ʹRk]M흶~6%amsjMTOw+A^] 0317f{DG? i ?GAx<30I' T\N!q:"kw bfe̵mH9$7;z/}\yU\* endstream endobj 547 0 obj << /Length 234 /Filter /FlateDecode >> stream x]1N@ fnDVP,)XQ%:N%GH"q \mkWӚ+n*~鍚 +Z*Pycc*[x|rwwPsH|P LӘU,f{?d]oqH\ (}uZ oxcn tiN]V'V3Df%,C tiqDk @-/"o endstream endobj 554 0 obj << /Length 100 /Filter /FlateDecode >> stream x3337T0P04P02R05T0TH1*21PAsLr.'~9BIQi*S!B4РX.O e\=3 endstream endobj 558 0 obj << /Length 171 /Filter /FlateDecode >> stream x31ӳP0P0PеP05Q03VH1*26(Bs<M=\ %E\N @BA,N؃$0z8Q'`& >`& `G${ ?Qr `E endstream endobj 559 0 obj << /Length 171 /Filter /FlateDecode >> stream x}1 @ a!s51VBVbnY-DM(HgjxD1alT+ Q9O=|1!w)ڠ) B T{@6\% .:Z@ Z|ae_U/b endstream endobj 560 0 obj << /Length 109 /Filter /FlateDecode >> stream x31ӳP0P0QеT01T5RH1*26 (C$s<͸=̹=}JJS ]  b<]D,r H1n endstream endobj 561 0 obj << /Length 143 /Filter /FlateDecode >> stream x=1 @wn^Xbhi(m,-q#(|cYj9֌YJUT΢yךTN̖Y ƭx܎b*N7qDoRp, endstream endobj 562 0 obj << /Length 99 /Filter /FlateDecode >> stream x31ӳP0P0Ɔ )\\@$lIr p{IO_T.}g E!'E@!ncr h endstream endobj 563 0 obj << /Length 193 /Filter /FlateDecode >> stream xe̽0[x "~- &2`A+Zl+ z1xK7}`|8CQ'p7.h nv7Z͐1nc!孅+ ݗД>!uBG3%9mM5F4V.կf֚RFiHk7e0)#W^a> endstream endobj 564 0 obj << /Length 219 /Filter /FlateDecode >> stream x}н @ H!KyZt;:9::(ZpCLrE>%ɋhH)#tyT?D@(rIfRfFی3'zj[Cp\; f[ k} H{wZI Nd;j<WJX2.&,iT !q^P endstream endobj 565 0 obj << /Length 194 /Filter /FlateDecode >> stream xuб @ H!KyնԩP+AAAQpGNA70i^4(]G 9˅ŊL(9O=l1EN 9A*lTS[lolnګtѩY|guU^emz'g'(Ieގ endstream endobj 566 0 obj << /Length 155 /Filter /FlateDecode >> stream x31ӳP0PaKS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O1TDvBL4 D"?8F0 &> (O'W 1` endstream endobj 567 0 obj << /Length 168 /Filter /FlateDecode >> stream x31ӳP0P0a3S3CB.C I$r9yr+r{E=}JJS. @-\. ?000+ e8Iv!#!d>B2#dn?`c XYc%e0pzrreT endstream endobj 568 0 obj << /Length 262 /Filter /FlateDecode >> stream xuAJ@xAN`bP+.U҅"8EBxxq7@|/Ģ.oa7Jh+(*[$'eY1Ƨ|qqFwΏ)xN)%WX 0 A@'X!TW@ F-@\GaL@+?QowI Sji*ՕTj`t ^3@ #=ңuf'^^ endstream endobj 569 0 obj << /Length 232 /Filter /FlateDecode >> stream xuAJP?dM9/T f!ʅ.]( ]+@"9/Ibd>f_dzt2㘏 S^'Di̮dtGZn8I]ȖT~/ϯWgZm+F EQ$>B>$@Q Y¯"8(: ,:QBM?jlӞokb{tM_+u5 endstream endobj 570 0 obj << /Length 217 /Filter /FlateDecode >> stream xu1N@P#. l5ɺ&RheaB8 G bc WySWk{][!R:]޼~ȡe.{ywxBQ _>*@H9“2؜!b( b> stream x}бn0n|OPBP:!T*CfeJ;fhծGQx (JXbٟtg4{y]SLK^+}&iƵq`Q=P}.rG?_h %htL(>a%ȽwGk]BrQN &Cv&̍A FȗF7"'1u&<کZ܆dT?s1ݭC&Vo} endstream endobj 572 0 obj << /Length 234 /Filter /FlateDecode >> stream x}бJA ,[ G.Νg5pVZZ(ډ;ba;$'XHglEQMaE%=!H4uB@)m=__S~Cۚ;l6-30sofs0GЩz*pR[3fK鯢ق:w#ĝhI;3Y:3]VKq4C;࿟y,mw%wfi_ x x endstream endobj 573 0 obj << /Length 262 /Filter /FlateDecode >> stream xu1N@E"4>Xq ,  * ()@ QaK\#Eg xyxԙ.rS/I9,/ݣkoK~<>H:Bn JQ 'PG>&f_S3 H#>%Xh:Y3ICE2%3ЁUmr88va;7;׫g*zɴ'H 8o3.7F>se弖k" endstream endobj 574 0 obj << /Length 183 /Filter /FlateDecode >> stream x31ӳP0PbSS3CB. I$r9yr+p{E=}JJS ]  b<]{u 1{ H2Y&|$#d>B&vFāj\= m endstream endobj 575 0 obj << /Length 203 /Filter /FlateDecode >> stream x]=@5&plQ+D ,ZZh38 G@avCef^2 &:( =< ANWc{\k7?/#&dH2٭IJGV5jLGhdڷaElTIyO*줪TIUo×T_\+45Ԫa?|p endstream endobj 576 0 obj << /Length 243 /Filter /FlateDecode >> stream xmбN0г2T%R$2 ĀCQYK)S =D6w6 O:}sX]QE5Z%ǕxEH-ihf}M5 =T=c!.bǜU,k/튑u$=?AbΔ20g-h.풓&|cIJӷ܏5k{Z;h> stream xڅ1j@oL#hN,J8rR%)S8$.e(:J›27KN9KE΋_3S>gSN9js5?e>S2 mv!4 > stream xMϱJ1"0>Bt7BBGˣ#\yŒYC_„kJςƵƠoA{]VyfIc/ݝ]Íqh H<YNW͌!#|i~8-v:Q,b#X}n}Hْj`O:Aom"jAk1xp3YvG-m endstream endobj 579 0 obj << /Length 235 /Filter /FlateDecode >> stream xu=N0\X&G\hVE"T+*D49# '@|{SYO7-մ-3.ư١m--Z.sUwE/oXmϩjG;vd)3v(&_*r) ԗ(G^KoNP=:F#Ȑb0caߨ``u`;}!A%gyY$ქ<K~ endstream endobj 580 0 obj << /Length 210 /Filter /FlateDecode >> stream xڅ1N048feH-AK|%G2amCEg[|w[>]r-;mzM[.NGxSӜpϟ_{ ۇv}a@ZJhD2Ȅ$2c4dvJuNͨ (p7Rij/M)vAm+uӿ@"S endstream endobj 581 0 obj << /Length 232 /Filter /FlateDecode >> stream xmαN@ `W"yG8DJS:TD$02ʚY%AC:d) MܜSE-ԬiSTk> stream xU1N1Ei|kBR[ AEQA h.SD;&O͟7+nykzeayH={ɏ#~@~  ,FI# $Hy!p9sP SlQ S]BS3O?9Cz 5I[lIݐ\N+*iD=ktSn'-o endstream endobj 583 0 obj << /Length 190 /Filter /FlateDecode >> stream x};@%$p.$1q ,ZZhQ8%aaD)e3&SKp4C g0GgԂޠ1mx܎ cncv`3TJyĨJ6$(r&;;/Xy9pED]Kv6}zκOY8ˏywf.'+yWana Oq endstream endobj 584 0 obj << /Length 286 /Filter /FlateDecode >> stream xuJ@g"0y!SZYZZ(]-rvABs.ovI{F%t\tZSSc/ش\-iYqaqKM%ױ 9UXl订 d ybR.aa cX"`?5̆o,, ߫0Ȅg_RPg)$.z4/@ciJKJʓnyA u%>@+ +0@:ɝs<#Nz3b:%^txۺ endstream endobj 585 0 obj << /Length 207 /Filter /FlateDecode >> stream x}; @49 SZYZZ(f=Z"xSg7 ?2Aɥ ^H[]McajIj*UTNp>"՘VkQrtaQ d,ɹu|--"1^JBR̉*z&v:N{X5gS\Uo.Nb\ endstream endobj 586 0 obj << /Length 168 /Filter /FlateDecode >> stream xڕʱ 0+[| LBI Njh}x&A Ifz9mPkcaP,IkSע03:;|L EI+Er$ 4./ @'PE \b<<Iya9PpbpO)T< endstream endobj 587 0 obj << /Length 221 /Filter /FlateDecode >> stream x}Ͻ 0C>B Zt vtr'utPtS,GB1EAA1$$wKҬ`[43\%4}r`^jijD1w5ޤ l. 0Nߚ`gTj*YO8:uȱqJꂽSyXND!uаڻ7ԗ:1D&/e6 xE3~0)<|] endstream endobj 588 0 obj << /Length 159 /Filter /FlateDecode >> stream x31ӳP0P0b#S3CB.cS I$r9yr+r{E=}JJS ]  b<]``Q"? ?8 8{0u L?` .WO@.R_^ endstream endobj 589 0 obj << /Length 177 /Filter /FlateDecode >> stream x}ʱ 0J-}{B(u* ftr'utPt+G#t< pwxb1?p dsԍaw\XL@y B-r@) -=/4mVgu𤆚N-.Ѧt+.Jf{m?FN3w!ct1]a`/B' endstream endobj 590 0 obj << /Length 190 /Filter /FlateDecode >> stream xm1 P ,jEB`A'qRGE>֣<;B|?Ns42!Mgohu۶՞Lj-)tC*.G'}4!r8FJp-27sX;+YJ>!PDhxհ#qʩe#\Y.D*~ps endstream endobj 591 0 obj << /Length 217 /Filter /FlateDecode >> stream xe=n0 ^ !Ȕt"YkMG4z0R :]ށ"ħ=,\'7O>i:aAOtL}eÞܖ[V($FFUG"@'C;MBMIU (5[resKMSCЩAgC4jFV"j"kJh+bo endstream endobj 592 0 obj << /Length 247 /Filter /FlateDecode >> stream xuпN0/`<JUeTD$02G#d|P,'?.n\uۚPk^kozETkToj/ ׯԭ 6~9H$؀BzF{baIu=L1;> stream x}= 0 kI NEzbIJS$.(qfc.1xIjsq$Uj"ۯ1)Fy#ҜN&"Yy 2$P5sΚʮTz)z@=qQg5椳[o }6 dcq endstream endobj 594 0 obj << /Length 222 /Filter /FlateDecode >> stream xm=N0_4{2lXҲH@j D (GQr.L(4~sr>p>ܟq q<> stream xuϽ@ ^H.1::htG K6idP@ 5E5^0PጙAKaRݮzNi)أ F8/nO+y\җ1DgiP->Ձan,Oz౽R0ʞ^ endstream endobj 596 0 obj << /Length 187 /Filter /FlateDecode >> stream xe=@!$p? b"VJ--4ں{4 Fiͼ$)%)]"c0;9߰jP(PlL񺢨v+Pt(> stream xM1 @'49(I F0X]09ZRY73las.O>t%ߓ1y8^(NIHdK*]87 vI%w9PpHZ..XM!/3(ѯz?Gh ź1n_*U JU@h ;0" cd:0&I˔dU~ endstream endobj 598 0 obj << /Length 206 /Filter /FlateDecode >> stream xmͱ0# $'" b"NI4)h< бZ{upФMGlL%%c4g WfY endstream endobj 599 0 obj << /Length 232 /Filter /FlateDecode >> stream xMαn02 ݒG^:DSD$:u@LЪ:DGˣ=D1>$N}q2QDcMMtR1% '3̶{FܽBيԂ4570ze(mi_,h[i[s?v%| ϛ'a73UVWhvV۩~rk endstream endobj 603 0 obj << /Length 171 /Filter /FlateDecode >> stream xڭ1 @49t n!he!Vjih!kW/#SL N 4!6a؀Zt;(vfA(:"}BVsJBp܇#Nxr #u_[X s endstream endobj 604 0 obj << /Length 171 /Filter /FlateDecode >> stream xڵ1@5$p,HEVJ--4Z8 G ЙLi q8Ew>$rAnA0JAo nx]A '*U>QPjĴc#1Ș@(rt5tQ=P:R/t endstream endobj 605 0 obj << /Length 233 /Filter /FlateDecode >> stream xڅ1N@ PG)"#ɬ&PFZHPQ ]"qt\c0e~졁?vlON7Q:9 Fb/_8ZI<Nbd1Z^ߟoo.$}ǝ!Amuf> stream x}бJ@9R#d^@ kL!he!V`hyWݵ?qtr; YtblqʧդSuLUG2,RTL:*]-:o~q4bi4,GvHqD CJT![Q|-< endstream endobj 607 0 obj << /Length 222 /Filter /FlateDecode >> stream xmN@D6 )U$\ AE2EHtS .]XY@͓vvfk5zuK6T9^~?=dJxF u }J]iǨ{l3P͔,N.]r |71Ղ]g?.H??ҙUz6 Er_n^] endstream endobj 608 0 obj << /Length 259 /Filter /FlateDecode >> stream xmбN@%L#케rKZL0Xy| _7x-?kr1J_1L/7 M[OoT7(\<Үn~zrwwŞ=?z> stream xeN0 u%p~Hr'*EL &C0G#t)lSۿoUZ"Hgg5{|~x+}+/AwDDBdT9ՙ6U&L6ZbHAW FY1_?(dhB̐2 Cfr\3[5:UFq "⻎ Fx endstream endobj 610 0 obj << /Length 307 /Filter /FlateDecode >> stream xu?N0 ]uG/mQlH017#V(=BKv*$OkO:j#;_96tzq7`}Ga}%qkz{}zwsA-{o9'`fGy )OZX#Ba `o ``C*BbQ>*g1O`ӆa$ "ҧ[bšriΖ,JufR꜊* h2k f{\'iגr>1f2ǢW,2f7_LLn1 endstream endobj 611 0 obj << /Length 207 /Filter /FlateDecode >> stream x}= @i> stream xڕϱ 0sn'0M[[V08G#ttU;QRDtLYL{'L2#_bw ZS)*z@U,Qmє7xw4_dXk$?[@n@ G\C̕u!U837>_0 endstream endobj 613 0 obj << /Length 260 /Filter /FlateDecode >> stream xڅбN0PW"OUj H01 &jWO ?!qw6D|>w-݊nν{ ;yh( m G뭻#o/-{j/JhāhG N?IRtRvRLM?$ͷ6SN$(p>!/)ԼKYXLͅdN;F$t>E2'"Ϙ4)p-|ⷊ endstream endobj 614 0 obj << /Length 162 /Filter /FlateDecode >> stream x3532Q0P0b33CCB.c I$r9yr+[p{E=}JJS|hCX.O {LA08v0& =hAԃ d}F%\=mh endstream endobj 615 0 obj << /Length 216 /Filter /FlateDecode >> stream x}1j0`xKt86pR@3e(Z5c( zҳ!C+eە"yn)pǣ3'[<{I_'Nʗvk_7('B<P; !,G GIJHIPjhŠ]Ɛ\fa:Và'f$ ?U?~ endstream endobj 616 0 obj << /Length 198 /Filter /FlateDecode >> stream xm1j@*x%¥V *v¸JRHkh>AB^fV)~LUx)d*{y-V; ^yײ{e'|^{)5r*8se%5(Et){o `{VfdNjW|n.Գ墺p%Euщ,7>F`1wCG,0w endstream endobj 617 0 obj << /Length 225 /Filter /FlateDecode >> stream xm=N048fH"-D $(PRv.]X#!|ŌgyoOyÞ,n,Ş f2w\2>n.ؒ9#zЈ-1p҅FcFR+M*ȝaZ~)\?(ߴa<-֊w%<2%RTN:ȱP5772L n endstream endobj 618 0 obj << /Length 266 /Filter /FlateDecode >> stream x}бN0 P:TO[+D$G1!j#8vbiSB'쌊S|b- m6*.$t۫3J6}?%wY X7:([x0/Xw?.1}Ď~4;V!0X^G`Yi|3KK[륰ӃrIsz ãFav+_ endstream endobj 619 0 obj << /Length 203 /Filter /FlateDecode >> stream xڅα @ B~\ N܂'+~B1`A%!DyH>-Pd|Mt8E'ZKUyAoJ4!6B0s>a~1[GBTG@ \hYc&W=倢'ci4XQ\K5g)YMbW) k: endstream endobj 620 0 obj << /Length 229 /Filter /FlateDecode >> stream x]1JAE`]О^5XWpA#H ޣQNPLYb" O~IgD^c^up;a|<`o}~|b_S¸} |N$@'" CCwDǦX]X<M"J= ЋVM67xQmKҠk:Άj*9hwcf{ endstream endobj 621 0 obj << /Length 199 /Filter /FlateDecode >> stream xu1@PL &T$&ZY+h ތpJ 8FHO!XccQ>Fp4 1|*]QpCi 훑𷂈Z~]K9@ae%d p-5J҃J!Mq^.q@GaOkn endstream endobj 622 0 obj << /Length 200 /Filter /FlateDecode >> stream xeͱ 0+[|VP Nj}EбCiˡBKd0L)1ok)>XJ쎘h֔Z4s)t9_h4S$oR^2Ӱh!l P؞ZɅ'z3Ē@mP,g({b_%C>G ׇid endstream endobj 623 0 obj << /Length 242 /Filter /FlateDecode >> stream xUϱN0 PW"y'$_@Znt`b@LXnRB>cꌝ "5q8g筭lߦmcj|vJݝm83ͅ}m"(>(g@@ĉiB$}J|D| >&A2 ʕ/*O}b1rt1'IK?tQ fTr%?B-z."&~he )x-;w! endstream endobj 624 0 obj << /Length 261 /Filter /FlateDecode >> stream xUϱN0:D%{H]#" & `ő:t&2fjg8EZ]/WTeEZӪ7;OKZï4X<9=}ޱ<ܐbKϊlr;}mGvð&d$0 nΓ :ye~3Sc?@hD ɑv!F]Ko țo|-xc`3O-'yZ?2lm{ endstream endobj 628 0 obj << /Length 117 /Filter /FlateDecode >> stream x3532Q0P02PеP0P0TH1*22(Cs<̹=\ %E\N \. ц \. 4|H (\=di endstream endobj 629 0 obj << /Length 118 /Filter /FlateDecode >> stream x3532Q0P0VеP06T0TH1*22 (Cds<̹=\ %E\N \. ц \. d {?q=Z@'W /z endstream endobj 630 0 obj << /Length 143 /Filter /FlateDecode >> stream x3532Q0P0P54Q06Q04TH1*24 (s< M=\ %E\N \. ц \. ?aC? ??PՓ+ .q- endstream endobj 631 0 obj << /Length 99 /Filter /FlateDecode >> stream x3532Q0P02F )\\@$2ɹ\N\@.}0PRTʥ(Dry(3773pzrr{ endstream endobj 632 0 obj << /Length 284 /Filter /FlateDecode >> stream xڝ=N0_"4>BMKiiY$R AEJ dD"9BVhqIw^6-o哚 6T+7=[;/먺綡ZTu7LkP@ݞb+"EFL@)mҍyd: ^{3zdb*D`F]fe_6/ֻ2XwClKbWN0;C˧4 Yb 9y1y/wc堙~G}iV^պ 眲RΚ0 ݦE endstream endobj 633 0 obj << /Length 205 /Filter /FlateDecode >> stream x}ϱ 0[|Fq+ vtr'utPty>JЂVCAn C>)NB<pmkq jZZpTvfJp4A!|ܚRieuݪ,;鷸"Umddgf$/qF+Q+]KC8ptj䐆ŀ "#$ʣN[ywa endstream endobj 634 0 obj << /Length 208 /Filter /FlateDecode >> stream xڍб 0Д[ DZ N⤎S ;!b #wBaj/9A]FG oPjT ߂[|>^Wn\1ڹ^Wöe;>w"ȑbne!'pΈlr1wE@vؒi`b5olOkuV lL$=o endstream endobj 635 0 obj << /Length 244 /Filter /FlateDecode >> stream xڭбN0 `:TG_ҖpCL &`J~> Uq,ĉ_]"hKZ_=n ; Z0+5RaK~5C%'>;*\ $U+u+}e'}^ܧ_"dj_V˿*'1S9}q2.Wl9ɒCТfeDE3vgZyٴfȅ endstream endobj 636 0 obj << /Length 200 /Filter /FlateDecode >> stream xڭб 0H-} LSZ N⤎Q;\Oh 䃻 jh1W/qz1pAf@Pki| }Qa|cpÖqA# KN2lɠw:RE99[CO#/Jǎmݐg'7ΐl9gXɣ endstream endobj 637 0 obj << /Length 158 /Filter /FlateDecode >> stream x3532Q0P0bK3CCB.3 I$r9yr+q{E=}JJS|hCX.O@D~DBD00H2? Iy0i߀ZNĥf2TV? r > endstream endobj 638 0 obj << /Length 153 /Filter /FlateDecode >> stream x3532Q0P0b 3CCB. HrW01r{*r;8+. ц \. A=e?0a``'d~"$}6$.0hO$8,'W k[8 endstream endobj 639 0 obj << /Length 241 /Filter /FlateDecode >> stream xڝ1N@4M/R.JHJ t(>BqLM󊝑v*.s|Q傷}-1e&oﴪlؖdL_;2;.Ȭ5&r2x:J缮4U3izdS!a1O*.}'%6+_%tlsp,)9SamG{Kj>t{}Ȫ}M zG endstream endobj 640 0 obj << /Length 115 /Filter /FlateDecode >> stream x3532Q0Pb3CCB.cS I$r9yr+r{E=}JJS|hCX.O7@s ?F?H\=u endstream endobj 641 0 obj << /Length 128 /Filter /FlateDecode >> stream x3532Q0P0b 3CCB. HrW01r{*r;8+. ц \. 000LC"A"YFsĐ@$R@?,Փ+ V~ endstream endobj 642 0 obj << /Length 199 /Filter /FlateDecode >> stream xe1@5&pj,$&ZY+hGqblGN}> stream x10gLxжXX &v08Fg<G <`v2$)"SUr¢8((kR(J:)g%A[=D:4Lhn&~^i/c.ĭn,c endstream endobj 644 0 obj << /Length 197 /Filter /FlateDecode >> stream xڽ @ p؞:jotr'utPtnG#tt(K>ȟK'S7xp> stream xڥϽ 0H>AAA9>ZL@3wS̰o8xp|)30-l1Y2rf3ǝtC)"l˒PK^QtJ*X endstream endobj 646 0 obj << /Length 259 /Filter /FlateDecode >> stream xuJ@'LyMr.'BBNK Eኃ()2dოgw\nZe+tyiZtW?zEN>?^_K^  )t"Y33BsrA㙢ƑJF :jD.$ &0X@ X {i6zCEPL> VlqZ`I'<EHf|F[(<|,ޛ endstream endobj 647 0 obj << /Length 137 /Filter /FlateDecode >> stream x3532Q0P0bK3CCB.3 I$r9yr+q{E=}JJS|hCX.O@DH2` #d?# rzrrӄ endstream endobj 648 0 obj << /Length 225 /Filter /FlateDecode >> stream x}1n0 Ed0EG0/ ԡȔdР7 dPK#O'O *k!XnKVz>uөg^3e݋}N7Oo#XnkR 0,H"`nX,2d;F)ԃ"G ٦)eC$9َ}r9H>Gime2bֿɯꢻNǀf endstream endobj 649 0 obj << /Length 223 /Filter /FlateDecode >> stream xڭ=0 S1T#4T HbF(=BN1#2|QlSL``: Ҍ f}a^cstz=^NЀ`|U|+Q܏JfL5IbG|86*Um%1x(VDFN{ܙmw^{Ǜ)5xu Vϗr endstream endobj 650 0 obj << /Length 208 /Filter /FlateDecode >> stream xڕ;n14s5,r%[D ")S$"r4Gp`(RF}?i7> stream xڥ1N@Y478n- T)UL(ԛ,IdUq n#t-l#k&ĖH endstream endobj 652 0 obj << /Length 225 /Filter /FlateDecode >> stream xu1N0E49BM,)@T@"萒(9K. #3?pW=w<~(ё6[;ϝFOْSxϟ_dw7qB#h%^J"s-,&ï& M ugTi: d)ȧֿHee_3 Y}ETԼ4rs$jYh%t;#k} endstream endobj 653 0 obj << /Length 166 /Filter /FlateDecode >> stream xŎ1 @EH!%q1[ZYPUx!㎝Vd7<[W-SÉ@fޒYFLXr;)svdJ9{ %_@"-0*rࡐZ'pGb4"mz!IoMSK?7W endstream endobj 654 0 obj << /Length 283 /Filter /FlateDecode >> stream x}J@Hfa4]<Vr YlWX `D9-4oɿ3eP=յj隣{^u\\:ݙ{z|bu~*.r冻D6 !#"%I\(3}Cc{mPD߄%:N4@&qTDMK2v ;Q9(nhK Idvd="Т>y &ɹf{[ӎ N4:58x'_'/t endstream endobj 655 0 obj << /Length 178 /Filter /FlateDecode >> stream x= @ L2'pH-,J--ףy2ŒmkO1rX54])/ UԎ URvL,=&dk6>s]PFX`* tB &66aQְsdmN|*38w ]ZZ錀 endstream endobj 656 0 obj << /Length 141 /Filter /FlateDecode >> stream x3532Q0PbS3#CB.c3 I$r9yr+q{E=}JJS ]  b<]0000PX?Po?=``D xr "cn endstream endobj 657 0 obj << /Length 231 /Filter /FlateDecode >> stream xڭοJ@=R#d$G \%'BBCܣ796[D@~9nֺLҮFR\3dQֽTvRT>o_Z_j7zh}+F e>XLΙ垞tQ8rnl`l`Kv❷ xuw0$nz_,ǟM 7ݲ]X`DtqY/W ^ endstream endobj 658 0 obj << /Length 127 /Filter /FlateDecode >> stream x3532Q0P0b33CCB.cK I$r9yr+[r{E=}JJS|hCX.Oc`'\{0 ?0%\=Rm endstream endobj 659 0 obj << /Length 175 /Filter /FlateDecode >> stream x1@O75pD ,ZZh:JD<@J ˆbb%3򎃮i0f3c3n[6DM8eŠ8NDRrpEEVn4TKUT|(UBMҸHȿ(? endstream endobj 660 0 obj << /Length 170 /Filter /FlateDecode >> stream x1 P t*d |BB`A'qRGE> stream xڕ=@ #0e't$$RheaB5pJ 6&Wd^狔cy9ƹjzPRei.;-+RGN R[&U|H-+֤|Z3/PDx"_  {MءlQ5򃠳RkD0qM]Is Fk,Uel m*:9n endstream endobj 662 0 obj << /Length 235 /Filter /FlateDecode >> stream xڵ1N0EEirqd":K" * D ra8 j$\<̟|Ҷ9~JSJ/q]Ngr |y@T2bH!iY)0DI~B& #;NvWV #tb9w?1&쵹+'KUwι9mkQڎHQ*mAi7t-} endstream endobj 663 0 obj << /Length 172 /Filter /FlateDecode >> stream xڽα 0@εIG882:Ht>85g<G5oHYc\lːIN͌Od>"YJq&S"EE\-u׋p*X&.EZ7-}K7-^D_~417yi endstream endobj 664 0 obj << /Length 227 /Filter /FlateDecode >> stream xM=N0j K.Yo?)@[%h(pGH"1&+Ai4絻RF.x/~-O_yUì o[^fv'^TGnBe*TRUCQf4.,B"tF) F#a~̇ Lͥ2~"1e`9Cf1YD5- VM4kcЇA-ʭ endstream endobj 665 0 obj << /Length 177 /Filter /FlateDecode >> stream xڭб 0+ 4%q- ftr'>#t =/u AIn(ƚ!kxB%N_C!Q-$Ft9_Ռ$h+3;tA|y=8ނM?`|ҋ-xI ,vQOzxE:Vv܄#Jsk|jVmx endstream endobj 666 0 obj << /Length 165 /Filter /FlateDecode >> stream xϱ 0]r cptBp" hX ;;rpcHQT2kv%d‚ϧ˞L%SrPE^ />" _*?_^ӗw/ķ=yD-L@@+z]l endstream endobj 667 0 obj << /Length 224 /Filter /FlateDecode >> stream xen1 } p~r$7 1юZ(yc+ d/dj I8&,‚}bTl+bY\2L5N{Gs/Pܠ 1?3W-%_} endstream endobj 668 0 obj << /Length 251 /Filter /FlateDecode >> stream x]1N@б\D&Gع؎HT+  * ()@*>Vu,7O?_f竂RlSqAENObQ4xz|M=%&>ǤgL6aV[2(̭v 9LJt'XX=YjUI+.~ЉgPws+CF`CHeD%;#7R NJCwX}xU~ endstream endobj 677 0 obj << /Length 146 /Filter /FlateDecode >> stream x%1 @E/d y+p2dbBB`6;%XZ<\W%Rp9E^h1ӞjvȜj,0vEzP`K$%b$$T$E d+oѥ׭{/ endstream endobj 678 0 obj << /Length 197 /Filter /FlateDecode >> stream xڍ `4w/Pj)MPԚ>#46_Gth =(TWC# |=yrϭ3;/ft싳^l,N+=u-',]ƠBR"/ w]OJ Hѐ4MJ0?_9.6վэ-iN͋eVL endstream endobj 679 0 obj << /Length 196 /Filter /FlateDecode >> stream xڍ= @ GbVbh%GH"/Vef Ʃj?8$C(gbg(X]r;fwPL@ | ~nF <z/@:Mrp\3]8[FihHOҙAHVxuO endstream endobj 680 0 obj << /Length 197 /Filter /FlateDecode >> stream x=;0DQ m#'1Q.@T@Ip'Xz&p:SN8qjhBq&,d p’r^ %mW|O w=ْ\%NfN‚R8Ԏ;?]Aq !帿;$EC3NMYBvҶ6n* UKe endstream endobj 681 0 obj << /Length 194 /Filter /FlateDecode >> stream xE10AH MR.@T@I< )) bex{6G9avὡũ4!H#8%5))z -lH1r-9 "HE H$;5ƚ2 @Ll)a7lI3G+lJ endstream endobj 682 0 obj << /Length 110 /Filter /FlateDecode >> stream x31ӳP0P0TеP01Q03VH1*22(Bs<L=\ %E\N @BA,BQ? C GG\\\0oy endstream endobj 683 0 obj << /Length 112 /Filter /FlateDecode >> stream x31ӳP0P0VеP0P03VH1*22 (Bds<L=\ %E\N @BA,B@ C \\\HB endstream endobj 684 0 obj << /Length 157 /Filter /FlateDecode >> stream x31ӳP0P0UеP01R03VH1*26 (Bds<͸=\ %E\N @BA,B?Q"A=h`;$@F0A8&TT#`xxrK/ endstream endobj 685 0 obj << /Length 180 /Filter /FlateDecode >> stream x31ӳP0P0UеP01R03VH1*26 (Bds<͸=\ %E\N @BA,A<@ fČ@ a@@D9e :ɑ $aU?pH\\\o endstream endobj 686 0 obj << /Length 179 /Filter /FlateDecode >> stream x31ӳP0P0UеP01R03VH1*26 (Bds<͸=\ %E\N @BA,B@0"00ԃ@D0 @a"W" ",XL/=  p ISp endstream endobj 687 0 obj << /Length 106 /Filter /FlateDecode >> stream x31ӳP0P0UеT01R5RH1*26 (C$s<͸=̹=}JJS ]  b<]L!W51 endstream endobj 688 0 obj << /Length 110 /Filter /FlateDecode >> stream x31ӳP0P0 )\\@> IrW04 s{*r;8+E]zb<]@ 5 \\\deX. endstream endobj 689 0 obj << /Length 142 /Filter /FlateDecode >> stream x31ӳP0P04S54V06R04TH1*24 (s< M=\ %E\N \. ц \. ?aC??@P`4,r endstream endobj 690 0 obj << /Length 96 /Filter /FlateDecode >> stream x31ӳP0P0@P!Ő H(`\.'O.pU()*Mw pV]zb<]\= endstream endobj 691 0 obj << /Length 162 /Filter /FlateDecode >> stream x31ӳP0P0UеP01R03VH1*26 (Bds<͸=\ %E\N @BA,<b@N ?8$D D`#2f2X3Iq,63 *@'W yK/ endstream endobj 692 0 obj << /Length 104 /Filter /FlateDecode >> stream x31ӳP0P0@dbUeh䃹`\.'O.pCC.}0BIQi*SPE!'EA0XA0Փ+ 9-I endstream endobj 693 0 obj << /Length 157 /Filter /FlateDecode >> stream xڅ0EkHO-DD'㤎]O:2bg'g/18ǂS WqY2˝jCHo mvx=7~ &ĈdDVvUr9+G^‹aUnF;~ZQ:?8 endstream endobj 694 0 obj << /Length 111 /Filter /FlateDecode >> stream x31ӳP0P0V04W01Q0PH1*21PA#CLr.'~PKW4K)YwQ6T0tQz ?*1pՓ+ JS endstream endobj 695 0 obj << /Length 102 /Filter /FlateDecode >> stream x31ӳP0PP04W0T02VH1*26PA3Dr.'~BIQi*S!BA,B?ĸ\=E:( endstream endobj 696 0 obj << /Length 118 /Filter /FlateDecode >> stream x31ӳP0P04P0"sSsCB.#39T*9ɓK?\ȌK(ΥPRTʥ`ȥm``P !\`߀ Apzrr]7 endstream endobj 697 0 obj << /Length 172 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O&4Ŀ,`ꀐh2B0 0`@?D0pzrrV endstream endobj 698 0 obj << /Length 254 /Filter /FlateDecode >> stream xڍ1N0E"49BD.!ҲH@Q V9#Xqabf4ҷoy5w|pw Raͫ~yzH==US53UKnC#[J  K(R( 4]7^/_2 (`\ <Lx\XgA7A:HÝְZjIKj)! "chI(QUJ{շ1Ge/]tG߹< endstream endobj 699 0 obj << /Length 272 /Filter /FlateDecode >> stream x}1N0ЉRDr#x.٠,, E"T ()@Сr5|BF*\[L}^u#ԓ+ ^曻GnTyusĪl.ASFU͆cۤ0k?Fvh;!uif B "Qc?1X})bԑvI nG/ADk"vAd0ξ 6ae+ ؐmⱹ\5RgR? J endstream endobj 700 0 obj << /Length 190 /Filter /FlateDecode >> stream x31ӳP0P0bSSsCB.1s<L=\ %E\N \. ц \. P߀ J2~~d|"N`%값 hL F'y,$33oAYՓ+ H06 endstream endobj 701 0 obj << /Length 198 /Filter /FlateDecode >> stream x}ϱ 0 [|TkI Nj}>JcҘ 4蠄|4;.ˇ)Jq)+di#  3 bnA5o3bDTYk[z^DyÒ1 <§QSHhUsjD0N/QG<T]KDbh@C63K[xGj endstream endobj 702 0 obj << /Length 230 /Filter /FlateDecode >> stream xڥбJ@/L i +PysQ%o镶={[r\/䶷\C#;"L E(JdG)23!_#2C[{GE{ʐ :Z2 fFb֘9e)QSFO?V2C鎾?9ru endstream endobj 703 0 obj << /Length 197 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.C I$r9yr+r{E=}JJS. @-\. 700& @Y4$)&?H L2A :0Y&q RbbH.C _@|A! HC, !݈I endstream endobj 704 0 obj << /Length 149 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.C I$r9yr+r{E=}JJS. @-\. $BփI uD6`D2JOĥj2|$(47Ae\=WD endstream endobj 705 0 obj << /Length 141 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O$3``'Lȁ|DAjD  \\\, endstream endobj 706 0 obj << /Length 230 /Filter /FlateDecode >> stream xڕN0/?BՅv`b@Lб $R_.jKŊ-}oﳻͦTИJr&7R+Ly?ocv~K*^d`dPɑaDZN{8;@Ά:0GdzT 3#'d!Q M4 >15Ȏ×t*ć5 endstream endobj 707 0 obj << /Length 114 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.1s<L=\ %E\N \. ц \. p,~BĄ'W NP endstream endobj 708 0 obj << /Length 105 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.c# I$r9yr+q{E=}JJS ]  b<] 0 %\\\6Qg? endstream endobj 709 0 obj << /Length 231 /Filter /FlateDecode >> stream x]ϱn0` n#' v D$:1NClf1t#4Cd?Ka@?>ό/x7e`+/l2 .|w9be;U:.Jp΂Zг j@AR&B n ~x)[yF^}lEƪ# `"P0~? endstream endobj 710 0 obj << /Length 126 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O``'!P:'`b\=jo endstream endobj 711 0 obj << /Length 201 /Filter /FlateDecode >> stream xڭ1 @4 \kP1),J--!9D,,T]S[̃3nQ*9zK5.sWj9!!qSdaV o,cP$nPPBz@Q(>Zll/5.K=&Mإ(o9)[-_m0v`fs8 endstream endobj 712 0 obj << /Length 199 /Filter /FlateDecode >> stream xe1 0-wӖZtP*AAAQPPRo7iqpT I( 8{~B&6}\9Ol[L,7@g@GEq;>:@8w^@8@X&as!eV^zH4 6Q25> stream x͐=@XL #V &naRK (҂.C l}/N竌BJh&)^PF ] 厹Fq(Eu1 }C$QtQZۂgmJ9Հe 7Fд?oaF k ,|_F&h endstream endobj 714 0 obj << /Length 182 /Filter /FlateDecode >> stream xڭϱ 0H^{ӐZZ+AAA(}$]8N KM9&xg,\Od+ f.S0~ ,Ђ)qo19/"jB.P;UuDF 'aybhF4j-iMːO*"`a oƅt endstream endobj 715 0 obj << /Length 218 /Filter /FlateDecode >> stream xڝн 1 Y|;? N⤎磝"b/Y>Jڤu)&cjiɈZ=qYh>&xޡG*hɘR. eى/".Ҭt ҪwVhO/o2C xBbMn7ݥ| "Ԁ3ï>$$J endstream endobj 716 0 obj << /Length 250 /Filter /FlateDecode >> stream xu1N@E'rai=1IL,  DѶ. (ig?lncQiں'Tl=yE&lk\FZ,6KNZa| 9|t5iûH Jbz<rd'0 (9qp&8 %?cFi=H^Q #t)g/pxLkDυ3zA endstream endobj 717 0 obj << /Length 127 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.1s<L=\ %E\N \. ц \. D?`OY$$ ;R?$XՓ+ VX endstream endobj 718 0 obj << /Length 197 /Filter /FlateDecode >> stream x} @\|jU$A:uNձCQWQ /mU%v?,Ŝlriz mgCsb ۓ"[YyAm }$E'}2FZ_V7W?Wei f )XP>V*5yMg9V/zVJAf9'*LCx8 endstream endobj 719 0 obj << /Length 210 /Filter /FlateDecode >> stream xڍϱj@_pK@{98Sj@-48 -rpnA0f#VX܏]і1ey8%dIL2~Ar<"9hM锳AitJweB# LX6vs`RaF$i4 ;QWytExݭ'{gk~϶,O*$=t %~ endstream endobj 720 0 obj << /Length 242 /Filter /FlateDecode >> stream xmбn@ P#$/ "L :vhծgO@@$2Dv."PtO h"+4}ih//hMм.tI?hfs ,hRtA אLZ5;: Gk?ޱR/R7ux;xl;3{gߺjmkxN|סuޔΚv:T-tjO;Q d,ŲZ8ݎ[+R endstream endobj 721 0 obj << /Length 201 /Filter /FlateDecode >> stream xڵͽ 0+ zO`ZE`A'qRGE6Go t(;T%w.z!h>22J;@j)bAjPjJ-SYmEc-wy 7R5-!l·<дM nܝޣtVWYw8C:rb endstream endobj 722 0 obj << /Length 186 /Filter /FlateDecode >> stream xڭ1 @ aM!L!he!Vji(Xͣ)ykk|x$ 0 S9|W> stream xu=N@ _b%79 H" * D[n&"ymafYy.\O:/wa\gVVOK{Ǵý~~|m]=(k}fϋ kEm&fhF hrá +'2ʉ3q4|PY؁0e齳s5\@e'XreSU4Q~MQd endstream endobj 724 0 obj << /Length 206 /Filter /FlateDecode >> stream xڥϽ 0+->Z+S*AAAѹ}>b$*.bBz:ԥVDJQܣmT;fiTTf3:; :Yc6\;lhkb⍹/N-Z6*p|ZX?4>usn tn N2\KKv endstream endobj 725 0 obj << /Length 205 /Filter /FlateDecode >> stream xڍn1 ]1%o )$n@S ZYG!i _ϲ=gzp;:٨T6{hh.DmyءQvF0`80cf̱b9)zA}T$"'S|_Q((M I +TPGey?4dѸYz1_ S endstream endobj 726 0 obj << /Length 220 /Filter /FlateDecode >> stream xڝ; @ )isJE"b=A aS~] endstream endobj 727 0 obj << /Length 216 /Filter /FlateDecode >> stream xu1N0E*ir ,-D $(VT@Iv(>–)VAaYO??V=ϝz`U6]oX?ݕvⷺ}qE XXͨ̎p[P0LhB M 4ESDiDf( DETHIc %)>/~Œ\r/_})oG endstream endobj 728 0 obj << /Length 164 /Filter /FlateDecode >> stream x31ӳP0P0bSsCB.c3 I$r9yr+q{E=}JJS ]  b<]300? C=`cf ?F%5Ƅ@.N%\=CSt endstream endobj 729 0 obj << /Length 275 /Filter /FlateDecode >> stream xڅ=N@ M_(E"T+*AD \%7!H9Ec{BHLid=RI'tT%=VjIM}h=<|ŕԱh UXiSQy :!1{.g t<A9Nt¿ɽ`n [Y'(3@ ~sPoi5E,b6y0ɬ1$V ٺ[Lz #h&;ij$^MR} ^x?m endstream endobj 730 0 obj << /Length 165 /Filter /FlateDecode >> stream xɱ @ : Y k 7:9utPt>ZpcҘ(@>?1t>C1I0IF*x܂ڡA ʮv@F G` t>'C/fH= b賚'b6l Q"Di endstream endobj 731 0 obj << /Length 137 /Filter /FlateDecode >> stream x31ӳP0P0bCSsCB.cc I$r9yr+s{E=}JJS ]  b<](B` D00 aDHpzrrȧYA endstream endobj 732 0 obj << /Length 217 /Filter /FlateDecode >> stream xڭνn0pH' Q" vP+ċekdUGk?>48^iƏ%Ii?1B4,Ⱦr'd Wwc'/kL8TEk%t:u=|?Q ;DN d~U7 S[v0ؼ?bjv? k1N\*7V*=4#S endstream endobj 733 0 obj << /Length 123 /Filter /FlateDecode >> stream x31ӳP0P0b#S3CB.c3 I$r9yr+q{E=}JJS ]  b<]``? ×0? 'W g endstream endobj 734 0 obj << /Length 161 /Filter /FlateDecode >> stream x31ӳP0C CB.sD"9ɓK?\ĜK(ʥPRTʥ`ȥm`C}?  Yo`*?!*9=g!@d\= endstream endobj 735 0 obj << /Length 159 /Filter /FlateDecode >> stream x1 @бa1[ZYZZ(ZoG 2΢]> stream xڍ1@E #0eV$&ZY+h+{4(- 㲘ڼOϛ$ͦ񄇚1'O6MvV6&U~{I7 ֤rkT dR" "/x"o"x Aā, Ң~~5oU9qNȩ9IR 3,hK` endstream endobj 737 0 obj << /Length 221 /Filter /FlateDecode >> stream xڭбn0bt @Y"QPNt@hycs U.ɺϿm˧ > stream xڵ1 A i832VºSZYZZ(ZXYz#llXZO7荆d/9C;GtVibs0W,lQ9O=l1!洖}N)!0Z2-ygg"(.0P5tŷAUɲ+Y0\%-nYW endstream endobj 739 0 obj << /Length 218 /Filter /FlateDecode >> stream xM1J`b`w.~7hXW0VbZ * vnUra!,ǔK-tgQ ->Gy劲p3%WtpK-Ϗ kxzX 33䎅rCF40@:b #LɂY.dČ 曶AȺ lB{,Zxώ`1K{+orSN~o' endstream endobj 740 0 obj << /Length 160 /Filter /FlateDecode >> stream x31ӳP0P0R5T01P05PH1*26 \.'O.pcs.}0BIQi*Sm` $?` #$`'0   Sd.WO@.] endstream endobj 741 0 obj << /Length 159 /Filter /FlateDecode >> stream x31ӳP0P0R5T01U0TH1*21 (@es<L=\ %E\N \. ц \. `,dF }H<00g?`G"?\=kqt endstream endobj 742 0 obj << /Length 174 /Filter /FlateDecode >> stream x31ӳP0P0bScKCB.1s<L=\ %E\N \. ц \. 7P& eJ``$? @cg@%4*PFF2?F2~~F2?N7 H{ r V endstream endobj 743 0 obj << /Length 195 /Filter /FlateDecode >> stream xuν @ > stream xmν 0C(vAAAѵͣ7Q|AwݤGr6&آt&=>'|z zzBQvi z0b zoU YUX)է-ؽFF'{DžyVJtlH!r&u]Ŋ;7RCSQ񋦠iwH>ʳh endstream endobj 745 0 obj << /Length 237 /Filter /FlateDecode >> stream xeαN02D%{pҊ.TD$: &73Ea+RősƂ)eTQS9mr|IJҌ.kk* C秗{˫3Q&l [f۲cvӨh+켍 R PPÛLm55wۃQ?ڋ_"|v։&Ԋ*Z IM ]4O`9kb{0D>7k endstream endobj 746 0 obj << /Length 218 /Filter /FlateDecode >> stream xڥ1n@E?@#\ ^ c)ʅ*q"QQ8%Ŋ2[$r~y.9R3.#OcE_/T_ܙt_?g~)O)'o6`Pv*;k . , UPC< èzDNe{Υ]ɷ~+| 2%E_Iqhҁ x endstream endobj 747 0 obj << /Length 143 /Filter /FlateDecode >> stream x31ӳP0PbSsCB.crAɹ\N\ \@Q.}O_T.}gC.}hCX.O@l``z 灸C??P szrrRZ endstream endobj 748 0 obj << /Length 232 /Filter /FlateDecode >> stream xmN0Kxe' 0Y*E"L vd(~wH`O,+¯.wZt7j='(IB??v7ϭo^x# `0#,yB=:F0A.O= {řs2t 9FtJ:ZTTwHsͪTU!,)b")3t#}wo endstream endobj 749 0 obj << /Length 258 /Filter /FlateDecode >> stream xm1N0E'ris v7,eHV ()@&9#L<| Q`ɯ9JrZ\\Q<^ W7(s W+:C-GnB"LdT@.ëGHF316 6P9n\ Pbf4RuYHq_#B}!\0gܜ!TFIAC$yDE}H#A _|o_ endstream endobj 755 0 obj << /Length 137 /Filter /FlateDecode >> stream x%; 1F;]]hL!he!Vjih7eIY@5`NKnn;[.>Yʬz8nQuĥ>W#D*L"QCĶ5e" ьwO)B endstream endobj 756 0 obj << /Length 132 /Filter /FlateDecode >> stream x313T0P0S01T0P05TH1*26 (Bes< =\ %E\N @QhX.O 27??~0?P`G( endstream endobj 757 0 obj << /Length 192 /Filter /FlateDecode >> stream xڅ1PDPl Ċ1D+ cmq@IA;WL0 v xlagnEt4'g'Ty!n{> stream xڅO; Pl {I*L!he!Vj)h-G,-$q̃T;LNuihuɗV'/2O4Ĭxq7 $$M | ,G\W{F9^ـ"J[|rY"ֱ4nT?pGrjݬc_e*[M* endstream endobj 759 0 obj << /Length 167 /Filter /FlateDecode >> stream x313T0P0U0Q0T01SH1*26(%s<=\ %E\N \. ц \. L@$AD=$? ?@P&VV̌...SG;&.WO@.n= endstream endobj 760 0 obj << /Length 162 /Filter /FlateDecode >> stream x] 0->KNZ N⤎>cbMN8>] y GGbO%T2[0YFK&pOdLSAZZFHW 2"L}Tߩoﻭ "Іֺ? endstream endobj 761 0 obj << /Length 114 /Filter /FlateDecode >> stream x313T0P04W5W01T0PH1*22(Bs<=\ %E\N \. ц \. a`?r 5ez endstream endobj 762 0 obj << /Length 116 /Filter /FlateDecode >> stream x313T0P0V5W02W0PH1*22 (Bds<=\ %E\N \. ц \. c``pzrrlI endstream endobj 763 0 obj << /Length 152 /Filter /FlateDecode >> stream x313T0P0U5W0T0PH1*26 (Bds<=\ %E\N \. ц \.  @N5 D؁{! ?8$ &> F0Tta*`gr W: endstream endobj 764 0 obj << /Length 175 /Filter /FlateDecode >> stream xڵ 0DQXK'2҆  * D h%##6HWYM0p sf؜Tz2{XKf1)Kd*rdGR/RA-%a|ݠЂV$QoeUG+O;a endstream endobj 765 0 obj << /Length 171 /Filter /FlateDecode >> stream xڵ 0EQ  miCp  (0 i~ϧ{~37 <& ~9JϓJu }s7&xܟnKœ(4^Jq^.JNQr?)F#PQ1H)3R;;J~.؆xC?ZOYb endstream endobj 766 0 obj << /Length 104 /Filter /FlateDecode >> stream x313T0P0UеP0T5RH1*26 (A$s<≠=}JJS ]  b<]'W * endstream endobj 767 0 obj << /Length 113 /Filter /FlateDecode >> stream x313T0P04F F )\\@ IrW04 s{*r;8+E]zb<] P\=AQ@ endstream endobj 768 0 obj << /Length 148 /Filter /FlateDecode >> stream x313T0P04U02R06P05TH1*24(YBs< M=\ %E\N \. ц \. ? 0`77g.`r j'. endstream endobj 769 0 obj << /Length 171 /Filter /FlateDecode >> stream x313T0P0S0W0P01VH1*26(%s< =\ %E\N @QhX.OXǏ?1 ɁԀԂ2} pzrrxS endstream endobj 770 0 obj << /Length 116 /Filter /FlateDecode >> stream x313T0P0V0S01T01QH1*26E-ɹ\N\ \@Q.}O_T.}gC.}hCX.O A-4v@ ù\=emH endstream endobj 771 0 obj << /Length 136 /Filter /FlateDecode >> stream x313T0P04U54R0 R M F0\.'O.pC.}BIQi*S!BA,???PP'W ,5 endstream endobj 772 0 obj << /Length 99 /Filter /FlateDecode >> stream x313T0P04F )\\@$lIr p{IO_T.}g E!'EA0XAՓ+ ; endstream endobj 773 0 obj << /Length 157 /Filter /FlateDecode >> stream x313T0P0U5W0T0PH1*26 (Bds<=\ %E\N \. ц \. @#HD؁:Q'@&> f0d82>3 df Dpzrr@: endstream endobj 774 0 obj << /Length 107 /Filter /FlateDecode >> stream x313T0P04F f )\\@ IrW04 s{*r;8+E]zb<]:\={-= endstream endobj 775 0 obj << /Length 155 /Filter /FlateDecode >> stream x313T0P04U54R06P06SH1*24 (Xs< M=\ %E\N \. ц \. A# ?0` @.WO@.8 endstream endobj 776 0 obj << /Length 110 /Filter /FlateDecode >> stream x313T0P0V04S01T06QH1*26 (Z@ds<͹=\ %E\N \. ц \.  \\\A endstream endobj 777 0 obj << /Length 145 /Filter /FlateDecode >> stream x313T0P04Q0P0T05WH1* !P"ɥr{Ź=}JJS ]  b<],j0a||=CC apzrr/ endstream endobj 778 0 obj << /Length 103 /Filter /FlateDecode >> stream x313T0P0W04S06W02TH1*2 (B$s<,=L=}JJS ]  b<]0 szrr$~ endstream endobj 779 0 obj << /Length 117 /Filter /FlateDecode >> stream x313T0PT02W06U05RH1*22 ()Lr.'~8PKLz*r;8+r(D*ry(01l;cNJ l r \+ endstream endobj 780 0 obj << /Length 168 /Filter /FlateDecode >> stream x313T0P0bCSCCB.cs I$r9yr+s{E=}JJS|hCX.Ov;: PNF01`u@Qf f2J~ 񀿁;'W Ǟs endstream endobj 781 0 obj << /Length 251 /Filter /FlateDecode >> stream xڅJA'\!Ls ޱƅ+,J--;y4B[O"hWf,4s n,͡c%:IRc{l3yz|c;9?Tj fDTP&E{h+9G2D~>/BGE$E7~ }KvmV:$,H@%j}W}azH O#bA=b2~|0 endstream endobj 782 0 obj << /Length 239 /Filter /FlateDecode >> stream xڍ1N0Dg"o|$Q6ZZHPQ *!p!eU8i=opZ-uC玝|H?Я\~4wJ3޻MÍ?ε/2"P<> ufA@5ã`cO4s1d1gʮɧ:eP~Kٜ-˺QvOh9X܅H$% RM Zlmb dr)}A!> stream xuνJ@YRoyMry),J--$ba#*Āb8Gi+9/w]iF ftQ5 sʟjN\`v 1f!]b:ڣ5a&HzЃZ](&Dv) ZEֵ^mVvjRPkY-B4x1+ɛ>[OB:@|ӃFA:nKe4bڈq4Kmۘx~⃌ endstream endobj 784 0 obj << /Length 184 /Filter /FlateDecode >> stream xm=` .߁1D'㤎]ċ8p n #~$(}L> stream x}0K:#pO`i1NI4 Kd0FMj\ijx@½%\PPGL2P[2;|=7P~K<Ls 9y|9#l K#vӜ_[ZCN _CF,a8[NXTQ endstream endobj 786 0 obj << /Length 218 /Filter /FlateDecode >> stream xڝ1N@4QY AT (Ar 3AzWJ_kN|y9H/vI'Zun8-)\ؙBwoVWg)6r}Gݚ3J~ ZTMa.)- o̤/`tR27V֯ifhh`+-RN]dvg9 endstream endobj 787 0 obj << /Length 183 /Filter /FlateDecode >> stream x313T0P0bCSCCB.c I$r9yr+[p{E=}JJS|hCX.OD|?b0 AD}&> f0H0b!On%rv?s?>  `szrrǁG endstream endobj 788 0 obj << /Length 147 /Filter /FlateDecode >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \.    `|$lthvb)،6 Q .WO@.̌r endstream endobj 789 0 obj << /Length 145 /Filter /FlateDecode >> stream x313T0P0bCSCCB.c I$r9yr+[p{E=}JJS|hCX.OH" $`@CLmQD !( ,x endstream endobj 790 0 obj << /Length 227 /Filter /FlateDecode >> stream xڍ=N@\4PY AT(PR$ގk 7eUI"Q|{;5袥aC]8> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \. ?c4 N%'W  endstream endobj 792 0 obj << /Length 108 /Filter /FlateDecode >> stream x313T0P0bc SCCB.crAɹ\N\ \@Q.}O_T.}g E!P E >Փ+ HX~ endstream endobj 793 0 obj << /Length 156 /Filter /FlateDecode >> stream x313T0P0U5T0҆ )\\&@A "ɥ`l¥U()*Mw pV0wQ6T0tQ``HX`'$@DD?`AH?` @OjhPՓ+ UX endstream endobj 794 0 obj << /Length 218 /Filter /FlateDecode >> stream xE=n@E.,MvNm M,#EPR%)SB9QPr.]lȢOLt&c&FRf1K~|U.k9s endstream endobj 795 0 obj << /Length 123 /Filter /FlateDecode >> stream x313T0P0bCSCCB.cs I$r9yr+s{E=}JJS|hCX.OLŘN|? ?*f endstream endobj 796 0 obj << /Length 177 /Filter /FlateDecode >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \.  B`W${1y 01h͇q|Fa  l?`!'W , endstream endobj 797 0 obj << /Length 194 /Filter /FlateDecode >> stream xU-@%&c 迨 P$u[GEev K1h8&nL؃-;CFXA_>pi ?!&+R"c(ɉ(N+ƵGSroW\"Ϡ+tIߣmśh5| dXB]/qs| endstream endobj 798 0 obj << /Length 170 /Filter /FlateDecode >> stream xŐ1 @ERxt)R-n!he!VB9EqW7seϨxAƘxң3U5ݮr 쀾"h `,T'uID x/H 9 Zpqol endstream endobj 799 0 obj << /Length 174 /Filter /FlateDecode >> stream x313T0P0bSCCB.cs I$r9yr+s{E=}JJS|hCX.O0"370`H؃@`?#^^Q`Cƃ-Y  f $700 F"b\\\wN endstream endobj 800 0 obj << /Length 209 /Filter /FlateDecode >> stream x1n0/ʀ! &HYj کC @9j1CNjKޠ{iˊs.y^,V\.x_ЉۜWH[KEԯ|9_do\g ƃHLd pLi'Ai ?NI i&tZ0^gȅX{cY701<5  endstream endobj 801 0 obj << /Length 197 /Filter /FlateDecode >> stream xڕС0jrf{::"#a e0XvtmCOh)T^ aLiOvG ֤FscT,r0ʖSiNfEN`Y9Q3pqNN3O0n ZJ4&}5ty+A -ؼ+ԀW2>z endstream endobj 802 0 obj << /Length 236 /Filter /FlateDecode >> stream xu1N@ E"a|$H" * DH$*\!G2HQwmT 娔DJsՠg?x#Um<>r\Iq+wn˜24wC0MLNLtA 9a=tC68yF̛aO2/a<&E>oxv endstream endobj 803 0 obj << /Length 124 /Filter /FlateDecode >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \. @†H0 z(QՓ+ +T endstream endobj 804 0 obj << /Length 167 /Filter /FlateDecode >> stream x1@G(LtYY +D ,ZZhq@IaGhf'_Ϭgɂ#}SqblF.b27+e=Z3bÏB&.ْ`9:Rs)U*H]J^w¤%HRQC/~*hGo8 endstream endobj 805 0 obj << /Length 189 /Filter /FlateDecode >> stream xe;@!$p,1q ,ZZh.F5\5o2s? q98^}G|9^0vV2#kgdfAYL{NELi iww?>, ʐ ] xBi LHʛ1VL0JRaVuZ-Vi endstream endobj 806 0 obj << /Length 197 /Filter /FlateDecode >> stream xڍϯ P#)>tœ &5m.b_CYN wzto,NvE69Wh .-rZeD/@sL@56Mo%n} :}v%$@FTiXz[V!zyM-+_X=Ey>J3CN.{K endstream endobj 807 0 obj << /Length 226 /Filter /FlateDecode >> stream xE1n@б\ M<'m JHqT)"*L(iRZt)GLᏱEW23ɢ}ɟ\YV>>xUs&Ւg9pzy^Jz-NS={kg`g?EJEAJ>.dt &JI0r熻qM 5.M_f[݆{GZ>_?WKq{ endstream endobj 808 0 obj << /Length 192 /Filter /FlateDecode >> stream xڭ= @ )"U F0Xmb aҔ)®p)6 GqBQ@O[SQ6{ t&NExޡ9OA q@#~8 7ŝm'ch/m:^[ endstream endobj 809 0 obj << /Length 191 /Filter /FlateDecode >> stream xm= @ x Ղ?` A+ RK E[)S,;h%Xfh< }:ex\T:8^pVQ>EmqF;)C}FE$ sXBט^Hȃ@?|bezYETZ_q-`R!a~K<.Kj/\ endstream endobj 810 0 obj << /Length 187 /Filter /FlateDecode >> stream xڝ= @g"#Xraˀ!N;GYg!BR@[]/w%ܔ|q&?,Lƹ+x"ҡ@yRx -0遍~*?umֽr!0e] EӐ`%Ж*sz endstream endobj 811 0 obj << /Length 182 /Filter /FlateDecode >> stream xڍ1 @EIk9 n!he!Vjihh%GL2Φօ}g?ofǜlS>'t#k5?;2{Zd܆L]rBC\"iJzD=[5/jLAOQ~ߏ@B_Zh4J5Ϋ^RMuZ9uEJ endstream endobj 812 0 obj << /Length 193 /Filter /FlateDecode >> stream xڕα@ .<} L &`qRG;[pqᾤ 5)+H+9s<^&|XLפ*L,r0S⺡MNMC $z11wx!"><Zi&N?>cH RaH'c ˁ:ѴmO, YK endstream endobj 813 0 obj << /Length 201 /Filter /FlateDecode >> stream xmPE4K BBrmM>}}V́;ܹiԥS=T'u9&a+NFF⻥OK+ VZ[( f#2;܃J>PDCv@Z }•cC 7'* 4u.7mp b2rcZI_ endstream endobj 814 0 obj << /Length 154 /Filter /FlateDecode >> stream x313T0P0asSCCB.c1s<=\ %E\N @BA,@Az H?*;&p4Aka[~ `1.WO@.^ endstream endobj 815 0 obj << /Length 253 /Filter /FlateDecode >> stream x}J@#E`}!k.p` A+ RK E#U(y[,gǰzqꜟJz`;볟 Z.(wk~x|ws%{/xv4lnfxYDdItSn\#7@efd=`El6X4jB*`f}E_h0bj1SL̀,x>v*!*:MƢ:?-y%ۧF@-7> endstream endobj 816 0 obj << /Length 161 /Filter /FlateDecode >> stream x313T0P0bcSCCB.1s<L =\ %E\N @B4Pe,B @d ?  B~oAd $?HzI8'W z endstream endobj 817 0 obj << /Length 132 /Filter /FlateDecode >> stream x313T0P0bcKS#CB.cC I$r9yr+r{E=}JJS. @-\.  @x@@?C1;}pA|.WO@.O) endstream endobj 818 0 obj << /Length 169 /Filter /FlateDecode >> stream x͏= @_#d.͟ B Fp !VbnxK q\`eW񊉣~2c!GOj .mO1dXV|-M -X endstream endobj 819 0 obj << /Length 198 /Filter /FlateDecode >> stream xڝ;@%$p.H)L0VjiVW(x[_~0E_cƃ=2b4gA ΄Sp)-8lsQy endstream endobj 820 0 obj << /Length 115 /Filter /FlateDecode >> stream x313T0P0b ebUel䃹 \.'O.pc.}(BIQi*Sm`Pz<7,{\W endstream endobj 821 0 obj << /Length 171 /Filter /FlateDecode >> stream xڽ= @[&G\@7!Q1#X^,7[n8ȃW3r9Al&]'-\,cx܎` s0 n ==Cbq1 SeKvI'mr/)T8R`5zf endstream endobj 822 0 obj << /Length 155 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O$$PD2`$ȃ@H&?:7 q.WO@.ll endstream endobj 823 0 obj << /Length 183 /Filter /FlateDecode >> stream x}=@XLvNBLH0XF[٣Q8ab^2}KJ)*%Kw4 +@@)juE]VQzB[_P :9o.A@9(dq%7@'a/=ߵG.^Tyh p A!\\[>P: endstream endobj 824 0 obj << /Length 200 /Filter /FlateDecode >> stream xڥ= @g fI"SZYZZ(ښͣ[.(wS|7q4HRYs_8 LWCNv?$#(%p:lHj&5pGٌs V,S*7;(&A]t, -GT@8=F> $_ȥF<5ޯ endstream endobj 825 0 obj << /Length 211 /Filter /FlateDecode >> stream xڭ= @ 4 وVVb&7J{ Lig Z 6_B޼q;QH1.#ܡ$ )ѯO-3 # ƒcM?n0O$!Wɾb|31P_6rilxz+=Տ>jO=]quBVŴ~[)D\|kse8'vG endstream endobj 826 0 obj << /Length 158 /Filter /FlateDecode >> stream xڭ1 @ПJuj!Fp A+ RKAEh9JAqc![̃I`4-ØԈmjw쎜{Vky\Y\/|9êe_Hx+5C8#$RC\B"xo<Iw endstream endobj 827 0 obj << /Length 185 /Filter /FlateDecode >> stream xM1 @4!s7q5@T0XErr,,2ԎgDM&rv=pr^ًYMyaoY!RrGB7 }KD#"eZSW!("PB Ca}96A=> stream x313T0P0bc 3CB.cS I$r9yr+r{E=}JJS ]  b<] @AH2`h AA~[@ Lx:B endstream endobj 829 0 obj << /Length 148 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O` $0()D? d=H2cģd> endstream endobj 830 0 obj << /Length 186 /Filter /FlateDecode >> stream x5= 0W:oN`B`A'qRGE7^̭ ء4ؔ? ,&Q@>0[}pb*Q)QzܟvI>>yG:J^]S |-,ZHZX:^<r[C准qzb&gaQ$L endstream endobj 831 0 obj << /Length 174 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O `?aC00~ @2?Dv`N2~+ߎ #ȏߏ`` ?G#g``?A6 H@RՓ+ ɝm endstream endobj 832 0 obj << /Length 202 /Filter /FlateDecode >> stream xE; PEoH!LUBBBN!۲t @!L@,a̻{ې lfOÄܒZrɌOp>ܘW!kJ/LnRQ;H(+p{h/ O.ok> 44W&F&R$}xY& endstream endobj 833 0 obj << /Length 237 /Filter /FlateDecode >> stream xEαj@ dz)CB=ҩCɔdnvj:t&=$%p!:d-"zX!ZnhyxDQd}LKႲ)ֳ[{vȭ+OPy5 @U-G[;z[*lB;v\ɼHer;SHR Z88 ~Ka{ endstream endobj 834 0 obj << /Length 176 /Filter /FlateDecode >> stream x}1 P S2Y<9*BV N⤎G(Ϥc|?!?'S3>gt#͔+^wr~ÏB.9#W!H"Px+"B I / >i`$f_$hj(D{{-ӎ~b endstream endobj 835 0 obj << /Length 203 /Filter /FlateDecode >> stream xڝ= @_L#8MLRL!he!Vjih'({!q-6߲`}t!'<8 91 ũ piNfqJf)c2ot=̜w{@^m W÷x: dTLdO_'X`*w]!WҢqz9KU" }}d endstream endobj 836 0 obj << /Length 141 /Filter /FlateDecode >> stream x313T0Pac S#CB.# I$r9yr+Yp{E=}JJS ]  b<] X큸7001;j?0FJ endstream endobj 837 0 obj << /Length 222 /Filter /FlateDecode >> stream xe1N1E*i| .-V Ab $(UAݣ(>B,?kWEwk.i;O%/$=iI^>$nF6x0ڄʬ ͎X⌾T~fGvlgOȠ<|HTGǂ+ˇD5WTL3*=2,<8h endstream endobj 838 0 obj << /Length 226 /Filter /FlateDecode >> stream xEнN0 J^ @ZHHCL @>ZlDZTe}9W|Qps}ů}PYkP|N#5[ Sj~??ScNzDDFM&4=:4WL hLVښQ5A1;,wKi sęǐ dw;-y"ͧ\ۼ>[z3Vc4 endstream endobj 839 0 obj << /Length 181 /Filter /FlateDecode >> stream xڕ=@!$p. b&ZY+h pJLh$%^5Y (xTHN)74 U[QcL uMĄB9ƛG3a(if M( /#`cV2OZ˿Z;5t endstream endobj 840 0 obj << /Length 207 /Filter /FlateDecode >> stream xڥ= @4{t&)!BBB,xxqFE惝}ov)ZRGk;Sʱڬ)Nюe6aܠOi(Zb>$\Cǹ.5Tº)7 P \)'ߘ'-,e$9ґ i `AY ֚ G9-c endstream endobj 841 0 obj << /Length 241 /Filter /FlateDecode >> stream xm1N0E"4 @TE"Th+)S ͓=3uE5w|pWs/ 5gFGn{n5j+UknS=6@! `dHp糢0g0p \ύF<'"DMbLz[Zj6]*7DE??(jALP5ˠGԡ(OY*G@BR栛 5pI endstream endobj 842 0 obj << /Length 245 /Filter /FlateDecode >> stream xm1N@ Ema|HBbE"Tj`&GkH 4أnv+4rVISJ{!Orݢ~9^ꖋknR*.PI^((`)3Sژ1+-:%8p'?, \%ᔀ^ÊH"4)MP9%7Hi/! GdL!n&{| JMc_u|_!r endstream endobj 849 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 851 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 853 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 855 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 857 0 obj << /Length1 1608 /Length2 4269 /Length3 0 /Length 5073 /Filter /FlateDecode >> 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 859 0 obj << /Length1 1144 /Length2 3969 /Length3 0 /Length 4721 /Filter /FlateDecode >> stream xuSy<߶eDLv 3˱%}h 3hDv%&T$*oٲ%d.Kd/y9{?}_}BM%@K@$0gGH (@QhH Z ' CH a`EL|^ |PH4¸zh/B3qp0gib$zJL\? \1 -tGI ?D Rш&n+$g Q< º&sDx)1RWMOϙi!}WRSvGD#~J]C#}] &A`$C p҂~0`AnpBM}|=B ] t `Ͻ!Kʁt E'ͮiQDA$!(Gr I*' 9vÀN_>8 A +O%#  D1=XLZھ(ԯElD2W8 "ZQHWu;1!qwЈ_/0?,H"@^G8}(-+D$}?iW_x~]_{7$@Ob\"<#Kչ%ɴ_=哥"_h5[bJIj!%yT{ ס 4,,:\%+`_m\OV5 :ċ6B},Q`}ocj 9Et+bs6uPLaݍZ`ϰ۩ zMU"z UXXGF5NG]ǗopۼT55IhWk$onT/\aFjDiF&NP9/ WZ# ݌hu3/38} hOJ5cܶb#:kZzqL9,i6\%+@f)IST;_?S&V:"2h2y͉O]6)m9ƵpT$<}zsu=ZYhl֐3@EfB "廑];A߶vfyq>Z 'H3懨 "V{(tFyl;2 ɊCɘ-bD$SvX5XU`u_(N;CxʗK1=dc)qsIS15)K1[z{y<{}#_.AS%ttZwc,]RLLq4[3%չ<+~62ҿ _VV^Smְi+^_1NC6_,^Q[6CIn$yQ*1_.G}('PT{qx}r*8IpR`| 88le VlPiMe6n6ڄGؔ18V 8M[[M]Jj2) lHהSo )Rx/yϾ錃$|墋QI$D: |ּ{36Kex/~]L# yU a1[hVKS3y+s;TPx店61LhS7!wjoNg-k/Jw~5ճ+1,!tAڅ{:)~gS%"J7 鄼7&* qpY$JSM . 4Qy[~ΐI6yk ByRᲯcD5!BdXkno}IC ǙUp Ŏ.Kr)&%z 4[8;N> jnZAi#*qw%Ϲo -p =*mJԬXspY.́U+M?x$){TU؊T蹙3g wċ~V.7oLptk *+MswȈrC:9n[L3zѯVw4RFJ<bq=9"s(Mе9g8f Hu"^˨ޟS('N<)yry2Ai >k=ZTQj{k`n-E_HKK!D{ICw&? ߌ &0sWdC?YU8H!p2,Q l M{^㦇@zq6*![h ڣ(]늠u=>]~%h淉㮡x1WXM  kO.gPOs}Ya7}(ǁ&n^l]!UR., RS]ˏis$8m`Qo'wy38uXS@]q1rڹ \VBQ2~>W['mq z^{NJtt2^^%yٕWL),[]SNqLcɏ8|ocR>t7 #00sXi?8jbrܑԝS<ү/OiyUa5ukE[(]y~Ӡsp.rVՌVpdD8[FL)|/FP_48{fu>L A+D? gxлzJǓ.fioɠ?4_fs$ޗcf̼S3kg.3tQ;Н/^11[w4W# Ug6'+;B! q}fűւ}fuL$v=ܑriŸHgO Vv)|ڜ "ryvgss4^ג-=u )HH먄GZnC4/ÐHP%(Gy||W$AX\1$G3E_($A>5i_uۡFN?elŵU($o(/W]8]j^2 7nfoLm}UxZS\4wlGVx7J~*_JՅ.˛dFrCajf"BxJ* ոMebn / 4>  wzU}o|ĎYxDԤv/7DSYh=OYH7p5?K<*\ 4n\w;7"4ےʿ2$ZKnF^LX*A9f* 4Lw-$t/S> 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 863 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 865 0 obj << /Length1 1626 /Length2 15695 /Length3 0 /Length 16534 /Filter /FlateDecode >> stream xڭce&+͕Ui۶mYiFm۶mӧǹ}tk's.RBy%Zc;CQ;[gZF:N4௜TVلfb 6101988`HBvf E5Jjjc0_O' 3[Wk;{[!LL&S kBLV fbkh` w10H[:PL>l-)͉o,'⯛?*goF.+7 {G6u99;9Z;f7Ngsr;YULZSҿt:X:Mܝeh0p6o0{Gpq5O4G3Gck'a;Y'_v_,LM`4rY502[nb:W5⟙ `lb C/k7%e>(o!7r+G%5]2{ gѸ\ l,=ɿ YWߖؚB 'Q wcy g#s~Kbklhmak@_tFVoWPQWҔ?,geg)2vOAA;w-#O-3 ߻!1YnU?y/aDl%g[㿓\8kMLM`֖팸,2ӝk1r'{AK zv9*?j96}kJ 7gȘVmQePW-T??$D <Vp9sk\j ,S}nr ;~eg`dm7~DKV*7ĚE)2QMeN5w.9-\u'b#_ʣaQhG0xNBu\X/iZRPg[xn*2ĝJJKڏ oWP>'$nd@a}0] ?l$6ʅH^*'Şl ,愆_//*Ê?7)~Hs(^1Ynk z|9N̩p2z7J,]yIp(>03+@PK:Fk`w'q*lFHEױw#.e, D'ȔZ8u 0 |\Ti* җ2C{Ju5>K$w/M[E4 D#KGKKc%$v"95.K*ml7rIRo.f?G`C<6u@Ə:Adcnmp=UPQJXVNkνL. .5ʺAi!}^bAίê/ej+1Y1zP( ._TDsS.@Nrֿ?9 .Tg6˃&yEV{w>Q?}0_@U-F¡sWxaMS hjz?՛ћB+TBG}V9sQ8X(cIEˍKFoҳ׎e?TqƮ葵پ]*ȜriԲ[УYȣJWx eOUx:2Rn=PN\ڑ^\`оOe=cקlؚr|̠~31{ Bl}Q`R~`Tֳbl!}({= }9ecaCdao4?;00y݇<0e)4ϒPxq+KK_\~^?{-"ٺ[q0pnP&x- RHzu+Zt͑2w{O*f`sd`$9j\e`{"5r{%B#wu_3!J<(ŌU_.lT Fu[cNK~NYT~=dQAq2^*CW%~ L%5"[$g&SpaM‹} WxJ`t(EKeI3XL \A{$Z+9H^($C g7tmV2ˋˈg6ҫ: ὾CCOg4I FɭUПvEh^ t*) y35-GqHQw_G&:JI-CuS,?6>5ĺqokM.&.g|#Dɳ?2tEMM+@pƆȴartϤn n_<( ԇ ; ǡ7+ė))Ѯ\WOmXڿ_븚k&. '3C53$xY/Yp5b` U,5t){7ұVx7DRa<<;YsuTa̞&|oj{)-PΈ;4Xҕ@+ڊFx$'(U"1d3o+ %?&l7C4(Ni/GOr(l ,J 0F=U%;/Kn PQtՑ'lɛhՋv0/ît7N6feqrm!cܚ625ۑ$B<-5&z8rSE: ()Urz|-l$薼$5zJcXT:F K=VydZtMBm`LXX(>pez x#RꝵY~Z9-o&?]6τ$;|;[ +3|Qf)wj> 9!}E Wϭ:>ݡ`snxp - . [sw$E=3XWt8cx]I0s7 ?JAWVI彮 ՋtZ)&x}?LݴqMEx[S>SCx8UWǃ@#`4d{Ndsٴڪ+ ;Ĥj 4M=fi_:7ACd!H %k`)ٿ'..=߬uoA(M>oÏ3ZY.2L\Jgd_vq/߳V?(݋Bે~ŚE4-NrjIS O@'*|=n~po?,U$^Y+E%IrQiۆbԫHoaw(2uͨTo'yF, t/ĝ HJ`?`QC1HT"#)c0vRAiS+2Q1iݠ}!˚QO̐-,n5X#x%Rܟp^-&5t#b q j0HAYb'4&RK孷6Vk2lL/c  5×V/_Q !Nx]ko-!xf- =! ׊zB "NsQ1 R+J .1Vy5ArLRbꑒxQL|w1E;VNХBaMw,Fm Oz;Qpc`ꝧKp黎"7v 4%Ҩd.e$] w_{G]Z>-iDt?6#A=!gX@P$ڬfL  plFP(H3[JL/dy:7a{gx mBߩv?>ҪEYb$$,EfeCtt} p`ӡ| ўHŦbSr Mi*#"K9Ѫٻ(5K-$BFJЀy{0 Z.La QT:DB⬞:'V0̀D|a.q 0e!DR9^`!>zdC*:b ה(,%:@N3\I,e]5%i)L-Ҙ~pـ;JwԽU/dA)C;%q>̃_W{@+BW) ʲ\,dY:o󁏵k0Ca,>?"ۏ: 0@ _ ġ.{nY.flH`,9 s?"CGr;$-x>Q12c gb$Y,5au,!eDpl薀qS!sGպЕ0aE8XNK,$j:丟PäôXSPJ#IќFsp%,IXs夅1wVZ9L](ɷPu!D+H+UU<س S|e:[Ornbr6V109?[~i{b>{H.k"_t1%\Ve"Kg0[Fiyɹi!Z{ɰm19N7IN~u\YSL $NvZGN1I5iKk0xvAU@~m,Ǯ&[Ƹw)u8Hj ם=1>ƀsB;$CTDS ԢgD$֊U'(+B5iس24C``c;K!}%6a $h<;NT[?ǜ44+{ n{T(ZjI{<8%X+V XF>(j*Yf:e׎L"GuE^Xx 6[uZ8  Mf"-[cksSbug0}t)Q ]M@R}㽲yG.FyL*hr;7Kd&޻{So{+^Owvhj gOJ`YNIÇf 'J[_"A\=AM76ubdxqh1J]bSYJ>kPJn#$`|-_V{^l fs;ZyW2 ̲_v72`xN2 b't]3gLpO1tM!@3 P& )e??oQRvuaYo!u[~*`fTppYJ?Yg3E7Օgo86~rd8+>8oaO/Q`|Ib[Y۸ʅ{LJb\a~?V'G,|xX6[b<&nzrzaIE^K/,p;ɍ<cdZ-Ȟ´uL"<l nOwF+TE MKՁѻ bkk-1&M 6?f = ~lU *"3Ю"<u𤄑=sc=mq| YOWwh;y`$hʾduʴU Iy:e2BljD޳5g+N*@W1L[>Vr˷NwI/~bwy"['k}O#cZMPq?8•v.sV8pwɠvXS ܈!& ^28[:9τ:;h5,A7ĵlu/_?孔N۴kՄdeQ\a'8e? 9wtnWtucZ, +~ulWb>$%oЛhBpǿdwLŏt~ÅxT`D㷭8B"kzG_f_}It;~Z5v5H Q9tĜ#q2WMW^>P,<_1獸>=T漯Ş%O QeSv$5=tՀ8@GN@1{FN]ǭ_ǛY=u'* YYКϟ8AtWdRXjcŃD :9pHj ; )(e-\tF1ȟ16I^W]b)jNPCߑL MC56| B^HEӱ~a~C5>&}`F`\K:dLA+:)Mhce>ԕp!_f9bh]h-x*wQ]32 [ ҠQ( TMr:.HQd`GbG966I_\VOѝW&{=ÂF (ҩ&} &ib8ѷθS{J|wQ{uwD 3dG97o >Z*ge~7tb"Dؘe.ꭩɫHYx|JP|Хg酗wofhl ]EkVm_&2k10?s$FfiR77޺rبfc^oϧK ,ԧj#,1QW(H)eHW`p.{=| Ź9OHpZ`›Q,c4onvoALQM9=a>$k[c)`ʶ*م"ތX+ɤBߕ/Y2ykx՚AG44Pr7fx%dv%5d:݄aeLlЫa"$^.&=:[$*ܢI lj- :] \b i:<ˁ)eWUDTļØUDHT!!qF>h&a%PwA6J_ϗ+Vs\RVPzfC/ I,[Y$]\\Ne#)E %ͣ_yL(a ^5UکcH> DTǂt_z(T5Tz4~zAxox:kXU n8)7GZ84|&t*xKBcq_$T)HNJj8[wh"!0`~hbD<֏,SuݰޥDoZlA2g\³ i~0A 2B냐-.[S\p#1q "@v|wZh^ >;G5r2.\:cglJq?S9GܱRm>+)z{ Y]~墌0"ovoztXEQaImZhy]Sye@x-O9%L\nJآn$/K/LnC#JUQ4ΥJ.qu^0v1CE/vxjAˌ "f*Vh`t 1;CWbFhgbrV%_XS'v& WO׿o,_"sx;oϕ~`穊.U(>:tcvzNYF5aM;j ^yY,| NƪpN,.gw@ֳyX6cJI>:ߒ~gwi7"FPhL+"E{( Bc A e_sI_} 7dӶ˂ 0/&7q%"]v O܇'QFgF"m]9reP\3pqh NC~ssP5whd+pYu(ܴ!3a`6+ LK3jG{"ҹ3<8O$X%| Ewɐ9%r.;<7\) aގZD( %K[lk`V`(n)u Z_D?RJ۷NЛ w} ZTN3դمFI\p.6Pcք% F#/{y$ȏFcAuMCsБ..OӜzL?9Kb-:œv+vt 7|95lQ 8x{W@PeV9x, +ñW'ʼn LuS&]V9[S ٷoY8YE7%@p4N/6Ԭ8>R3ڬ M*?ւ ҄ NXbiܮGC4Zby j~Isg!{ŵ˨oCt=RsdžB{%Zwh-2vڳcEH<.V}$?>\C%PqKM\ʡ|}W\ksqw ^ zWY[YJtu|HDSbri7ۋ"9|c'b[$w]t 8]n7@Ci5+~EEgF7$ŤrODy4\ ț@@НFLeĩz#á)mj`BTbrt|B6 ź4gK).w bҥ&2Go:WȷUO.GpÐP")@%.|zr@vrUMr=u}xhxCŸ. X~h8ᐅ?΢ j4X*iRpV$6 }~QYVx8+FF֧i]k mXMsa kTxҟ[&Sxrx٠4c Om[Y*?$|j'/^[SzowmdBԌPR0ʯso\KQ⭗m.2ЅBucS JoM nE,a +djVmY1I2ĐTAJԂ.̀:!%U|`|VF4C#S 8k atCz H-5Nˆd,l3LH0:쐇,Q4r{*kx6`f!f% =.T2*mJ1N)Zm,ۊ)ζ>h@0yR ;Q.{;b?c .XyBaӑrf8zHOzl b:],7X?;E{H#2TZ.qĈX2*4RC!a0xb@񽆄+{!F8SPu}VdSʆ0tg7F3|=‡|G漜7U0y"JXڂ#e|!{g M[#pmo0Utך= Y8 Pw*vёZthq-^)im?3NRn)4(ȗl78NG&5;nplyFYI'6':;FZ|Uk<n x#޾,0O 4ߡe 3ZWWa5^2SI,3" cB#(Q $4.^}|x}n\?qpW"{{XX5L@fRҨf~ZR˶=z'62%^މ{6A*#\$OGRVw"ۋ/j]hQIlכiNPdb=nO{?#<&a1e/*)2Ս6 (\:9B1UCeLR-qXe{}T Kx]ST$=s!`g3тM)Rs Eų*8>h:]e`uaihAt?vٺ$})S~ŽP5w1C#s]uv{.viTcͣK-p,4 .S'>m$7/.!s!ʺ|ãOMUcCƽvr /UG )^8Fr?Lx%|H`Ӷ5_kfo+[VU?#as =ƉYG~jEQqZȫ?DNQI#!T oTLM-}|~Ւ3Jܝ~կZ̔ka+LI#=O*NRQ F?:@x#{B᧝bbΌ߉ -qE maJh4=3Z]bj8Ux^m>-}>OՠrIߥDٮy "m"GO>rDf\QzIޗ}p?oOj i<`QJOzia%E|leJ346J.5xu:J ŒzhAc1BosT\?n;f~{U!:3,hb`ezT':eYJXLZYM |d]7,-m ^sKTn/)kZ2^ *G? df+wqZt;/hۦQ7h#0Sc>\V,1;ҼOfj Pr L*p.jp9&B]`WH m,#Ҵ{/5iV\,@{qj5y%PַF_i$:/L-)YkVYۢݬlu/W#q~D;flK^^?G4TVE KAߐe&| )T~v_Zn.5/4\HVfQxR<3d=UM6lB#:/1%$B3ID~{tѡ^_qNt٣jj`\bqxl4Ʈ~[DMst\6:ʂ e[4zXpd+h'(< .1=˘rE끓}>&f&:{3K)r4hD{O2e- Q/JKH[ :G;?}e d&6*wbGBntM^C"#C*=h1L IȎpYaJ=,Dђ4S@P"F*3!xKáSh[8k|Q7S #'Aym^{-_p;$P-2+S-޿\֮ (69q_~)6e\mxRO(?U̝cךtqZyR.2yܾ.h@ ؔ$I4r{`:Y4u|\w{]͡Y~N}嘿ߖ~ - p Ao]GF)gNˁ~B)wlkl98B((o_X1#3xd5ib: {m2 ur~SܡU]p~._Iq"̻T%he'Mmc>שZ*vAgKGmsP4=W! vA8:< 9ၷqs$b:M-P}ͽD7!*6DŋRO喋QzM ]ƀ'`-@N _0XYұ\v3kuGy/ȡcF_* lv# ֨$ReX;f++% 7c'Q;#uě~4(o0߬FZ*i'7[0g>p2SH1G vB/kwEǴ$o/4C_'/,+#Q(!haIEvaSg5ODXޕvǘ݋m!.'-ξt?n!m. +(d$vO Ϥ1?ׅ\~p~v['OX2]6UyN|d(Ԉ[:/_ZRbUGBHtg9ke[s5!1X?8U5wgRSJ][NI'gۛjA?ֲ endstream endobj 867 0 obj << /Length1 1630 /Length2 19720 /Length3 0 /Length 20553 /Filter /FlateDecode >> stream xڬctem&vvTl۶mvŶmb'UYIŶ=ݧt{uO\׼^cQ( 9K8ػ330L\TU-pƮbƮ<Ms3) GuprrPhtP}p7:8ڙۻvT57Z,QE%miI:@Pr3ZM]iS{3Jsa%08Zu345wGEp4wvq vX:ۻ큫fOJᯅ__0%WSgkGWߨJb.fn/_ZWck{?Lf.@c9:[+ 7k{̀lnil4wq gzcGG׿e?svu1Z01i7=?"mo`f͝ fof@/ߐ;Hoz/>Wh 7 P{.c{=h?c;kZk;߶[Bk kOs3%kWS+1o%W73wZۛ_m331?$[eno_+K׿gҖUS,*W5/ǿG5f' @M_@y7vu_?OFQu57;mS/Zͽ)것)oMFvkv`?3pc:mj0iSǏ}oX@4B?2" .Nڃ`Fr3E-&Iew(.Vg'@2@ GG$xnf3G_c#C}7y$)^F?L?!_9]jr4P=ߖ݈љ3/X,AMe=.ÿDZ$ Ψ4v/Kp9oɰ^Ꮃ?l^ +aDՠ=LJ %SY[#OB\)Z!p*eG4֠ՏV-gc058},GԽog1Я*lq|x`iX"US65ëЂ-q={Rv<1wwm}= F3GͲe;0^?z/@*da Ru>Mꇚts:EҲ8vSx WlXi=ld@ -'2uZM.h](q;xuh70jhJ =X_w쥄ZLPTPlR=3P9ki V%&uijS=-2jr9r1}fdZCRMrbv(vA+ <]4P=C1XAZ(bw%ϵQ֠f*8yBP`f !/ j_/Y] =vbn,lhaΕKQv j!ANow+W,*tЈ"-dgq1`Uv81c&_ ؄]X<ڔ `m-9qԟcVAR 6iKj\ŠU"Z^.TFM\P֐ {f$ρ}:EzC5C,p ߅ymԯI. l,҆no%uj k4.)怿'Gr_$xF=jڍky鿰ѩ\vZK=FtmxJ-87eV3V_,<, :DRˑv_@ e *@isŽSZ[Qti효,zQҍ_**.>A1Ca/5['D_6^tsG&峻! +vcTzLz|~j]g{nLmSڅ{'Ν9cAK. *eY?T2.JlFJ ld`[,nYHrv8ݤ'щ|i/#`37<om`N]C|sIL jyc븴\Ct`ֈ 54g7ֻ!jrD/E vYrR¶wjB*r8: H䲢i<w](횥CB_wglndSc$~@Ńq\[`)>pl , :.` k;1%$E҈DeK7b-xp&yu~: _-esgc+Zkbv49&ƶܐJarOZ*,7ϐJ*n՜-/0·*qk^R:t) gzBiC0}SSa}CN=f=Gc"L(6e^RumoKcX=7q-*/6K*گX/vdqގ,W{iv4 4y6ʢ(64{؆Odd4=HFUD݆jn4[WIkFXc.G׳6 u$ij*|8H܋&]{f\6ɣ} (OI:͖h|]$cP"$ekm4C s Y*$ѳN5nXuhuVL?3؉z)f?㹺80d`#R|`Fp"5EuRY]1-]8lMIaOԺ'O k񀾦)Ѯd#Qs͠¼hGp_+7ͫu491hb;n5 7wz2.TыY4Ymo !n$b=D8B aFXG@6urlK ֲVݭ9>}jeLC:Wdfce ~iPSn2v^ı6Qcr "\=r 9l_/Q.lM[uƲFI#-2~hO/[#(,Iqсu 86Iq7t#D\j'Z–Zf${[*[R ܋=XfMaI {cUbM}ݎC`o%J8WnJNsPO6rjOys9|P@RGvZ2'M+7LTkmF0unMZ +J *˲u9GLq%넶aHT.B63{o:+&qfε_ =4cepSdBeRq/u| ~9Kx[lTn ҒwE?t&_+;CldH]23)pߢ Hzi3] 0d+\D\G <}f'6"JeOHҠ罯T)BgP 1BdfJb#5vvC`Tw -~-ZQ]a5!9©k104Xor(mLU E>&2LLHQت` "Ϻۘ53A4h|ô_IjJ'\F68-+~Wx =LM i-%eF}aL=mLŽ*ͯuBGќ/]n'WOȍyQ 6n~ c6^gbKiUp"RʸSl;`TW`̲pHubv(،LCIcs UF̀NpDTcBJ /xe4C4Hko|T7 9AS X3z,Gkr ]^vaa[.ףaj^=-I1KSy J5 '*%1d3KLj,p/,t%CX=y[ё+f9+ 6Xj_p. uk>51WcYKfd`MUvYkt+^}2WGR{s+ ]U~q;$\mc5LQ1$ EԛCjA'ީߝq3߁5qb 'ȇ.*J6Z֛rItU*Pa#cJ"cP@ Y'ΈN0Xi0b城1BQ8G_M!77}"'thM6' | \oj8v7 (oU+;Wӡd E)y_ w:pf F]*tf8o\ǚjFO0V:Փ( B}$0){>zҕ)ۿi_ĵW?Bdr eL{٨=^OI5QQ-f{8+daeKBt OsX6VOk}I~L&ABfVi)1͚={n[qߤx <&n9so[\Ǹ3> ORϋrش)FϞq]si{ eKfj)&O#;f؜ sWr[bf=u&q.}-#UDs6V*Ur!Ot(ґ$oڇ M:*jMw>Ž%4<-]ci4G-Xy:iy:H|}%yin1C!aZ0D'l>VMHҪU+9.%CZ q]>P0),32*COŻ/GkLn概P (1lb'l ( a73G\~-MkPvwMdrَ~oIDY<"n]Y|mӫy6=8C'u2ѳ,3*bÌX- OȾ4if> ^}eU2eK4LVvtOb`~N=& "ľMIpKȧ[iG// !rN(; ,# LAp*Qvl^n{ W4Ti~vDquRD'bZOo[ ljBe -5^7 X!ذGm9p yǕɼȮ0ۇL_Yj"z alRCQ"%DՊox|^O%w( ͪD(?E;axosn q8% ߵ:{kDԉ6 gV:P 4OH?bWU% F,`!e]K]=(wqs Wh|482+QOQ<_,ޝ>~R;}WaE|У(mA mNa0-#tSb OGmZ1a١2mkQ]ǡ 򳚌\m-mW*=qڬJ$//{Jk'Yb&8j ]ߝc o Zs9 eQo{1OZgsfweF{U .XL6 6}'QMiTXДCOIGZ9F*(j*Oˢu;>`^`LW}bMFx!ad>|)/O*ԅd +.~a=uAЃ~#Nm3kMW%]0-f^Y\JXeK׳3՚6Wd =g{N 0-0?nd%~{&ji}`:OP{oɋ`-#k}8%LHFqmm%iBMav X"ŇIv$fcUg~~*lݼy;hGeD C Uo4O_f^(8hFdD &l9yob~T5pbA`kTNqyԳS/ ¦!O)^5wغaȩAQ4)x3ud?9yf=@.K=5l7f02`Fo,cH hbS8rWK=vNYd@82.wq6sb3KP¸Ә }r67 qN+kl8U'd” vTI1\|pQ+GT[bH9T`z;L6aS0# p-dffg[a3;:ΰ8j:)U6g8}Qf8 NMk`NOb,gA R=\ă6L)қ=0v @rbĩ?o߆loj95PH}7-2,_Aƣ'w*Rtz_|ãqBdΏIUH~|1%JOڴncߝ8;|+]$bpX:r|83z$*;kxs^5!rSS Z+| wtiCX^(`h`@-n9QS]CP~b'>Wnd%0CtBk͘)Ll5U8٥ m2H,JrOe ēf9wN[T}n۶p؅eFPYh~.:D5yܝ{P9 M_[m9>NO`ZE߿1*G39(9HaBZ8Cs˩ycodKH>o1k s#: JRG ZN~rxDXFI6`-]rgY+h:šyJZU|*9}l-xBO;sԢ_11_iz1 $ x=d$ +E-ބgL2Qn-UY862S|ON;gx"[2?0iy "TԾf9:=zEZ9 Ĝ]/ :s1;Ss!&+rƏOOnF[4s[~]ge!ugULVdgnaOX8 P$~M8@lAУq3|YD֖C~ԚES_Ve (ıɿ~"薤njOTmw͊RGa;=cB0iPiiİM4d?Ɛ$n ۤMރqo 1dڦb%S~26HOeA{}9ɽDC(\]v%z8kq]Hx_d(ɿy-LM)1S˧ $g8oJ bDWVWo\`[u(s,jRnS grWLmeZQCd2t!9@1dޭv&ג; r_PK6HZt %tЕv17&d4c5lӲj9bg?˂S+O C`ބa*3B 3ȑhb\k#G ^Jc<c6BIVLYVqQN%^`un|c1n-K66NN)ǯc2+@V5˻wPFRy+Ap?|iN̡}-s2&b%Ix5Q<ەI^ czOB)CuQE>%clN7v9fn:UZvRM&+xҧG_Ҝ ʵv̳?"0Qp*UR* orx<0%:6Rh:< [La5k6ڀIwO^&Ȋy%c׿ &锗\%k[!^o+<;^"\ w36 }PSHL^cru9W.~1B;\yjW.h!u<"e(H4sUCJ0\3W_8{>HXuAT NZ9,i*Y {Tv"cJpsŖaLMHk/B,Nx|`&,:g|GNbz^[}Q4:1j*Z;H )a e8Mc!J(AŅ!eʘ|5䔆.y U*6Uo*$# ~<|J=GGN7pkY])7[Ē9lNv[KBB@ҍb`c 6-H*l e1CL~x[& LJLnazJNEMJ i ^M#Rpzۑ qo1pR╻HJ( 3KI* A_]>Q1j}cp *JW?XNuCODt12DF߻/L6G|k77*\a{Ӯ[L%wJ5zYkD{ *No0 ,+FuD =5-.b^x|T"=ɒړ43dƵt5)lHD(rg.0űc_.p>l(wgJ= ܯ_֊WH!y,dO7oݽEj42!O e}<{{xd[aYWfo),gVgxCYTt|7'WNl7Ĵe*yL4h:OmVG1;2V?^K߮wM4~?[/)$ }f0? RwnzCr~NJLnꀺ˺b}^H-yg6 n_u;.CPSk}.>;{d4u0)6*B5R;ߠJʠTPµ!UKGSw:WIl?dmfo$#j<1\ӧH"HQK*y_:s&wi0q ˄DfRdFP@]`MrRPN!e($욧w!:c-PY:&2ڭ/^~p`mIn$qk=d Nh`[co bTc0o5 z eouUL8H0oyoXPʌ-n߅lp*r$بThHe dK gĖYDvX.THop l8JF欴}f\vd+D᠛x҄/"79ƇgQl~wq cz#zE.l"e+ $sݭch^ i I㗛qnLC qpwņ 8 uN ?IBP09N1Gz8g[aelZ%dKRxn;}T: !J!M2O_ŷ3=fǫqaX oSGt@%dُU3nyP:_{rDŽv[z=^VFat<"s)Ae1_'^]xG@0p=%bT=F}d#O;t-tLs(p_!I㏘HM7FЏSIIoXjGa=Y$CX-$v]Ta,tߍyu݈@~7!4Yl71No47ȊɆy" 1aØ_읩5墔p*=ڟDf\7RkQ2IH\Y ft_3%+wndQk/M!)nZsS3Ft.4{ﶬ9 .# q"D :r#;,_Ej4,wA}Ct+܏ :R-* oH/,C55y!v0qa/(ǒ:h!)}Cγ&U0CNɋH=QcQHE#o_Rvx3L0K͚vBܝAHD&Stl.ir-K$h{On) Gift7VdtEոAUky̻t8Ajm᫄xH] 8Ak^STSHꪃ -s ML9N%GbFT{$V*1޺JC@Y)BhG%=^Ҫ#t@I`/Ws8Sm-p^:+SnQ-KoX a+$'@XU WfBmv>+FƔ<9giff$Qۍ>`tf s8j-KUE{k6!PWNXQ?0(45^kxyL׍sZLl ?5@q_.SV4;"`Ø6&%V)bYdhv/Wu+7UB;{Ze:M1ʡ'\dEqYuAz!3XQôSXM2b ,Ҏ={h bkI tN5Zʏ[ Q%pľ+!TT.'m{gB/T5dO7)fQwatux#v'i1o\znhAx )N^D23KhV☉R6] q'Hg1vRxX`7Wvn)LVyy"^X9)VO^]2O {Zb!o6Ϥ\gj1xFVx?|s.#\RT5?J\fX3H?|$c׌@԰mxHEP Oh{Ȥ6"5tmNfh0?qT~6kj|./E{wgl(i>fG3ygb*\d03qlMK`I"mR~{c-pGg0Ij|ȋzEɾ řxG2^B3LSHC~˰v*7c,Zy{ߔliSSd{p]?v)U)[Րn6oH\a|`rtW-a9~-ثy, 䭶q!MJ*A—2ultA.;./e, d~ms{H:VHQn)gc'AEszr/ˀrnL.a;)Z z8+ސք"a5A8Q-:'Iirbƚ>@/5)s:0FnsF}h_T~7ä"JLIN4=|pnڞ/{3AU߸b+'`NC1*إY@02"_x `_ %?\i}k]Bz8F׈I2DXjn0@@`5ޕqzC0h,Pz A Sba8cS h['ܞFPiLK/&g$|  ݯK-FOF'C k6m"kS8(β ~GաPQ!:wk 0집Ϗk2ZBl G-3;j) 7/,3JwP an&%%SݫW⤵r:߶OJGc`p&P/-E]f+M);1h!&'MX14|Z[DQ\(!F ztǔD|dZc?+@YP'Ɇ?㱻uKm̊K,"2Hϛ~q(?ܙ) H Մ@g,dEuO#Ԙ$@El5—?^oŜ]TUp ;DxsJzLsEpHmBEsZFTNα[s e"CA D=g.+/A]nh"U}3z}Q.yJ3+R@l ċh7:蜶\H)Y0}>Y^RW,<45ա bvOk]{+.3q9g a(Sr `Nr"yr7["2=% ~6,ISP=lV ӻMOt y] =ѐeX5i/s 0~)|dj_:֜f8\Ρ]W I9v].9aLS W&P}t͑aF|e7GK1`%/B/oG4ꅈLFRO'{G2c ;eJ*ϕGPk$#hM\5@~~N's%&Lw}ςa jRHY$:tn74Hӥa8*=[6b]#{x-~f-5"/ B4SZV&NCqw)|ɬ' vv8%@o'҈VU%D ͧ³BJ0;:~"x}=q_Ctnc=2A x _J۳,@ M7bdž!y~ON+Ή/!\&."g0m>jc}Ghm%Vȍ#՘z~]i)]o"**.$~x%Y*Vj.fl⼵P16%a2UyYͅ>Q7'C2ĥ}QA%ep6$8d7D]U96;ղ \.c-e{c՚beFZ"1s mQ# -S씍5_IW?8ڐ`ni9%QPX2mH$KV%O.ylD)Y$l`a/~z_QFE8`#lf9v:񣪀o W YX6cDGX#忙OnGޘ};RWDlyZmt3&|&+7-O"!ޯوOEnu/CLp\:Bm@Yf[Q}!} tlqeV\'=q-Wq37i?[>>q^ ^SL1J/7\RnMs&"2arhQ̹^-QO;,bҾ`І}XȋS.[:;`.e8[Ph@h`6^6xzrn|(L]$J"k6]UF펗ɹpFܯRWa|j.Q%Є?lϥj z8ܝ?UG]?V۹Va Qo{׋ _JTG%Pː?)X1Il@S1'^,cM/ L_<PSXFbeE&Ud@MŝlXW$TD\VCa0G?WUM &qơ0.K1Aϼ57ρ'rsV.gor#_I>{Ə *R`$ekP/LvSsֹ$@sW}+YJe. /)m}}UPv4(W|LTG$YײbjH$- V 209[#cw2x|{ݠ7q Ndns0II0jO`TC%y eN0^-D_C"e! qAbh n+ylذ 'F'SZW`^u^4eh'1:p,#8y5Y:T}P_>\l7%8tg!/>$߭ˆDLk ֍Ť3Yۈ>rW/x{BA?UNF o ^JTkI1kbK?W}rI{zgQKshM\HPrW{An2NN,]b; 8J\k 6d+asMϭ9n)_C{U֑&8Z{?<8?'|}Ӵe1qGL- !1n_c?dϙj`2{0-ZKX~_|(y2I YNt`ֱ|)T>".h%\[ne_@_&4&w x Vs@pICCto ~,Jr?Xɶ~]*4GR{8}OL/8RjyD8 UB$06f2. |Ím4VN~ ;=ʞ'L /P4Ց2lʰgSDn{y!|6/lŭŃ:0.¤Ph p> 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ݒ-<{݂;=w }gΜyνg~]jU^BUEb]X8X {3Wgu2D@Eh*bjxxih. X(ZNN2 @ vk0011 [3 }pA`7qp,Av@GGe-G ք2 K9l5g7. g)hz z@'{7 r2݁ ۹ZUwAN77LlrpeUG.֦.v囧hPSp+`rv3|F Wg_0VNv@g77n_}KvGC@.@;KVdη.o@`dEl pnO 53 oEZ@v %22-%2 "yߩe\M{hL]PlL-jj[[)3YP[,M.odD~߂ ӴۂRl=wlZrLͶYm*\4=Ȥ_T7 1=GNnGڿ8uV2uqyY9odo4Hl6zi 6wurzSm?? h41 R74.;P֨Y\Pψ4y em|i;txޖgNR1bҶ1~>҉>U\ˮ9nTO:x!ʭ0]a9ӎ}uSTy3.ubw"k̟|r6RZ2\oH^hעuU+xV*.g7e8K:/@^"ӺǐM09N2,_sz{J-P`VõIf\"m[O7 `εJj#׃tjg!q=l I() <;g=R"ʾC|΍8P0|Q.ܵ.l1^.fb ^Z2&6>cR ,qXKgHSR~ٿjg2?{U\vG}&( KW"Ѝrں#p/f 5=C*EZ\?%'!`8ѴnjU.`sgբiE19FTzdd#-:sܣq4Ҟ&0cMi:\U3c.싱_V1:$y܂F^+lI;;qeצSLC:@S$κ@6$nL(9!d2SفC_`LMmduz,,n[Z+OƋ"2W!5QTͺ~XWsdch M(ZFD.'(:>F$aM&>Q?6KG|DڈA%qjuwM| \-}K |Gt^>lي!GraӸSl2Nw@BAΓ"ME t|HbY< 'Ḑ]c2a$!%V(.$L^Vt;A 8Ά8Ɵ5tSH90t8pSJ m,(ԗG(o5 kV$E,NCFjϽl}CyH*)2q])eU(a,w C K"bKdiJ2u\I=qF]Nb'g|~¶.cC$ !9-AqM(a^t=\[cN( EXo,>$c}M]]vTw*U:G]A$؁橮ZWfEfkKŻ7V~-{Ӌ ;MS7ax H%+Q !. QKܟ|N>B$MQBgP] 0ߢ]LyCPa΍lxV/5U!#OeE"ډ6i/lu{.Tkwm QCpnmL\f,3/?i?clKպ[ !F%S#qy&J^Q*yn2F hއo |rΣV+7i)U*[kݿ1c.8AFe05U,0k:c:̇|<jhz2Ԣo^ N%6 į2˼%-A'҆Uwa4zȣˆi*˶bjɒ jOa%bӁ ^8'dU_[ /1KQ״p_|.z:" T^Ծ&""Yšϓt03szʫX@D>80eV3Kb j2Ĭe Bi'2+l>Q3Y69GuӚ"R&LoQ,V=-l j+Zv5^%1˧Gk.@1P4چ'cM)hʱv,LZyǐRL2?R^jA7N;&|Pj" h/$~U9ʘ&]#C0Pd4c"jp>J]!i65jţ; ,h#-Wʛ.A}_[ytoi֎smrM=$њRb{+><| ^Bt.&!_;kzXF <ɍsU ֬&@} DuwRs[ZhW@Cl]%fXV@m{']MRFšQ~Q 9 PzX|7ԒAP:oBӇ2) Y8_DcI'}!q9"_R뗀 y(D?1)%i1QE6.jVD9-:Ldp*TBV}C> }1@lEМ`_Gd &ېp1Ak kU2 ՠEdi"m>vőlV >/\߻޵5}j:xճFÒŷѰ+u#!xg~\{XZTȣ*k3@4^>xVH.w.+ I# CL3a^_a: ~W d,B>ؐ%caغD'jwi*F߶nCZ7~Fy!_piXow%?m&cW͟5l rK=ͺASaYñegG6 "/injٵa̦*K"byǝ&R ,>q\;f$֘ aȥJʾ)0ob(( Yܒ|6YB[wu%c.[E@X|2[ۊwqҸ*c-,F6[i,%̎Ʒ.Eqa<*z#u(rǂxؾWmI{9g cNU:G04c: E и㟿;wsjsX?Tul=5aE M  6'[!gQC9]a'.C}<' \3ʈ(< [UyBE$ט=P%kƊc T)\YXʘ]GܮUAH{.,,ٞϢ[zΖ]nT:fGS7%z ά>גSV:EƟ"- ];P;JxM=Ӗ4E%9VAgC=2ߨUSN)E_Lx|1 43~I}cy\a '?Ʋ:@i]:CwM. <PK@@I=V%[>MQ!:ɟH%A!TOh /ljd4 9 &p^@oݨFy5l,TBA q̱#b3g7w0W[/b OețM䅽.-v@j~<[ҲohskhlZJ yy\!&+ۜNhSyi MYG(% )_bœG:0fc%8e~@injiOr>WEOSKF?B^{q8L3͘+0 (,u;X!tj.G)V"TeF>]y_J5GK2%H0U)P$*)s줷 xz'zU^v1om ev,PƆݷozgJq/x%L&){ Dx%:i[;{[c|z~2"ϖmU,4B&+͆y7 UbPhMwcv ]oDgxArb&-Lg*ȩs?29^ sAp)ylN%ƚe`^m*M^6ޗ?a Qr" o5c+sAG04yP\d S):&xwOM'RM}VD;_mđhC9d|CꃚhMu% ޞγ;+1YkďCz6$km%SjD:t0Өw+ҙH}o dUj+Ə RɑjopPw pj^]BW[Fk'ꪓ{%<!]晏i]ZZ$tyS[OFs (g"*:;oE,4) x*/I:UbGY_, Ը1A~ʵyk'z5Pc]7d8_L~%qVd؈?.9}fyl i籿zQK8N.M>֛I}T-׽!/$DRPvJ\gk\\8gg$Zѹ>ET6yN\ ,A(kfO+y3-0/'&s0"+u }ytH ➳3"s:ߓL'{I}MM^[L\U|[IY#bUckje?mX[=r_6{HrPQ` ]}NNaxHקJC}_H1q)&wgjYy@eG0砙xCon>Ɵj~,-:櫤%8Yi\ %~RS'}l3~ݡrL%BICi3]=m߁RgYT vn ȳʝ[Ɗc]g@V$lW\]} !,B;蘭4Vq`֪MNt1!g]m{AɵFmƸNYFG;eT gY*@h?-s Ù?Jt"${>L%+1'鼸CjvNtu+b'ZXQP唧*3̗9Qef2e6ˇ$(~HQFv+kyÎV6fOVDz(7i(Z.׀'8j&yGR!Dޣ*߮> 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 874 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 876 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 877 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0+Jb'$8B 8l[jWHL$Q;o.Z ̼7/o~:W{xPCWQb6;J^ǩv'-[~Gݾߣ#i6ڿRV_n84]֚̽e[sYͮi P[ L:?=v8|`4nh7u{QE sU5Y7{C]_?{B^QSu; 3jV՞d;&xD\20-0b# !ڇ\)&q)% 1ON"ۂ%480`rH%Dd#C K .%"l %RQ NLHI($ux-LJ@J!^H :ggM597F7FN|[{}&Ff*pdk_ΜN0VG9ʱwDK4X=CaCɁg2)4X(rb0/s4lƵ.b]ʌ[r> stream xmTn0CƆ@LE"jD;oƤjgy_xN{qV'wC&]\]]u>t\qxں7ŦmN7isƬ'k~G]?ߓ` 4;RV_n86]{̭֚u[sfߴ L:?v>4|`0nhWu}QE KU=5Yw߇l?N6jwwv Z/բ,ko{&PaffIq XMJ0LfhrdĥP> stream xmTn@Cx ^"#&W R ە7iSFyo.{a;M[ݱ;w}puUtjWowa読;|SltCɛz;nʽ4%<i$>57JN.n86]{̭֚u[ҏӫ(hߴ5g( L:?yv>ixgm7~д/"$(,v{F~{Tk#zv~Wa׾`R-r睉y?&xYF\20/0b# !ڇ\)&q)% 1ϹN"ۂ%481`rH%Dd#C k Ю%"l %RQ F'b=:S:,Rx( y]eѱԁ_[WS3+!Z af> 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:+@,B:6f{b\qeǂuN\슶̏R(ӞƐd7t-3>Y9ۈOI+ȕ״%>Fl)qԍtSTX8n9Ē+p9\/ڭ p)gdEKhe]NJXX.5 Z2XhX;^1G8%jI,sYg]Ò2⨫ybAOWOKN+QM?.<^+W.<\u>n(~t?\C endstream endobj 881 0 obj << /Length 699 /Filter /FlateDecode >> stream xmTn0CƆ@LE"j.RC~8iZ)Ayo7?nkNy$냛G׎ծU[7|SlfM[kwʽ5g x=i6;RV׵_n85]֚̽u[OsE͡i P{ LՑ @4=tb/yVvL MnݞArjwf4P׏ީFT]Nrî}sBZ2pmmR?\rs<, X#.KIɌCH'hjmJIQ09da"2rG~\5hגQv]`n @v)(A'b}qHI($ux-JBJ!^I :ggM597F7FN}Y{}&Ff.pdk_ ΜN0VG9ʱwDK4X=CaCɁg2)4X(rb0/s4lƵǮb]ˌ[r> stream xmTn0CƆ@LE"h.RC~8iZ)Ayo7?^$ŝPIs77EW]}==硫nTشxGɛz?{k۝=` 4vN߷u8NM>(s&`ywS0jzQshz+&TuS~Hxqq`P<+ OC톦}SWUn}@`T;P3qtj}w*5UWSܰo\ze \[3. 9ff ؤdF@!i @F\ ` H sn4ȶ` $(Ng 2R0zd9#Cb.k(@.0[Czr aà8SuX$Q:\CAfpGR~m%^!N%$h&՚R #ƿp'XϾ>AI }3Nh25gNE'bkkؿs %|V !3?fc91ӊ9|u 6ZcWCab d1׮eF-9Ag깐3Z=I= 6-7p?)pegT> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C0t endstream endobj 884 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C2t endstream endobj 518 0 obj << /Type /ObjStm /N 100 /First 935 /Length 5832 /Filter /FlateDecode >> stream x\ksF_3GUjl+Nr&~khtH* t|G7{NhDe8J9t 8j+z|뱊*VVJ p"+)=B%Q&81 [I,N\%{|%cvBvbʼn7KY)+Ñ W)в JWVGWt"3UZut+MX+EVVUG# .Tc+ ȱ` O MDW8A#1l:ʁk ) )@#%-Zq##F) R ER+8RH@F:&|$d`RPҐn>1j2)>IF$/:\UB#IJ%UH5 AmrtfI} iZ’*bB}ZHsG͋/Uso:-ӫwT~2vܟ7,6̓72eFXGɠiBVu ӌ{շVi|?{1oFƵ #d3҅ڐ}LۉP6|UmNIckMi5|0-Ҡ\-`)ڑ0tc vZ ""@0pikrUp` ₺"4O36IF.cOѣ!P)6: R"C!HqPl sDxhO Okt@ 8 `T쐆THDTp UԑFh'0Shm\m525bծf )kY#mwC1&h<,4 lޕB@=0im#"4b!f / r ˤw46* "}p8 7 .y `Fz*Uшt5}0 jN8i\M(G3) ]j!ȓ.yuE14Wo*ɋ v]j)aL(V}8.$!O=ĬVm ]!ML%<1&Uêy1ޮ3uF*Qlt9N |z#0irW:V4)4J"Y̮gEcHK m"dX>8CrG͓QWOGͯE<|2fѩi>MUh&3l]q]Z?noy{ܶuO hKo*QN޿Sm3¬UۦEä"a55Rl3rhkB,d:ŢˡoaQ@ェ<.(J0E^3`JYLdg}b>Sдz,,;,p<p(4*iC ˃s:x(xu5ܱu -=B2!L N( 7QnjVZ N1l:Qoۋ={rw/uVE]` ݛh'loNޢ̢̢̆̆̆T̆̆4̆̆t̆̆ ̆̆̆j]պ2iQ`d' VF+h:zmE}sQ~C\!㐻e/`{Fd;:(Qj@kGjd upt6W2n3}Õ+X+zE+yƕ ˁTzr%R\r%5ף;gls6W0 Cj0,Gjr,Gjr,Gjr,Gjr,GjrGjqGjqGjqO8繗6>pATQ(?eP2 ړ%s}'e"Lњ^Iρ+ɵ7-"+ Glj#oTiSer9dZiF!73繜@>Ѭ**te|伕} h3 hhxOP1? px;Lxvٶ~tظuIOnڗ}nFK8}׈ۈxpߴI`y5S.DcFK,_%r2H9@[I^ t% D8z,y/D=zBїwњ=2&x_fA̼Iě3˼d m^2%^2%^2%̷)OL!B߯ԉc{ZF0Zr+ H@՗5HX_r z~/y~Z0dkךW ï^[_} ~RRW/Bb}I/l4]3lEH!l_1qzy_ "33̐T'fw;tΡ,qUF JB\ $P49T#(i i)Rjc2YCCVۂCCVN5|^Tۮ^]sS./SwS>ư#bb3znņ,z δrfUlTlvMחe3Jf(bs#Rڹ0vz_I;u%C߄HoW!m}Pԗ"/kX/k[e)zB,`h(04p 6([Al( ,E[_|q{`#NEl}`iQ_#(A6|1`[ < 8}r '[&r\#-؜Pnx@!B2duM%P:XP:}W:%i/iH7U e(\FSYp`m-~ ~ ~ ̆~ ܆~`@a`m_l#/Ơz Zz@CAc=}wzz@/ʡM1z@aeE 6.ɝ:)aSf S ZoKhoуYLt ulDgT=iߔۥszH&|-4VtӎomVtwO%9[=yj]wkU{Y:X]"ˎ}ob[y7~mѵZ75X}ekUݙMo缃yr{N|n *s|P!npIIKJ&>.)Ql2v(DW3Qeu&-0o[.S5TfMIFW&WG)G^_r˹ Ht~ _:#Jc2N)V^wZ)p2^'y O=̓OKZպ}XTg 5F (%k)poq6.)ӣ%0E׎%]|]LM?\Q_eѲMPoͧ|2;oɈ=oy8A+lyn3>y|{Fd(wsDfŭ̍]4.+,YyKN_?:9KtG+R۞'0x3|>s]P{r_۸[:6%Ƽ-*&)=WbVr3z{oM.]-NG'g ki!hi)29)9J"'%=WV+ս9kfͲZ翜py|>pGwa۟xa I!S!EZ1HYG7ʖۤh9MW9;󗗧u"|>|6O'[s6 <4Q*쉸61n_4gWsXd i3LДOxz1~lϒ+ρh?f1 [~Ys\Ml>nhl>7_7g:ȑ~Տ/9?㒹ea)ÄÊ\171V@Z?4?n+d</&ft]b1^i~/ V ..ˁfϛhދ?!糋F%0_w />BWczuDN>LIG k Aw(l9F$ݞ ׷]NZn{u[\RеN;y;>M _q/M<m<~fw7p|lU60ZxeZ›1rsdmt+:5z/7tnWI E,MdxeS,L5ݴRU|,c57Jk5$o,*q:d:du&UB5^?Zb^8>^bVʽdA'ea%GNN IR<'z])zGX)zsf@k3L?NCm`Dw_9S!=jN9vHF2y͎do@`j:$ "4Xamc) C^4>*2É:Yz!6NIސ`7}y6tdT*Vn4ANخ֐5R|`Z 'wlcHnE.B#C:ۀdŶ ^4 쇨>oH?>@+BG( Zďs8'O{4]iE&['&]m qضڥ{(]Q}ڵFk}iT}Uݱ5 ]GG]}e0i_B_]t}keXn6\u + ´tn'3r~kR|s7|* endstream endobj 927 0 obj << /Producer (pdfTeX-1.40.25) /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.25 (TeX Live 2023/Debian) kpathsea version 6.3.5) >> endobj 889 0 obj << /Type /ObjStm /N 62 /First 514 /Length 2587 /Filter /FlateDecode >> stream xڕZߏܸ ~߿$HIeEC{I6N/){̶xIQ0sg:O]Љ?v8th\Gs;ΑwA\,#БAV"t;g:k0 ՕA|APOEw PzcE)^ P'Qyy%1t*lٕ,q`Eį5@:;$#aT  VK8HYy0XQp]4%f4$Ę(Z 'c0%^6bSs ZD$P#*,4KLƎHBi$Hxa6\!– d?Oݛ?<~:=߽ɏ_¶tyO.lxpϢ컸$d//ckaʋ+>/pcm\үд,>4[K{$q}135WuF+ǴվA1nj`8 pcWo@Vئ>4+oCMʪzfط).[YuF&MCp%hShlmH\#@ҍ|k]n\Fwc\Fs}r6uFc#aeڬKh$1ڛ 볇,_~ףJez6³+\5 Yʬm33)jo>޽^b+t|KL"@YCOnblN+s~n_L=("ORruҩ}䡧KP8nQ 6I@F`32)Oipkm>L=y pORYߛD}ej3mȑsb y;dѲpu2$6T@)CV]MJk~@ߴn>ib ]hK oʄG Vu3p vիJ<8FWA>aIKr o>Q.!L?oZ7vlf@Wu*c 4$Zk@22fz\)YH 3Yn '8m}iK?&I`0%[Bl~@ߴn.4%`3tw||>}9vBIKLUJŭHfT&@_d~ eF %ڡ.,BC<fl`-Ɖnh r!nhu`:<ک=c[=]I,RuD~l4ˢ6B ԩkjATb|zw~|})ZjB/[;[uz:UR KlpjRwR{P 5Qp+DE3⫐Qz^  p"^(EdA됝; N/wTD g;ך[^ &Q!_˗vB|_S5UzM٣%R_|XverMzrޱ*lNPJAJK.`C2 ƶ_/3^WnclS+{jW8g -rm5N* ӄJ -5U/H ×B,m:@Dt^ցMUy0MR  /c(Gj:-1@tX܌"kn[ob M<[O|-SXv哗ϙ;).*._ĥzmD\J&z7xmh#6]m#.5.U-yqEl%eB>ۧӳ^jyIߕJ/{OIL>> endstream endobj 928 0 obj << /Type /XRef /Index [0 929] /Size 929 /W [1 3 1] /Root 926 0 R /Info 927 0 R /ID [ ] /Length 2397 /Filter /FlateDecode >> stream x%wxW{ aB  !6aؑaEq=EG`ud$I'.$'ra-~Rj}ieA';QagB'|!ZvnqzPPa.VN%)Oۀilfq 5F PSK͆6Rk} V1dƛ0=ær1k~RCͦs8֏x6-E9TP9^kb2*cA Ի$ɵB,E 㡍 \dMrZi-ZTāY0a̅y0X aӖRXp4.FjlcȁMJcXYP[G%ZƽK /тNśE %1%E6Hv#aLStX$1aOZWż#aCErK\2vQ *8%؉PG뀼*ͳIS$M0j]Zn4*蒎ld'K'Q$8%'-K$/fnΡy"ӈE$/qK6^HS%ZG6֩%K:KjXwNJ2.f:94dQc+t!:zz ]+{@.^-dυv]l1UlbH]w2l#+0` r`ʌ2<QP X&qZzh0&B#df>s)0t3áCKãp,E HDfKo۞NoK>NJc.Vsͳet8w|bKHs[ ,HN 9@,B7zM /4+og/@J D*D asC{Vsh?F8W]WӊXʝkΒ@,Bs3[v)@"Bs+ZK %&8n]g?&35H ThJ X a!@ WVmd9,&`se"XAR`aͣt. 9AwzA|5:{dғOH;e8NV_glg^$(ξBl/Fl R;eEŅ/mM%OKq⪫ksl|0aعf%#pkqÿō;[nq&q+q8qJo?gow&~cxY#pW|Ad|_1_ ŷEuUSDRpKW}JӃn~ U0Xv_٢[>4ǯD.>5KDG]-32Q!ŠY]dV?~1Q31c0?[kmZ1t1z1Uqm-J ԂaR /U+9~IT[_Q o4ږWhW (H~vNۗH~>!,nLm'ȟ '$6.~m''38}8C)gjGgi?gM }~3زGl}Zϊ "^z6q)S|=__rgkk m6qڡ ߬[m|Gsx/]n]L=ڇnruIwLvv=ZS{9NkMwjkp֚RXkKRMZ٥λZs\kuYkKKԛ9-Q)NWh7KW8)N7:DʄV>`c0  à(` QP XqPPaLFnz'qpt endstream endobj startxref 287975 %%EOF AutoDoc-2026.05.03/doc/manual.six0000644000000000000000000004732415175510000013150 0ustar00#SIXFORMAT GapDocGAP HELPBOOKINFOSIXTMP := rec( encoding := "UTF-8", bookname := "AutoDoc", entries := [ [ "Title page", "0.0", [ 0, 0, 0 ], 1, 1, "title page", "X7D2C85EC87DD46E5" ], [ "Abstract", "0.0-1", [ 0, 0, 1 ], 43, 2, "abstract", "X7AA6C5737B711C89" ] , [ "Copyright", "0.0-2", [ 0, 0, 2 ], 49, 2, "copyright", "X81488B807F2A1CF1" ], [ "Acknowledgements", "0.0-3", [ 0, 0, 3 ], 57, 2, "acknowledgements", "X82A988D47DFAFCFA" ], [ "Table of Contents", "0.0-4", [ 0, 0, 4 ], 62, 3, "table of contents", "X8537FEB07AF2BEC8" ], [ "\033[1X\033[33X\033[0;-2YWhat \033[5XAutoDoc\033[105X\033[101X\027\033[1X\\ 027 offers\033[133X\033[101X", "1", [ 1, 0, 0 ], 1, 4, "what autodoc offers", "X786190217AE14EBF" ], [ "\033[1X\033[33X\033[0;-2YCore features\033[133X\033[101X", "1.1", [ 1, 1, 0 ], 11, 4, "core features", "X7A835D9779307F98" ], [ "\033[1X\033[33X\033[0;-2YAdopting \033[5XAutoDoc\033[105X\033[101X\027\\ 033[1X\027 incrementally\033[133X\033[101X", "1.2", [ 1, 2, 0 ], 32, 4, "adopting autodoc incrementally", "X8081E3BA7B3EC702" ], [ "\033[1X\033[33X\033[0;-2YWhere to continue\033[133X\033[101X", "1.3", [ 1, 3, 0 ], 57, 5, "where to continue", "X83D6D8B481C07CD8" ], [ "\033[1X\033[33X\033[0;-2YGetting started using \033[5XAutoDoc\033[105X\\ 033[101X\027\033[1X\027\033[133X\033[101X", "2", [ 2, 0, 0 ], 1, 6, "getting started using autodoc", "X7A0D7AA484F466E1" ], [ "\033[1X\033[33X\033[0;-2YChoose your workflow\033[133X\033[101X", "2.1", [ 2, 1, 0 ], 7, 6, "choose your workflow", "X7BEF736283D2A7A9" ], [ "\033[1X\033[33X\033[0;-2YCreating a package manual from scratch\033[133X\\ 033[101X", "2.2", [ 2, 2, 0 ], 22, 6, "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", "2.3", [ 2, 3, 0 ], 97, 7, "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", "2.4", [ 2, 4, 0 ], 190, 9, "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", "2.4-1", [ 2, 4, 1 ], 212, 9, "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", "2.4-2", [ 2, 4, 2 ], 252, 10, "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", "2.4-3", [ 2, 4, 3 ], 364, 11, "checklist for converting an existing gapdoc manual to use autodoc", "X83448D91868D7994" ], [ "\033[1X\033[33X\033[0;-2YScaffolds\033[133X\033[101X", "2.5", [ 2, 5, 0 ], 433, 12, "scaffolds", "X8524193D824CDE0D" ], [ "\033[1X\033[33X\033[0;-2YGenerating a title page\033[133X\033[101X", "2.5-1", [ 2, 5, 1 ], 436, 12, "generating a title page", "X7CF22DE28478316F" ], [ "\033[1X\033[33X\033[0;-2YGenerating the main XML file\033[133X\033[101X", "2.5-2", [ 2, 5, 2 ], 487, 13, "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", "2.5-3", [ 2, 5, 3 ], 514, 13, "what data is used from packageinfo.g?", "X799956EA85D3FC15" ], [ "\033[1X\033[33X\033[0;-2YEntities from \033[11XPackageInfo.g\033[111X\033[\ 101X\027\033[1X\027 and scaffold options\033[133X\033[101X", "2.5-4", [ 2, 5, 4 ], 572, 14, "entities from packageinfo.g and scaffold options" , "X79EAEF277DD1FAE1" ], [ "\033[1X\033[33X\033[0;-2YWorksheets\033[133X\033[101X", "2.6", [ 2, 6, 0 ], 589, 15, "worksheets", "X801D4A2F8292704C" ], [ "\033[1X\033[33X\033[0;-2Y\033[5XAutoDoc\033[105X\033[101X\027\033[1X\027 d\ ocumentation comments\033[133X\033[101X", "3", [ 3, 0, 0 ], 1, 16, "autodoc documentation comments", "X87668C487B1A2094" ], [ "\033[1X\033[33X\033[0;-2YDocumenting declarations\033[133X\033[101X", "3.1", [ 3, 1, 0 ], 46, 16, "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", "3.1-1", [ 3, 1, 1 ], 54, 17, "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", "3.1-2", [ 3, 1, 2 ], 61, 17, "returns ret val", "X7EFF79F47BE24F78" ], [ "\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" , "3.1-3", [ 3, 1, 3 ], 68, 17, "arguments args", "X81DAA454857F7971" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@ItemType \033[3Xkind\033[103X\033[101X\\ 027\033[1X\027\033[10X\027\033[110X\033[101X\027\033[1X\027\033[133X\033[101X" , "3.1-4", [ 3, 1, 4 ], 82, 17, "itemtype kind", "X852A9FCA7AB6EC4E" ] , [ "\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" , "3.1-5", [ 3, 1, 5 ], 115, 17, "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" , "3.1-6", [ 3, 1, 6 ], 121, 18, "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", "3.1-7", [ 3, 1, 7 ], 168, 18, "chapterinfo chapter section", "X78938EE37A532FFA" ], [ "\033[1X\033[33X\033[0;-2YOther documentation comments\033[133X\033[101X", "3.2", [ 3, 2, 0 ], 190, 19, "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" , "3.2-1", [ 3, 2, 1 ], 197, 19, "chapter name", "X823E613385D09F6F" ] , [ "\033[1X\033[33X\033[0;-2Y\033[10X@Appendix \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" , "3.2-2", [ 3, 2, 2 ], 234, 19, "appendix name", "X83163DA586882825" ], [ "\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" , "3.2-3", [ 3, 2, 3 ], 250, 19, "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\ ", "3.2-4", [ 3, 2, 4 ], 267, 20, "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", "3.2-5", [ 3, 2, 5 ], 287, 20, "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", "3.2-6", [ 3, 2, 6 ], 297, 20, "endgroup", "X7C17EB007FD42C87" ], [ "\033[1X\033[33X\033[0;-2Y@GroupTitle \033[3Xtitle\033[103X\033[101X\027\\ 033[1X\027\033[133X\033[101X", "3.2-7", [ 3, 2, 7 ], 317, 21, "grouptitle title", "X82FB96F37FAE8167" ], [ "\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", "3.2-8", [ 3, 2, 8 ], 324, 21, "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", "3.2-9", [ 3, 2, 9 ], 359, 21, "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", "3.2-10", [ 3, 2, 10 ], 396, 22, "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", "3.2-11", [ 3, 2, 11 ], 403, 22, "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", "3.2-12", [ 3, 2, 12 ], 411, 22, "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", "3.2-13", [ 3, 2, 13 ], 425, 22, "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", "3.2-14", [ 3, 2, 14 ], 465, 23, "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", "3.2-15", [ 3, 2, 15 ], 481, 23, "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", "3.2-16", [ 3, 2, 16 ], 496, 23, "notlatex text beginnotlatex and endnotlatex", "X7EF303147F1BCC22" ], [ "\033[1X\033[33X\033[0;-2Y\033[10X@Index \033[3Xkey\033[103X\033[101X\027\\ 033[1X\027\033[10X\027 [\033[3Xentry text\033[103X\033[101X\027\033[1X\027\033\ [10X\027]\033[110X\033[101X\027\033[1X\027\033[133X\033[101X", "3.2-17", [ 3, 2, 17 ], 511, 24, "index key [entry text]", "X82FD2EEB788E76F1" ], [ "\033[1X\033[33X\033[0;-2YTitle page commands\033[133X\033[101X", "3.3", [ 3, 3, 0 ], 521, 24, "title page commands", "X841E3AD584F5385C" ], [ "\033[1X\033[33X\033[0;-2YPlain text files\033[133X\033[101X", "3.4", [ 3, 4, 0 ], 556, 24, "plain text files", "X828AE38F80CB02E7" ], [ "\033[1X\033[33X\033[0;-2YGrouping\033[133X\033[101X", "3.5", [ 3, 5, 0 ], 648, 26, "grouping", "X7D7A38F87BC40C48" ], [ "\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", "3.6", [ 3, 6, 0 ], 710, 27, "markdown-like formatting of text in autodoc", "X79558A2F7FE187B4" ], [ "\033[1X\033[33X\033[0;-2YLists\033[133X\033[101X", "3.6-1", [ 3, 6, 1 ], 719, 27, "lists", "X7B256AE5780F140A" ], [ "\033[1X\033[33X\033[0;-2YMath modes\033[133X\033[101X", "3.6-2", [ 3, 6, 2 ], 757, 28, "math modes", "X871412737A0E12E2" ], [ "\033[1X\033[33X\033[0;-2YEmphasize\033[133X\033[101X", "3.6-3", [ 3, 6, 3 ], 778, 28, "emphasize", "X7ED0330479146EFC" ], [ "\033[1X\033[33X\033[0;-2YInline code\033[133X\033[101X", "3.6-4", [ 3, 6, 4 ], 796, 28, "inline code", "X838CCDEB7E0ECEE2" ], [ "\033[1X\033[33X\033[0;-2YFenced code blocks\033[133X\033[101X", "3.6-5", [ 3, 6, 5 ], 809, 28, "fenced code blocks", "X7C0629B183765575" ], [ "\033[1X\033[33X\033[0;-2YDeprecated commands\033[133X\033[101X", "3.7", [ 3, 7, 0 ], 851, 29, "deprecated commands", "X78CA9E5C7F494C19" ], [ "\033[1X\033[33X\033[0;-2YReference\033[133X\033[101X", "4", [ 4, 0, 0 ], 1, 30, "reference", "X782AAE4E86411FF4" ], [ "\033[1X\033[33X\033[0;-2YAutoDoc worksheets\033[133X\033[101X", "4.1", [ 4, 1, 0 ], 4, 30, "autodoc worksheets", "X80ED3C2A78146AD1" ], [ "\033[1X\033[33X\033[0;-2YThe AutoDoc() function\033[133X\033[101X", "4.2", [ 4, 2, 0 ], 37, 30, "the autodoc function", "X863584DB8497D8BA" ], [ "Bibliography", "bib", [ "Bib", 0, 0 ], 1, 37, "bibliography", "X7A6F98FD85F02BFE" ], [ "References", "bib", [ "Bib", 0, 0 ], 1, 37, "references", "X7A6F98FD85F02BFE" ], [ "Index", "ind", [ "Ind", 0, 0 ], 1, 38, "index", "X83A0356F839C696F" ], [ "\033[11Xmakedoc.g\033[111X", "2.2", [ 2, 2, 0 ], 22, 6, "makedoc.g", "X7BFBC6907B26AA95" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "", "2.4-3", [ 2, 4, 3 ], 364, 11, "", "X83448D91868D7994" ], [ "\033[10X@Description \033[3Xdescr\033[103X\033[10X\027\033[110X", "3.1-1", [ 3, 1, 1 ], 54, 17, "description descr", "X7F1D85188262A827" ] , [ "\033[10X@Returns \033[3Xret_val\033[103X\033[10X\027\033[110X", "3.1-2", [ 3, 1, 2 ], 61, 17, "returns ret_val", "X7EFF79F47BE24F78" ], [ "\033[10X@Arguments \033[3Xargs\033[103X\033[10X\027\033[110X", "3.1-3", [ 3, 1, 3 ], 68, 17, "arguments args", "X81DAA454857F7971" ], [ "\033[10X@ItemType \033[3Xkind\033[103X\033[10X\027\033[110X", "3.1-4", [ 3, 1, 4 ], 82, 17, "itemtype kind", "X852A9FCA7AB6EC4E" ], [ "\033[10X@Group \033[3Xgrpname\033[103X\033[10X\027\033[110X", "3.1-5", [ 3, 1, 5 ], 115, 17, "group grpname", "X8677FE8F80C00B14" ], [ "\033[10X@Label \033[3Xlabel\033[103X\033[10X\027\033[110X", "3.1-6", [ 3, 1, 6 ], 121, 18, "label label", "X7B0E20A27D64DF6F" ], [ "\033[10X@ChapterInfo\033[110X", "3.1-7", [ 3, 1, 7 ], 168, 18, "chapterinfo", "X78938EE37A532FFA" ], [ "\033[10X@Chapter\033[110X", "3.2-1", [ 3, 2, 1 ], 197, 19, "chapter", "X823E613385D09F6F" ], [ "\033[10X@ChapterLabel\033[110X", "3.2-1", [ 3, 2, 1 ], 197, 19, "chapterlabel", "X823E613385D09F6F" ], [ "\033[10X@ChapterTitle\033[110X", "3.2-1", [ 3, 2, 1 ], 197, 19, "chaptertitle", "X823E613385D09F6F" ], [ "\033[10X@Appendix\033[110X", "3.2-2", [ 3, 2, 2 ], 234, 19, "appendix", "X83163DA586882825" ], [ "\033[10X@Section\033[110X", "3.2-3", [ 3, 2, 3 ], 250, 19, "section", "X78AA98BA7E0635D0" ], [ "\033[10X@SectionLabel\033[110X", "3.2-3", [ 3, 2, 3 ], 250, 19, "sectionlabel", "X78AA98BA7E0635D0" ], [ "\033[10X@SectionTitle\033[110X", "3.2-3", [ 3, 2, 3 ], 250, 19, "sectiontitle", "X78AA98BA7E0635D0" ], [ "\033[10X@Subsection\033[110X", "3.2-4", [ 3, 2, 4 ], 267, 20, "subsection", "X7FD77434802A3580" ], [ "\033[10X@SubsectionLabel\033[110X", "3.2-4", [ 3, 2, 4 ], 267, 20, "subsectionlabel", "X7FD77434802A3580" ], [ "\033[10X@SubsectionTitle\033[110X", "3.2-4", [ 3, 2, 4 ], 267, 20, "subsectiontitle", "X7FD77434802A3580" ], [ "\033[10X@BeginGroup\033[110X", "3.2-5", [ 3, 2, 5 ], 287, 20, "begingroup", "X7D3060C17EDBCED1" ], [ "\033[10X@EndGroup\033[110X", "3.2-6", [ 3, 2, 6 ], 297, 20, "endgroup", "X7C17EB007FD42C87" ], [ "\033[10X@GroupTitle\033[110X", "3.2-7", [ 3, 2, 7 ], 317, 21, "grouptitle", "X82FB96F37FAE8167" ], [ "\033[10X@BeginExample\033[110X", "3.2-8", [ 3, 2, 8 ], 324, 21, "beginexample", "X83D6DA3B83D3436C" ], [ "\033[10X@EndExample\033[110X", "3.2-8", [ 3, 2, 8 ], 324, 21, "endexample", "X83D6DA3B83D3436C" ], [ "\033[10X@BeginExampleSession\033[110X", "3.2-9", [ 3, 2, 9 ], 359, 21, "beginexamplesession", "X861E2E778510CAF7" ], [ "\033[10X@EndExampleSession\033[110X", "3.2-9", [ 3, 2, 9 ], 359, 21, "endexamplesession", "X861E2E778510CAF7" ], [ "\033[10X@BeginLog\033[110X", "3.2-10", [ 3, 2, 10 ], 396, 22, "beginlog", "X81A2D44D834C0A17" ], [ "\033[10X@EndLog\033[110X", "3.2-10", [ 3, 2, 10 ], 396, 22, "endlog", "X81A2D44D834C0A17" ], [ "\033[10X@BeginLogSession\033[110X", "3.2-11", [ 3, 2, 11 ], 403, 22, "beginlogsession", "X7BADE876794FF309" ], [ "\033[10X@EndLogSession\033[110X", "3.2-11", [ 3, 2, 11 ], 403, 22, "endlogsession", "X7BADE876794FF309" ], [ "\033[10X@DoNotReadRestOfFile\033[110X", "3.2-12", [ 3, 2, 12 ], 411, 22, "donotreadrestoffile", "X78DC644E8519280C" ], [ "\033[10X@BeginChunk \033[3Xname\033[103X\033[10X\027\033[110X", "3.2-13", [ 3, 2, 13 ], 425, 22, "beginchunk name", "X83C01F9B7FA1C973" ], [ "\033[10X@EndChunk\033[110X", "3.2-13", [ 3, 2, 13 ], 425, 22, "endchunk", "X83C01F9B7FA1C973" ], [ "\033[10X@InsertChunk \033[3Xname\033[103X\033[10X\027\033[110X", "3.2-13", [ 3, 2, 13 ], 425, 22, "insertchunk name", "X83C01F9B7FA1C973" ], [ "\033[10X@BeginCode \033[3Xname\033[103X\033[10X\027\033[110X", "3.2-14", [ 3, 2, 14 ], 465, 23, "begincode name", "X7D3671AF86B995B9" ], [ "\033[10X@EndCode\033[110X", "3.2-14", [ 3, 2, 14 ], 465, 23, "endcode", "X7D3671AF86B995B9" ], [ "\033[10X@InsertCode \033[3Xname\033[103X\033[10X\027\033[110X", "3.2-14", [ 3, 2, 14 ], 465, 23, "insertcode name", "X7D3671AF86B995B9" ], [ "\033[10X@LatexOnly \033[3Xtext\033[103X\033[10X\027\033[110X", "3.2-15", [ 3, 2, 15 ], 481, 23, "latexonly text", "X8033B34F80A12A10" ] , [ "\033[10X@BeginLatexOnly\033[110X", "3.2-15", [ 3, 2, 15 ], 481, 23, "beginlatexonly", "X8033B34F80A12A10" ], [ "\033[10X@EndLatexOnly\033[110X", "3.2-15", [ 3, 2, 15 ], 481, 23, "endlatexonly", "X8033B34F80A12A10" ], [ "\033[10X@NotLatex \033[3Xtext\033[103X\033[10X\027\033[110X", "3.2-16", [ 3, 2, 16 ], 496, 23, "notlatex text", "X7EF303147F1BCC22" ], [ "\033[10X@BeginNotLatex\033[110X", "3.2-16", [ 3, 2, 16 ], 496, 23, "beginnotlatex", "X7EF303147F1BCC22" ], [ "\033[10X@EndNotLatex\033[110X", "3.2-16", [ 3, 2, 16 ], 496, 23, "endnotlatex", "X7EF303147F1BCC22" ], [ "\033[10X@Index \033[3Xkey\033[103X\033[10X\027 [\033[3Xentry text\033[103X\ \033[10X\027]\033[110X", "3.2-17", [ 3, 2, 17 ], 511, 24, "index key [entry text]", "X82FD2EEB788E76F1" ], [ "\033[2XAutoDocWorksheet\033[102X", "4.1-1", [ 4, 1, 1 ], 7, 30, "autodocworksheet", "X809FE4137C08B28D" ], [ "\033[2XAutoDoc\033[102X", "4.2-1", [ 4, 2, 1 ], 40, 30, "autodoc", "X7CBD8AAF7DCEF352" ], [ "\033[2XInfoAutoDoc\033[102X", "4.2-2", [ 4, 2, 2 ], 443, 36, "infoautodoc", "X81F946A785BA3D6E" ] ] ); AutoDoc-2026.05.03/doc/nocolorprompt.css0000644000000000000000000000031315175510000014560 0ustar00 /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000000; font-weight: normal; } span.GAPbrkprompt { color: #000000; font-weight: normal; } span.GAPinput { color: #000000; } AutoDoc-2026.05.03/doc/ragged.css0000644000000000000000000000023115175510000013073 0ustar00/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { text-align: left; } AutoDoc-2026.05.03/doc/rainbow.js0000644000000000000000000000533615175510000013142 0ustar00 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-2026.05.03/doc/times.css0000644000000000000000000000026115175510000012766 0ustar00/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { font-family: Times,Times New Roman,serif; } AutoDoc-2026.05.03/doc/title.xml0000644000000000000000000000256515175510000013007 0ustar00 AutoDoc Generate documentation from &GAP; source code 2026.05.03 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
3 May 2026 &AutoDoc; is a &GAP; package whose purpose is to aid &GAP; package authors in creating and maintaining the documentation of their packages. ©right; 2012-2026 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-2026.05.03/doc/toggless.css0000644000000000000000000000167215175510000013503 0ustar00/* 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-2026.05.03/doc/toggless.js0000644000000000000000000000420515175510000013322 0ustar00/* 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-2026.05.03/gap/0000755000000000000000000000000015175510000011136 5ustar00AutoDoc-2026.05.03/gap/AutoDocMainFunction.gd0000644000000000000000000000547115175510000015332 0ustar00# 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_XML_HEADER", Concatenation( "\n\n", "\n" ) ); DeclareGlobalFunction( "AUTODOC_SetIfMissing" ); DeclareGlobalFunction( "AUTODOC_APPEND_STRING_ITERATIVE" ); DeclareGlobalFunction( "AUTODOC_MergeRecords" ); DeclareGlobalFunction( "AutoDocScanFiles" ); ## Global option record BindGlobal( "_AUTODOC_GLOBAL_OPTION_RECORD", rec( AutoDocMainFile := "_AutoDocMainFile.xml" ) ); ## ## 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" ); #! @Chapter Reference #! @Section AutoDoc worksheets #! @SectionLabel AutoDocWorksheet #! @Description #! The purpose of this function is to create stand-alone PDF and HTML files #! using &AutoDoc; without associating them with a package. #!

#! Instead of a package directory, you pass one filename or a list of #! filenames containing &AutoDoc; text from which the document is created. #! Settings are supplied via an optional record using the same entries as #! the optrec argument of . Alternatively, you may #! omit filenames and specify the files via optrec.autodoc.files. #!

#! A simple worksheet file can define title-page information and chapter #! content directly in the source file, including example blocks. #! If this is stored in worksheet.g, you can generate documentation via #! @BeginLogSession #! AutoDocWorksheet( "worksheet.g" ); #! @EndLogSession #! This creates documentation in a doc subdirectory of the current directory. #!

#! Since worksheets do not have a PackageInfo.g, title-page fields are #! specified directly in the worksheet file. #!

#! For backwards compatibility, worksheet calls still accept GAP global #! options for specifying the option-record entries such as #! dir, scaffold, autodoc, gapdoc, and #! extract_examples. #! However, this feature is deprecated. #! @Arguments [filenames,] [optrec] DeclareGlobalFunction( "AutoDocWorksheet" ); AutoDoc-2026.05.03/gap/AutoDocMainFunction.gi0000644000000000000000000003746115175510000015343 0ustar00# 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( 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; chapter_name := Concatenation( pkgname, "_automatic_generated_documentation" ); default_chapter_record := rec(); list_of_types := Set( List( RecNames( AUTODOC_ITEM_TYPE_INFO ), n -> AUTODOC_ITEM_TYPE_INFO.( n ).chapter_bucket ) ); 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, ent, val, entities; entities := rec(); if IsBound( opt.entities ) then entities := opt.entities; 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 # (sort the key names to get stable order across all GAP versions) for ent in Set(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, main_xml_file, dir, opt ) local filestream, i; if not EndsWith( main_xml_file, ".xml" ) then main_xml_file := Concatenation( main_xml_file, ".xml" ); fi; # open the target XML file filestream := AUTODOC_OutputTextFile( dir, 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.autodoc_appendix_file ) and ( not IsBound( opt.appendix ) or not opt.autodoc_appendix_file in opt.appendix ) then AppendTo( filestream, "<#Include SYSTEM \"", opt.autodoc_appendix_file, "\">\n" ); 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, parsed_date, NormalizeTitlePageContent; 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; # Parser state can leave title-page fields as a list of lines. Normalize # them here so trailing blank lines do not leak into output or filenames, # while still preserving intentional internal line breaks for multiline fields. NormalizeTitlePageContent := function( content ) local normalized; if IsString( content ) then content := [ content ]; fi; normalized := List( content, line -> StripBeginEnd( line, "\n\r" ) ); while Length( normalized ) > 0 and IsString( Last( normalized ) ) and StripBeginEnd( Last( normalized ), " \t\r\n" ) = "" do Remove( normalized ); od; if Length( normalized ) = 1 then return normalized[ 1 ]; fi; return normalized; 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, NormalizeTitlePageContent( argument_rec.( i ) ) ); fi; od; if IsBound( argument_rec.Author ) then for i in List( argument_rec.Author, NormalizeTitlePageContent ) do if not IsString( i ) or StripBeginEnd( i, " \t\r\n" ) <> "" then OutWithTag( "Author", i ); fi; od; fi; if IsBound( argument_rec.Date ) then if IsString( argument_rec.Date ) then argument_rec.Date := Chomp( argument_rec.Date ); # remove trailing newlines, if present # PackageInfo.g dates are normalized, but @Date should also allow # free-form text when the input is not one of the supported date formats. parsed_date := AUTODOC_ParseDate( argument_rec.Date ); if parsed_date <> fail then argument_rec.Date := AUTODOC_FormatDate( parsed_date ); fi; fi; OutWithTag( "Date", NormalizeTitlePageContent( argument_rec.Date ) ); fi; for i in [ "Address", "Abstract", "Copyright", "Acknowledgements", "Colophon" ] do if IsBound( argument_rec.( i ) ) then OutWithTag( i, NormalizeTitlePageContent( argument_rec.( i ) ) ); fi; od; Out( "" ); CloseStream( filestream ); 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 opt, val; if Length( arg ) = 2 then opt := Remove( arg ); else opt := rec( ); fi; val := ValueOption( "scaffold" ); if val <> fail then opt.scaffold := val; elif not IsBound(opt.scaffold) then opt.scaffold := rec(); fi; AUTODOC_SetIfMissing( opt.scaffold, "index", false ); if Length( arg ) = 1 then val := ValueOption( "autodoc" ); if val <> fail then opt.autodoc := val; elif not IsBound(opt.autodoc) then opt.autodoc := rec(); fi; if IsString( arg[ 1 ] ) then arg[ 1 ] := [ arg[ 1 ] ]; fi; if IsBound( opt.autodoc.files ) then Append( opt.autodoc.files, arg[ 1 ] ); else opt.autodoc.files := arg[ 1 ]; fi; fi; AutoDoc_INTERN( true, "AutoDocWorksheet", rec( ), DirectoryCurrent( ), opt ); 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; Info(InfoAutoDoc, 1, "Extracting manual examples for ", pkgname, " package ..."); lpkgname := LowercaseString(pkgname); lpkgname := ReplacedString(lpkgname, " ", "_"); if not EndsWith(main, ".xml") then main := Concatenation( main, ".xml" ); fi; tst:=ExtractExamples( docdir, main, files, opt.units ); Info(InfoAutoDoc, 1, Length(tst), " ", LowercaseString( opt.units ), "s detected"); pkgdirString := Filename(pkgdir, ""); if IsDirectory( opt.subdir ) then tstdir := Filename( opt.subdir, "" ); else tstdir := Filename( pkgdir, opt.subdir ); fi; 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 Info(InfoAutoDoc, 1, opt.units, " ", i, "..."); if Length( tst[i] ) = 0 then Info(InfoAutoDoc, 1, "no examples"); 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 ); Info(InfoAutoDoc, 1, "extracted ", Length(ch), " examples"); od; end); AutoDoc-2026.05.03/gap/DocumentationTree.gd0000644000000000000000000000604115175510000015104 0ustar00# 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, "mutable" ); DeclareAttribute( "ChapterInfo", IsTreeForDocumentationNode ); DeclareAttribute( "GroupName", IsTreeForDocumentationNode ); ###################################### ## ## Constructors ## ###################################### DeclareOperation( "DocumentationTree", [ ] ); DeclareOperation( "StructurePartInTree", [ IsTreeForDocumentation, IsList ] ); DeclareOperation( "ChapterInTree", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "AppendixInTree", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "SectionInTree", [ IsTreeForDocumentation, IsString, IsString ] ); DeclareOperation( "SubsectionInTree", [ IsTreeForDocumentation, IsString, IsString, IsString ] ); DeclareOperation( "DocumentationExample", [ IsString ] ); DeclareOperation( "DocumentationVerbatim", [ IsString, IsRecord, IsList ] ); DeclareOperation( "DocumentationChunk", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "DocumentationManItem", [ ] ); 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 ] ); DeclareOperation( "WriteDocumentation", [ IsTreeForDocumentationNode, IsStream ] ); DeclareOperation( "WriteDocumentation", [ IsList, IsStream ] ); DeclareOperation( "WriteDocumentation", [ IsTreeForDocumentationNode, IsStream, IsDirectory ] ); AutoDoc-2026.05.03/gap/DocumentationTree.gi0000644000000000000000000005115515175510000015117 0ustar00# 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" ); BindGlobal( "AUTODOC_IsSafeGeneratedLabelCharacter", function( c ) local code; code := IntChar( c ); return code >= 32 and code <> 127 and not c in "/\\&<>\";"; end ); BindGlobal( "AUTODOC_NormalizeGeneratedLabel", function( label ) return Filtered( ReplacedString( label, " ", "_" ), AUTODOC_IsSafeGeneratedLabelCharacter ); end ); BindGlobal( "AUTODOC_IsSafeGeneratedFilenameCharacter", function( c ) local code; code := IntChar( c ); return code >= 32 and code <> 127 and not c in "/\\:"; end ); 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( "IsTreeForDocumentationVerbatimNodeRep", IsTreeForDocumentationNodeRep, [ ] ); BindGlobal( "TheTypeOfDocumentationTreeVerbatimNodes", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationVerbatimNodeRep ) ); ################################### ## ## 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; return AUTODOC_NormalizeGeneratedLabel( label ); end ); ################################### ## ## Constructors ## ################################### ## InstallMethod( DocumentationTree, [ ], function( ) local tree; tree := rec( content := [ ], # a list of nodes cached_nodes_by_label := rec( ), node_name_iterator := 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!.cached_nodes_by_label.( label ) ) then return tree!.cached_nodes_by_label.( label ); fi; parent := StructurePartInTree( tree, context{[1..Length(context)-1]} ); new_node := rec( content := [ ], name := Last( 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!.cached_nodes_by_label.( label ) := new_node; Add( parent!.content, new_node ); return new_node; end ); ## InstallMethod( DocumentationExample, [ IsString ], function( element_name ) local node; node := DocumentationVerbatim( element_name, rec( ), [ ] ); node!.closing_separator := "\n\n"; return node; end ); ## InstallMethod( DocumentationVerbatim, [ IsString, IsRecord, IsList ], function( element_name, attributes, content ) local node; node := rec( element_name := element_name, attributes := StructuralCopy( attributes ), content := ShallowCopy( content ) ); node!.closing_separator := "\n"; ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeVerbatimNodes ); 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 := [ ], content_source_positions := [ ] ); ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeChunkNodes, Label, name ); node!.is_defined := false; node!.is_inserted := false; tree!.chunks.( name ) := node; return node; end ); ## InstallMethod( DocumentationManItem, [ ], function( ) local node; node := rec( description := [ ], description_source_positions := [ ], return_value := [ ], return_value_source_positions := [ ] ); ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeNodesForManItem ); node!.content := node!.description; node!.content_source_field := "description_source_positions"; return node; end ); InstallMethod( DocumentationGroup, [ IsTreeForDocumentation, IsString ], function( tree, group_name ) local group, name; name := Concatenation( "GROUP_", group_name ); if IsBound( tree!.cached_nodes_by_label.( name ) ) then return tree!.cached_nodes_by_label.( name ); fi; group := rec( content := [ ], content_source_positions := [ ] ); ObjectifyWithAttributes( group, TheTypeOfDocumentationTreeNodesForGroup, Label, name ); tree!.cached_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, context_node; name := Concatenation( "GROUP_", group_name ); if IsBound( tree!.cached_nodes_by_label.( name ) ) then return tree!.cached_nodes_by_label.( name ); fi; context_node := StructurePartInTree( tree, context ); group := DocumentationGroup( tree, group_name ); Add( context_node, 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 context_node; context_node := StructurePartInTree( tree, context ); 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( AppendixInTree, [ IsTreeForDocumentation, IsString ], function( tree, name ) local node; node := ChapterInTree( tree, name ); node!.is_appendix := true; SetLabel( node, Concatenation( "Appendix_", AUTODOC_NormalizeGeneratedLabel( name ) ) ); return node; 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( "AUTODOC_ConvertHeadingToGAPDocXML", function( heading, source_position ) local converted_heading; converted_heading := AUTODOC_ConvertMarkdownToGAPDocXML( [ NormalizedWhitespace( heading ) ], [ source_position ] ); if not ForAll( converted_heading, IsString ) then Error( "headings must convert to inline GAPDoc XML" ); fi; converted_heading := Filtered( converted_heading, piece -> piece <> "" and piece <> "

" ); return JoinStringsWithSeparator( converted_heading, "" ); end ); BindGlobal( "AUTODOC_WriteStructuralNode", function( node, element_name, stream ) local heading, title_source_position; if ForAll( node!.content, IsEmptyNode ) then return false; fi; if IsBound( node!.title_string ) then heading := NormalizedWhitespace( node!.title_string ); title_source_position := node!.title_string_source_position; else heading := ReplacedString( node!.name, "_", " " ); title_source_position := fail; fi; heading := AUTODOC_ConvertHeadingToGAPDocXML( heading, title_source_position ); AppendTo( stream, "<", element_name, " Label=\"", Label( node ), "\">\n" ); AppendTo( stream, "", heading, "\n\n" ); WriteDocumentation( node!.content, stream ); AppendTo( stream, "\n\n" ); return true; end ); BindGlobal( "AUTODOC_ChapterFilename", function( node ) local filename; # Strip characters that are known to cause trouble in generated filenames. # In particular, GAP rejects ':', '\' and '/' as they are potentially path # separators. filename := Filtered( Label( node ), AUTODOC_IsSafeGeneratedFilenameCharacter ); return Concatenation( "_", filename, ".xml" ); end ); BindGlobal( "WriteChunks", function( tree, path_to_xmlfiles ) 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 ); if current_chunk!.is_defined = true and current_chunk!.is_inserted = false then Info( InfoAutoDoc, 1, "WARNING: chunk ", current_chunk_name, " was defined but never inserted" ); elif current_chunk!.is_defined = false and current_chunk!.is_inserted = true then Info( InfoAutoDoc, 1, "WARNING: chunk ", current_chunk_name, " was inserted but never defined" ); fi; AppendTo( chunks_stream, "<#GAPDoc Label=\"", current_chunk_name, "\">\n" ); if IsBound( current_chunk!.content ) then AUTODOC_WriteDocumentationListWithSource( current_chunk!.content, current_chunk!.content_source_positions, chunks_stream ); fi; AppendTo( chunks_stream, "\n<#/GAPDoc>\n" ); od; CloseStream( chunks_stream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentation, IsDirectory ], function( tree, path_to_xmlfiles ) local stream, appendix_stream, i; stream := AUTODOC_OutputTextFile( path_to_xmlfiles, _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile ); AppendTo( stream, AUTODOC_XML_HEADER ); appendix_stream := fail; for i in tree!.content do if IsTreeForDocumentationNodeForChapterRep( i ) then if IsBound( i!.is_appendix ) and i!.is_appendix = true then if appendix_stream = fail then appendix_stream := AUTODOC_OutputTextFile( path_to_xmlfiles, "_AutoDocAppendicesMainFile.xml" ); AppendTo( appendix_stream, AUTODOC_XML_HEADER ); fi; WriteDocumentation( i, appendix_stream, path_to_xmlfiles ); else WriteDocumentation( i, stream, path_to_xmlfiles ); fi; else Error( "this should never happen" ); fi; od; if appendix_stream <> fail then CloseStream( appendix_stream ); fi; WriteChunks( tree, path_to_xmlfiles ); # Workaround for issue #65 if IsEmpty( tree!.content ) then AppendTo( stream, " \n" ); fi; CloseStream( stream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForChapterRep, IsStream, IsDirectory ], function( node, stream, path_to_xmlfiles ) local filename, chapter_stream, element_name; if ForAll( node!.content, IsEmptyNode ) then return; fi; filename := AUTODOC_ChapterFilename( node ); chapter_stream := AUTODOC_OutputTextFile( path_to_xmlfiles, filename ); AppendTo( stream, "<#Include SYSTEM \"", filename, "\">\n" ); AppendTo( chapter_stream, AUTODOC_XML_HEADER ); element_name := "Chapter"; if IsBound( node!.is_appendix ) and node!.is_appendix = true then element_name := "Appendix"; fi; AUTODOC_WriteStructuralNode( node, element_name, chapter_stream ); CloseStream( chapter_stream ); end ); ## InstallMethod( WriteDocumentation, [ IsList, IsStream ], function( node_list, filestream ) local current_string_list, i, FlushConvertedStrings; FlushConvertedStrings := function() if current_string_list = [ ] then return; fi; AUTODOC_WriteStringListWithSource( current_string_list, fail, filestream ); current_string_list := [ ]; end; 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 FlushConvertedStrings(); WriteDocumentation( node_list[ i ], filestream ); fi; od; FlushConvertedStrings(); end ); ## InstallMethod( WriteDocumentation, [ IsString, IsStream ], function( text, filestream ) ## 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 ], function( node, filestream ) AUTODOC_WriteStructuralNode( node, "Section", filestream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForSubsectionRep, IsStream ], function( node, filestream ) AUTODOC_WriteStructuralNode( node, "Subsection", filestream ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForManItemRep, IsStream ], function( node, filestream ) AutoDoc_WriteDocEntry( filestream, [ node ], fail ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForGroupRep, IsStream ], function( node, filestream ) local heading; heading := fail; if IsBound( node!.title_string ) then heading := node!.title_string; fi; AutoDoc_WriteDocEntry( filestream, node!.content, heading ); end ); ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationChunkNodeRep, IsStream ], function( node, filestream ) node!.is_inserted := true; WriteDocumentation( Concatenation( "<#Include Label=\"", Label( node ), "\">" ), filestream ); end ); InstallMethod( WriteDocumentation, [ IsTreeForDocumentationVerbatimNodeRep, IsStream ], function( node, filestream ) local line, attr_name; AppendTo( filestream, "<", node!.element_name ); for attr_name in Set( RecNames( node!.attributes ) ) do AppendTo( filestream, " ", attr_name, "=\"", node!.attributes.( attr_name ), "\"" ); od; AppendTo( filestream, ">", node!.closing_separator ); end ); AutoDoc-2026.05.03/gap/Magic.gd0000644000000000000000000005557315175510000012511 0ustar00# 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 Reference #! @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/_main.xml #! 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, using #! documentation comments and commands. This produces additional 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 ). #! #! #! These tasks can be enabled independently, so you can use as much or as #! little of &AutoDoc; as your package currently needs. #! For more information and some examples, please refer to Chapter . #!

#! The parameters have the following meanings: #! #! #! pkgdir #! #! This optional parameter is used to determine the package #! directory in which &AutoDoc; will operate, and to find the metadata #! concerning the package being documented. If given, it should be #! an IsDirectory object. If the argument is omitted, then &AutoDoc; #! checks if it was called from a makedoc.g file or similar, and if so, #! uses the directory this is contained in. Otherwise the current #! directory is used. In both 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. #!

#! For backwards compatibility, it is also possible to pass a package name #! as this argument, which then is resolved to the package directory of #! the first instance of this package &GAP; knows about. However, this is #! deprecated, as it is unreliable in the presence of multiple copies of a #! package. #!

#! Note that when using AutoDocWorksheet (see #! ), there is #! no parameter corresponding to pkgdir 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 written directly in &GAPDoc; XML. #! Appendices created with @Appendix are included automatically #! after these files when scaffolding generates the main XML file. #! #! #! 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. #! #! #! bibstyle #! #! Overrides the bibliography style used for LaTeX output. #! This is written as the Style attribute of the generated #! <Bibliography .../> element, so valid values are the #! bibliography style names understood by &GAPDoc; and BibTeX, such #! as alpha, alphaurl, or plain. #! #! #! 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. #!

#! Note that &AutoDoc; predefines several entities: #! #! VERSION #! Set to the Version field of your package info record. #! RELEASEYEAR #! Set to a string containing the release year, as derived #! from the Date field of your package info record. #! RELEASEDATE #! Derived from the Date field of your package info record. #! SomePackage #! #! The precise name of this entity is derived from the #! PackageName field of your package info record. Note #! that it is case sensitive. The content is defined as #! suggested by the example above. #! #! #! #! #! TitlePage #! #! A record with extra title-page fields for the generated manual. #! Field names are interpreted as title-page XML element names, and #! their values are written as element content. For example, you can #! set a custom acknowledgements block with #!

#! If this is set in PackageInfo.g as #! PkgInfo.AutoDoc.TitlePage, it has the same meaning as this #! option; see subsection in chapter #! for details and an example. #!

#! For the list of valid title-page elements, see 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 recursively for .gi, .gd, .g, and #! .autodoc files; all of these files are then scanned for #! &AutoDoc; documentation comments. The special entries "." #! and "" still only scan the package root itself. #! This controls where &AutoDoc; looks for source comments beginning with #! #! and for standalone .autodoc files. #! It does not affect where &GAPDoc; looks for GAPDoc comments; that is controlled #! separately by gapdoc.scan_dirs. #!
#! 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. #! #! #! #! #### 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: _main.xml when scaffolding is enabled for #! package manuals, otherwise 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 recursively for .gi, .gd and .g #! files; all of these files are then scanned for &GAPDoc; #! documentation comments. The special entries "." and #! "" still only scan the package root itself. #! This controls only where &GAPDoc; comments are searched for. #! It does not affect where &AutoDoc; looks for source comments beginning with #! #! or for .autodoc files; use autodoc.scan_dirs for that. #!
#! 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.

#! If set to a record, it may contain the following entries: #! #! subdir #! #! A string or Directory() object selecting where the generated #! .tst files are written. The default is tst. If a string is #! given, it is interpreted relative to the package directory, so values #! such as tst/generated are supported. #! #! 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. #! #! #! #! #! #! #! #! #! The function also checks the following GAP global options, i.e. options #! supplied via GAP's value-option syntax and visible through nested calls. #! These are not entries of optrec. See #! for more information #! about GAP's global options system. #! #! nopdf #! #! If this global option is set to `true`, then &AutoDoc; tells &GAPDoc; #! not to build the PDF version of the manual. HTML and text output are #! still generated. #!

#! This is useful on systems without a working `pdflatex` #! installation, or when you only need the non-PDF outputs while #! iterating on the manual. #!

#! For example: #!

#! Also, if the environment variable `NOPDF` is set, then &AutoDoc; #! behaves as if the global option nopdf had been enabled. #! #! relativePath #! #! This has the same effect as gapdoc.gap_root_relative_path, but #! as a GAP global option. It takes precedence over that record entry if #! both are specified. #!

#! If relativePath is `true`, then the default relative path #! ../../.. is used. If it is a string, then that string is used as #! the relative path from the documentation directory to the GAP root. #!

#! For example: #!

#!
#! #! In particular, a call such as #! #! sets both global options to `true`, and they remain visible to the #! call inside makedoc.g. #! #! @Returns nothing #! @Arguments [pkgdir], [optrec] DeclareGlobalFunction( "AutoDoc" ); DeclareGlobalFunction( "AutoDoc_INTERN" ); #! @Description #! Info class for the AutoDoc package. Set this to #! 0 to suppress info messages, 1 to allow most messages, and 2 to allow all #! messages including those that contain file paths. #! #! This can be set by calling, for example, #! SetInfoLevel(InfoAutoDoc, 0). Default value is 1. DeclareInfoClass("InfoAutoDoc"); SetInfoLevel(InfoAutoDoc, 1); AutoDoc-2026.05.03/gap/Magic.gi0000644000000000000000000006065315175510000012511 0ustar00# 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( AutoDoc, function( arg ) local pkgname, pkginfo, pkgdir, opt, file, input_filename, path_positions; 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( Last( arg ) ) then opt := Remove( arg ); else opt := rec(); fi; # check the first argument if Length(arg) = 0 then input_filename := INPUT_FILENAME(); if IsString( input_filename ) and input_filename <> "*stdin*" and IsReadableFile( input_filename ) then path_positions := PositionsProperty( input_filename, x -> x = '/' ); if IsEmpty( path_positions ) then pkgdir := DirectoryCurrent( ); else pkgdir := Directory( input_filename{ [ 1 .. Last( path_positions ) - 1 ] } ); fi; else pkgdir := DirectoryCurrent( ); fi; elif IsString( arg[1] ) then pkgname := Remove( arg, 1 ); Print("#W AutoDoc: passing pkgname as first argument to AutoDoc is deprecated"); 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 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; else 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; return AutoDoc_INTERN( false, pkgname, pkginfo, pkgdir, opt ); end ); InstallGlobalFunction( AutoDoc_INTERN, function( is_worksheet, pkgname, pkginfo, pkgdir, opt ) local scaffold, gapdoc, extract_examples, autodoc, i, doc_dir, doc_dir_rel, tmp, key, val, file, pkgdirstr, docdirstr, title_page, tree, position_document_class, args, used_legacy_value_options; # # Deprecated feature: Check for user supplied global options. If present, # they take precedence over any defaults as well as the opt record. # used_legacy_value_options := false; for key in [ "dir", "scaffold", "autodoc", "gapdoc", "extract_examples" ] do val := ValueOption( key ); if val <> fail then opt.(key) := val; used_legacy_value_options := true; fi; od; if used_legacy_value_options then Print("#W passing options via GAP's global options system is deprecated; use an option record instead\n"); fi; # # 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( InfoAutoDoc, 2, "Generating documentation in ", doc_dir); # # 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 AUTODOC_MergeRecords( scaffold.(key), pkginfo.AutoDoc.(key) ); 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; 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 # When scaffolding also generates the main XML file, the default # GAPDoc entry point must match that scaffolded filename. However, # packages with scaffold.MainPage := false may rely on a handwritten # PACKAGENAME.xml main file while still using scaffolded title pages, # so in that case we keep the historical default. if IsBound( scaffold ) and not is_worksheet and ( not IsBound( scaffold.MainPage ) or scaffold.MainPage <> false ) then AUTODOC_SetIfMissing( gapdoc, "main", "_main" ); else AUTODOC_SetIfMissing( gapdoc, "main", pkgname ); fi; if IsBound( pkginfo.PackageDoc ) and not IsEmpty( pkginfo.PackageDoc ) then if Length( pkginfo.PackageDoc ) > 1 then Info(InfoAutoDoc, 1, "WARNING: Package contains multiple books, only using the first one"); 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"; Info(InfoAutoDoc, 1, "WARNING: PackageInfo.g is missing a PackageDoc entry!"); Info(InfoAutoDoc, 1, "Without this, your package manual will not be recognized by the GAP help system."); Info(InfoAutoDoc, 1, "You can correct this by adding the following to your PackageInfo.g:"); Info(InfoAutoDoc, 1, "PackageDoc := rec("); Info(InfoAutoDoc, 1, " BookName := ~.PackageName,"); Info(InfoAutoDoc, 1, " ArchiveURLSubset := [\"doc\"],"); Info(InfoAutoDoc, 1, " HTMLStart := \"doc/chap0.html\","); Info(InfoAutoDoc, 1, " PDFFile := \"doc/manual.pdf\","); Info(InfoAutoDoc, 1, " SixFile := \"doc/manual.six\","); Info(InfoAutoDoc, 1, " LongTitle := ~.Subtitle,"); Info(InfoAutoDoc, 1, "),"); 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 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 := Last(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; 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( 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; # Normalize legacy list syntax before adding default entities. if not IsBound( scaffold.entities ) then scaffold.entities := rec(); elif IsList( scaffold.entities ) then tmp := rec(); for i in scaffold.entities do if IsString( i ) then tmp.( i ) := Concatenation( "", i, "" ); else tmp.( i[2] ) := Concatenation( "<", i[1], ">", i[2], "" ); fi; od; scaffold.entities := tmp; elif not IsRecord( scaffold.entities ) then Error( "CreateEntitiesPage: must be a list or a record" ); fi; # set some default entities if IsBound( pkginfo.Version ) then AUTODOC_SetIfMissing( scaffold.entities, "VERSION", pkginfo.Version ); fi; if IsBound( pkginfo.Date ) then tmp := AUTODOC_ParseDate( pkginfo.Date ); AUTODOC_SetIfMissing( scaffold.entities, "RELEASEYEAR", tmp.year ); AUTODOC_SetIfMissing( scaffold.entities, "RELEASEDATE", AUTODOC_FormatDate( tmp ) ); fi; CreateEntitiesPage( gapdoc.bookname, doc_dir, scaffold ); if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then if ForAny( tree!.content, node -> IsBound( node!.is_appendix ) and node!.is_appendix = true ) then scaffold.autodoc_appendix_file := "_AutoDocAppendicesMainFile.xml"; fi; CreateMainPage( gapdoc.bookname, gapdoc.main, doc_dir, scaffold ); fi; fi; # # Write AutoDoc XML files # if IsBound( autodoc ) then WriteDocumentation( tree, doc_dir ); 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 ) or ValueOption( "nopdf" ) = true 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 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.subdir ) then extract_examples.subdir := "tst"; elif not IsString( extract_examples.subdir ) and not IsDirectory( extract_examples.subdir ) then Error( "extract_examples.subdir must be a string or Directory()" ); 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-2026.05.03/gap/Markdown.gd0000644000000000000000000000041315175510000013232 0ustar00# 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_ConvertMarkdownToGAPDocXML" ); AutoDoc-2026.05.03/gap/Markdown.gi0000644000000000000000000003744515175510000013256 0ustar00# 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( "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 ); ## BindGlobal( "AUTODOC_EscapeXMLTextForInlineCode", function( string ) local escaped_string, split_pos; escaped_string := ""; while Length(string) > 0 do split_pos := PositionProperty( string, c -> c in "&\"<>" ); if split_pos = fail then Append( escaped_string, string ); break; fi; if split_pos > 1 then Append( escaped_string, string{ [ 1 .. split_pos - 1 ] } ); fi; if string[ split_pos ] = '&' then Append( escaped_string, "&" ); elif string[ split_pos ] = '"' then Append( escaped_string, """ ); elif string[ split_pos ] = '<' then Append( escaped_string, "<" ); else Append( escaped_string, ">" ); fi; string := string{ [ split_pos + 1 .. Length( string ) ] }; od; return escaped_string; end ); ## BindGlobal( "AUTODOC_ConvertInlineBackticksInLine", function( string, keyword_set, source_position ) local opening_pos, closing_pos, inline_content, tag_name, search_string; while PositionSublist( string, "`" ) <> fail do opening_pos := PositionSublist( string, "`" ); search_string := string{ [ opening_pos + 1 .. Length( string ) ] }; closing_pos := PositionSublist( search_string, "`" ); if closing_pos = fail then if source_position = fail then Error( "did you forget some `" ); fi; Error( "did you forget some `,\n", "at ", source_position.filename, ":", source_position.line ); fi; closing_pos := opening_pos + closing_pos; if opening_pos + 1 <= closing_pos - 1 then inline_content := string{ [ opening_pos + 1 .. closing_pos - 1 ] }; else inline_content := ""; fi; if inline_content in keyword_set then tag_name := "Keyword"; else tag_name := "Code"; fi; string := Concatenation( string{ [ 1 .. opening_pos - 1 ] }, "<", tag_name, ">", AUTODOC_EscapeXMLTextForInlineCode( inline_content ), "", string{ [ closing_pos + 1 .. Length( string ) ] } ); od; return string; end ); ## BindGlobal( "AUTODOC_FencedMarkdownElement", function( info_string ) if info_string = "@example" then return "Example"; elif info_string = "@log" then return "Log"; fi; return "Listing"; end ); ## BindGlobal( "AUTODOC_ConvertFencedMarkdownBlocks", function( arg ) local converted_source_positions, converted_string_list, i, skipped, string_list, trimmed_line, fence_char, fence_length, info_string, fence_element, code_block, fence_content, source_positions; string_list := arg[ 1 ]; if Length( arg ) > 1 then source_positions := arg[ 2 ]; else source_positions := ListWithIdenticalEntries( Length( string_list ), fail ); fi; converted_string_list := [ ]; converted_source_positions := [ ]; i := 1; skipped := false; while i <= Length( string_list ) do if AUTODOC_LineStartsCDATA( string_list[ i ] ) then skipped := true; fi; if skipped = true then Add( converted_string_list, string_list[ i ] ); Add( converted_source_positions, source_positions[ i ] ); if AUTODOC_LineEndsCDATA( string_list[ i ] ) then skipped := false; fi; i := i + 1; continue; fi; trimmed_line := StripBeginEnd( string_list[ i ], " \t\r\n" ); if Length( trimmed_line ) >= 3 and ( ForAll( trimmed_line{ [ 1 .. 3 ] }, c -> c = '`' ) or ForAll( trimmed_line{ [ 1 .. 3 ] }, c -> c = '~' ) ) then fence_char := trimmed_line[ 1 ]; fence_length := 1; while fence_length < Length( trimmed_line ) and trimmed_line[ fence_length + 1 ] = fence_char do fence_length := fence_length + 1; od; if fence_length >= 3 then info_string := NormalizedWhitespace( trimmed_line{ [ fence_length + 1 .. Length( trimmed_line ) ] } ); fence_element := AUTODOC_FencedMarkdownElement( info_string ); i := i + 1; code_block := false; fence_content := [ ]; while i <= Length( string_list ) do trimmed_line := StripBeginEnd( string_list[ i ], " \t\r\n" ); if Length( trimmed_line ) >= fence_length and ForAll( trimmed_line{ [ 1 .. fence_length ] }, c -> c = fence_char ) and ForAll( trimmed_line{ [ fence_length + 1 .. Length( trimmed_line ) ] }, c -> c in " \t\r\n" ) then code_block := true; break; fi; Add( fence_content, Chomp( string_list[ i ] ) ); i := i + 1; od; Add( converted_string_list, DocumentationVerbatim( fence_element, rec( ), fence_content ) ); Add( converted_source_positions, source_positions[ i - Length( fence_content ) - 1 ] ); if code_block = true then i := i + 1; continue; fi; break; fi; fi; Add( converted_string_list, string_list[ i ] ); Add( converted_source_positions, source_positions[ i ] ); i := i + 1; od; return rec( items := converted_string_list, source_positions := converted_source_positions ); end ); ## BindGlobal( "AUTODOC_ForEachNonCDATALine", function( string_list, action ) local i, in_cdata; in_cdata := false; for i in [ 1 .. Length( string_list ) ] do if AUTODOC_LineStartsCDATA( string_list[ i ] ) then in_cdata := true; fi; if in_cdata = false then action( i ); fi; if AUTODOC_LineEndsCDATA( string_list[ i ] ) then in_cdata := false; fi; od; end ); ## BindGlobal( "AUTODOC_ConvertMarkdownStringsToGAPDocXML", function( string_list, source_positions ) local i, current_list, current_string, max_line_length, current_position, already_in_list, command_list_with_translation, beginning, commands, opening_source_position, position_of_command, insert, beginning_whitespaces, temp, string_list_temp, skipped, already_inserted_paragraph, in_list, in_item, converted_string_list, keyword_set; # Convert inline backticks before list detection so literal tags such as # `` inside code spans do not look like structural GAPDoc tags. keyword_set := Set( ALL_KEYWORDS() ); AUTODOC_ForEachNonCDATALine( string_list, function( i ) string_list[ i ] := AUTODOC_ConvertInlineBackticksInLine( string_list[ i ], keyword_set, source_positions[ i ] ); end ); ## Check for paragraphs by turning an empty string into

already_inserted_paragraph := false; AUTODOC_ForEachNonCDATALine( string_list, function( i ) 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; end ); ## 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 AUTODOC_LineStartsCDATA( string_list[ i ] ) then skipped := true; fi; if AUTODOC_LineEndsCDATA( string_list[ i ] ) 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( source_positions, fail, i ); Add( string_list, "", i ); Add( source_positions, fail, 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( source_positions, fail, i ); Add( string_list, "", i ); Add( source_positions, fail, 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( source_positions, fail, i ); Add( string_list, "", i ); Add( source_positions, fail, i ); i := i + 2; fi; i := i + 1; od; if already_in_list = true then Add( string_list, "" ); Add( source_positions, fail ); Add( string_list, "" ); Add( source_positions, fail ); 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" ], [ "**", "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; opening_source_position := fail; AUTODOC_ForEachNonCDATALine( string_list, function( i ) 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 ], ">" ); opening_source_position := source_positions[ i ]; else insert := Concatenation( "" ); opening_source_position := fail; fi; string_list[ i ] := INSERT_IN_STRING_WITH_REPLACE( string_list[ i ], insert, position_of_command, Length( commands[ 1 ] ) ); beginning := not beginning; od; end ); if beginning = false then if opening_source_position = fail then Error( "did you forget some ", commands[ 1 ] ); fi; Error( "did you forget some ", commands[ 1 ], ",\n", "at ", opening_source_position.filename, ":", opening_source_position.line ); fi; od; return string_list; end ); ## InstallGlobalFunction( AUTODOC_ConvertMarkdownToGAPDocXML, function( string_list, source_positions ) local converted_blocks, converted_items, current_source_positions, current_string_list, i, FlushStringList; if source_positions = fail then source_positions := ListWithIdenticalEntries( Length( string_list ), fail ); fi; converted_items := [ ]; current_string_list := [ ]; current_source_positions := [ ]; FlushStringList := function() if current_string_list = [ ] then return; fi; Append( converted_items, AUTODOC_ConvertMarkdownStringsToGAPDocXML( current_string_list, current_source_positions ) ); current_string_list := [ ]; current_source_positions := [ ]; end; converted_blocks := AUTODOC_ConvertFencedMarkdownBlocks( string_list, source_positions ); for i in [ 1 .. Length( converted_blocks.items ) ] do if IsString( converted_blocks.items[ i ] ) then Add( current_string_list, converted_blocks.items[ i ] ); Add( current_source_positions, converted_blocks.source_positions[ i ] ); else FlushStringList(); Add( converted_items, converted_blocks.items[ i ] ); fi; od; FlushStringList(); return converted_items; end ); AutoDoc-2026.05.03/gap/Parser.gd0000644000000000000000000000067215175510000012713 0ustar00# 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" ); DeclareGlobalVariable( "AUTODOC_ITEM_TYPE_INFO" ); ## Argument should be a filename DeclareGlobalFunction( "AutoDoc_Parser_ReadFiles" ); AutoDoc-2026.05.03/gap/Parser.gi0000644000000000000000000015251715175510000012726 0ustar00# 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_ITEM_TYPE_INFO, rec( Attr := rec( chapter_bucket := "attributes", is_function_like := true ), Cat := rec( chapter_bucket := "categories", filter_type := "Category", item_type_override := "Filt", is_function_like := true ), Coll := rec( chapter_bucket := "collections", filter_type := "Collection", item_type_override := "Filt", is_function_like := true ), Constr := rec( chapter_bucket := "methods", is_function_like := true ), Fam := rec( chapter_bucket := "global_variables", is_function_like := false ), Filt := rec( chapter_bucket := "filters", is_function_like := true ), Func := rec( chapter_bucket := "global_functions", is_function_like := true ), InfoClass := rec( chapter_bucket := "info_classes", is_function_like := false ), Meth := rec( chapter_bucket := "methods", is_function_like := true ), Oper := rec( chapter_bucket := "methods", is_function_like := true ), Prop := rec( chapter_bucket := "properties", is_function_like := true ), Repr := rec( chapter_bucket := "representations", filter_type := "Representation", item_type_override := "Filt", is_function_like := true ), Var := rec( chapter_bucket := "global_variables", is_function_like := false ) )); ## BindGlobal( "AUTODOC_PositionPrefixShebang", function( line ) local position; position := PositionProperty( line, c -> not c in " \t\r\n" ); if position = fail or position = Length( line ) then return fail; fi; if line[ position ] = '#' and line[ position + 1 ] = '!' then return position; fi; return fail; end ); ## BindGlobal( "AUTODOC_SplitMarkdownHeading", function( line ) local trimmed, level, first_non_hash; trimmed := StripBeginEnd( line, " \t\r\n" ); if trimmed = "" or trimmed[ 1 ] <> '#' then return fail; fi; level := 1; while level < Length( trimmed ) and trimmed[ level + 1 ] = '#' do level := level + 1; od; if level > 3 then return fail; fi; first_non_hash := level + 1; if first_non_hash <= Length( trimmed ) and not ( trimmed[ first_non_hash ] in " \t\r\n" ) then return fail; fi; while first_non_hash <= Length( trimmed ) and trimmed[ first_non_hash ] in " \t\r\n" do first_non_hash := first_non_hash + 1; od; if level = 1 then return [ "@Chapter", trimmed{ [ first_non_hash .. Length( trimmed ) ] } ]; elif level = 2 then return [ "@Section", trimmed{ [ first_non_hash .. Length( trimmed ) ] } ]; fi; return [ "@Subsection", trimmed{ [ first_non_hash .. Length( trimmed ) ] } ]; end ); ## BindGlobal( "AUTODOC_SplitCommandAndArgument", function( line ) local command_start, argument_start, command, argument, heading; heading := AUTODOC_SplitMarkdownHeading( line ); if heading <> fail then return heading; fi; command_start := PositionProperty( line, c -> not c in " \t\r\n" ); if command_start = fail or line[ command_start ] <> '@' then return [ "STRING", line ]; fi; argument_start := command_start + 1; while argument_start <= Length( line ) and not ( line[ argument_start ] in " \t\r\n" ) do argument_start := argument_start + 1; od; command := line{ [ command_start .. argument_start - 1 ] }; while argument_start <= Length( line ) and line[ argument_start ] in " \t\r\n" do argument_start := argument_start + 1; od; if argument_start <= Length( line ) then argument := line{ [ argument_start .. Length( line ) ] }; else argument := ""; fi; return [ command, argument ]; end ); ## InstallGlobalFunction( Scan_for_AutoDoc_Part, function( line ) local trimmed, heading; trimmed := StripBeginEnd( line, " \t\r\n" ); if trimmed = "" then return [ "STRING", line ]; fi; if trimmed[ 1 ] = '#' then heading := AUTODOC_SplitMarkdownHeading( trimmed ); if heading = fail then return [ "STRING", line ]; fi; return heading; fi; if trimmed[ 1 ] <> '@' then return [ "STRING", line ]; fi; return AUTODOC_SplitCommandAndArgument( trimmed ); end ); ## Scans a string for after appeared. ## This is necessary to scan the filter list for method declarations ## that contain \[\]. BindGlobal( "AUTODOC_PositionElementIfNotAfter", function( str, char, not_before_char ) local pos; if Length( str ) > 0 and str[ 1 ] = char then return 1; fi; for pos in [ 2 .. Length( str ) ] do if str[ pos ] = char and str[ pos - 1 ] <> not_before_char then return pos; fi; od; return fail; end ); ## InstallGlobalFunction( AutoDoc_Type_Of_Item, function( current_item, type, default_chapter_data ) local item_rec, filter_style, default_type, item_type, item_type_info, default_boolean_return; item_rec := current_item; default_boolean_return := "true or false"; if PositionSublist( type, "DeclareCategoryCollections") <> fail then default_type := "Coll"; filter_style := "none"; if not IsBound( item_rec!.arguments ) then item_rec!.arguments := "obj"; fi; item_rec!.coll_suffix := true; elif PositionSublist( type, "DeclareCategory" ) <> fail then default_type := "Cat"; filter_style := "single"; elif PositionSublist( type, "DeclareRepresentation" ) <> fail then default_type := "Repr"; filter_style := "single"; elif PositionSublist( type, "DeclareAttribute" ) <> fail then default_type := "Attr"; filter_style := "single"; elif PositionSublist( type, "DeclareSynonymAttr" ) <> fail then default_type := "Attr"; filter_style := "none"; elif PositionSublist( type, "DeclareProperty" ) <> fail then default_type := "Prop"; filter_style := "single"; elif PositionSublist( type, "DeclareSynonym" ) <> fail then default_type := "Func"; filter_style := "none"; elif PositionSublist( type, "DeclareOperation" ) <> fail then default_type := "Oper"; filter_style := "list"; elif PositionSublist( type, "DeclareConstructor" ) <> fail then default_type := "Constr"; filter_style := "list"; elif PositionSublist( type, "DeclareGlobalFunction" ) <> fail then default_type := "Func"; filter_style := "none"; elif PositionSublist( type, "DeclareGlobalVariable" ) <> fail then default_type := "Var"; filter_style := "none"; elif PositionSublist( type, "DeclareGlobalName" ) <> fail then default_type := "Var"; filter_style := "none"; if IsBound( item_rec!.declaration_is_function ) and item_rec!.declaration_is_function then default_type := "Func"; fi; elif PositionSublist( type, "DeclareFilter" ) <> fail then default_type := "Filt"; filter_style := "none"; elif PositionSublist( type, "DeclareInfoClass" ) <> fail then default_type := "InfoClass"; filter_style := "none"; elif PositionSublist( type, "KeyDependentOperation" ) <> fail then default_type := "Oper"; filter_style := "pair"; else return fail; fi; if IsBound( item_rec!.item_type ) then item_type := StripBeginEnd( item_rec!.item_type, " \t\r\n" ); else item_type := default_type; fi; if not IsBound( AUTODOC_ITEM_TYPE_INFO.( item_type ) ) then return fail; fi; item_type_info := AUTODOC_ITEM_TYPE_INFO.( item_type ); item_rec!.item_type := item_type; if not IsBound( item_rec!.chapter_info ) or item_rec!.chapter_info = [ ] then item_rec!.chapter_info := default_chapter_data.( item_type_info.chapter_bucket ); fi; if item_type in [ "Cat", "Coll", "Filt", "Prop", "Repr" ] and ( item_rec!.return_value = [ ] or item_rec!.return_value = false ) then item_rec!.return_value := [ default_boolean_return ]; fi; if filter_style = "none" and item_type_info.is_function_like and not IsBound( item_rec!.arguments ) then item_rec!.arguments := "arg"; elif filter_style = "none" and not item_type_info.is_function_like then item_rec!.arguments := fail; item_rec!.return_value := false; fi; return filter_style; end ); ## InstallGlobalFunction( AutoDoc_Parser_ReadFiles, function( filename_list, tree, default_chapter_data ) local ApplyFilterInfoToCurrentItem, CreateTitleItemFunction, CurrentItem, CurrentOrNewManItem, CurrentSourcePosition, DeclarationDelimiterPosition, ErrorWithPos, FinishCurrentManItem, HasCurrentItem, IsMatchingMarkdownFence, MarkdownFenceFromLine, NormalizeInputLine, NormalizeItemType, NormalizedReadLine, ReadBracketedFilterString, ReadCode, ReadExample, ReadInstallMethodArguments, ReadInstallMethodFilterString, ReadLineWithLineCount, ReadSessionExample, RecordStringSourcePosition, Reset, ScanDeclarePart, ScanForDeclarationPart, ScanInstallMethodPart, SetCurrentItem, # active_title_item_is_multiline, active_title_item_name, autodoc_read_line, chapter_info, command_function_record, comment_start_pos, context_stack, current_command, current_line, current_line_fence, current_line_info, current_line_is_fence_delimiter, current_line_positition_for_filter, current_line_unedited, display_filename, filename, filestream, groupnumber, line_number, markdown_fence, plain_text_mode, rest_of_file_skipped, scope_group, single_line_title_item_list, title_item, title_item_list, xml_comment_mode; groupnumber := 0; autodoc_read_line := false; context_stack := [ ]; chapter_info := [ ]; line_number := 0; active_title_item_name := fail; active_title_item_is_multiline := false; ReadLineWithLineCount := function( stream ) line_number := line_number + 1; return ReadLine( stream ); end; NormalizedReadLine := 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 ", display_filename, ":", line_number ] ); CallFuncList(Error, list); end; CurrentSourcePosition := function() return rec( filename := display_filename, line := line_number ); end; RecordStringSourcePosition := function( item ) local source_field; if not ( IsRecord( item ) or IsTreeForDocumentationNode( item ) ) then return; fi; if IsBound( item!.content_source_field ) then source_field := item!.content_source_field; elif IsBound( item!.content_source_positions ) then source_field := "content_source_positions"; else return; fi; if not IsBound( item!.( source_field ) ) then item!.( source_field ) := [ ]; fi; Add( item!.( source_field ), CurrentSourcePosition() ); end; HasCurrentItem := function( ) return Length( context_stack ) > 0; end; CurrentItem := function( ) return Last( context_stack ); end; SetCurrentItem := function( item ) if HasCurrentItem() then context_stack[ Length( context_stack ) ] := item; else Add( context_stack, item ); fi; end; NormalizeInputLine := function( raw_line ) local text, comment_pos; if plain_text_mode then text := raw_line; return rec( raw_text := raw_line, text := text, is_autodoc := true, allows_declaration_scan := false ); fi; comment_pos := AUTODOC_PositionPrefixShebang( raw_line ); if comment_pos = fail then return rec( raw_text := raw_line, text := raw_line, is_autodoc := false, allows_declaration_scan := false ); fi; text := raw_line{ [ comment_pos + 2 .. Length( raw_line ) ] }; return rec( raw_text := raw_line, text := text, is_autodoc := true, allows_declaration_scan := true ); end; MarkdownFenceFromLine := function( line ) local trimmed_line, fence_char, fence_length; trimmed_line := StripBeginEnd( Chomp( line ), " \t\r\n" ); if Length( trimmed_line ) < 3 or not ( trimmed_line[ 1 ] in "`~" ) or not ForAll( trimmed_line{ [ 1 .. 3 ] }, c -> c = trimmed_line[ 1 ] ) then return fail; fi; fence_char := trimmed_line[ 1 ]; fence_length := 1; while fence_length < Length( trimmed_line ) and trimmed_line[ fence_length + 1 ] = fence_char do fence_length := fence_length + 1; od; return rec( char := fence_char, length := fence_length, remainder := trimmed_line{ [ fence_length + 1 .. Length( trimmed_line ) ] } ); end; IsMatchingMarkdownFence := function( fence, current_line_fence ) return current_line_fence <> fail and fence <> fail and current_line_fence.char = fence.char and current_line_fence.length >= fence.length and ForAll( current_line_fence.remainder, c -> c in " \t\r\n" ); end; DeclarationDelimiterPosition := function( line ) return Minimum( [ PositionSublist( line, "," ), PositionSublist( line, ");" ) ] ); end; ReadBracketedFilterString := function( error_message, trim_parts ) local filter_string, pos, part; pos := AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ); while pos = fail do current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( error_message ); fi; pos := AUTODOC_PositionElementIfNotAfter( current_line, '[', '\\' ); od; current_line := current_line{[ pos + 1 .. Length( current_line ) ]}; filter_string := "for "; pos := AUTODOC_PositionElementIfNotAfter( current_line, ']', '\\' ); while pos = fail do part := current_line; if trim_parts then part := StripBeginEnd( part, " " ); fi; Append( filter_string, part ); current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( error_message ); fi; pos := AUTODOC_PositionElementIfNotAfter( current_line, ']', '\\' ); od; part := current_line{[ 1 .. pos - 1 ]}; if trim_parts then part := StripBeginEnd( part, " " ); fi; Append( filter_string, part ); current_line := current_line{[ pos + 1 .. Length( current_line ) ]}; NormalizeWhitespace( filter_string ); return filter_string; end; ReadInstallMethodFilterString := function( ) return ReadBracketedFilterString( "unterminated InstallMethod filter list", false ); end; ReadInstallMethodArguments := function( ) local pos, argument_string; while PositionSublist( current_line, "function(" ) = fail and PositionSublist( current_line, ");" ) = fail do current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( "unterminated InstallMethod declaration" ); fi; od; pos := PositionSublist( current_line, "function(" ); if pos = fail then return fail; fi; current_line := current_line{[ pos + 9 .. Length( current_line ) ]}; argument_string := ""; while PositionSublist( current_line, ")" ) = fail do current_line := StripBeginEnd( current_line, " " ); Append( argument_string, current_line ); current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( "unterminated argument list in InstallMethod declaration" ); fi; od; pos := PositionSublist( current_line, ")" ); Append( argument_string, current_line{[ 1 .. pos - 1 ]} ); NormalizeWhitespace( argument_string ); return StripBeginEnd( argument_string, " " ); end; ApplyFilterInfoToCurrentItem := function( filter_string, filter_style ) local filter_count; if IsString( filter_string ) then filter_string := ReplacedString( filter_string, "\"", "" ); fi; if filter_string = false then return; fi; if CurrentItem()!.tester_names = fail and StripBeginEnd( filter_string, " " ) <> "for" then CurrentItem()!.tester_names := filter_string; fi; if not IsBound( CurrentItem()!.arguments ) then if StripBeginEnd( filter_string, " " ) = "for" then CurrentItem()!.arguments := ""; elif filter_style = "single" then CurrentItem()!.arguments := "arg"; elif filter_style = "pair" then CurrentItem()!.arguments := "arg1,arg2"; elif filter_style = "list" then filter_count := Length( SplitString( filter_string, "," ) ); CurrentItem()!.arguments := List( [ 1 .. filter_count ], i -> Concatenation( "arg", String( i ) ) ); if filter_count = 1 then CurrentItem()!.arguments := "arg"; else CurrentItem()!.arguments := JoinStringsWithSeparator( CurrentItem()!.arguments, "," ); fi; fi; fi; end; NormalizeItemType := function( item_type ) local supported_types; item_type := StripBeginEnd( item_type, " \t\r\n" ); if IsBound( AUTODOC_ITEM_TYPE_INFO.( item_type ) ) then return item_type; fi; supported_types := JoinStringsWithSeparator( Set( RecNames( AUTODOC_ITEM_TYPE_INFO ) ), ", " ); ErrorWithPos( Concatenation( "unknown @ItemType ", item_type, "; expected one of ", supported_types ) ); end; CurrentOrNewManItem := function( ) local man_item; if HasCurrentItem() and IsTreeForDocumentationNodeForManItemRep( CurrentItem() ) then return CurrentItem(); fi; # implicitly end any subsection if IsBound( chapter_info[ 3 ] ) then Unbind( chapter_info[ 3 ] ); SetCurrentItem( SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ) ); fi; man_item := DocumentationManItem( ); if IsBound( scope_group ) then SetGroupName( man_item, scope_group ); fi; man_item!.chapter_info := ShallowCopy( chapter_info ); man_item!.tester_names := fail; Add( context_stack, man_item ); return man_item; end; FinishCurrentManItem := function( ) local man_item; man_item := CurrentItem(); Remove( context_stack ); 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; ScanDeclarePart := function( declare_position ) local current_type, filter_string, filter_style, i, name, pos; CurrentOrNewManItem(); current_line := current_line{[ declare_position .. Length( current_line ) ]}; pos := PositionSublist( current_line, "(" ); if pos = fail then ErrorWithPos( "Something went wrong" ); fi; current_type := current_line{ [ 1 .. pos - 1 ] }; filter_style := AutoDoc_Type_Of_Item( CurrentItem(), current_type, default_chapter_data ); if filter_style = fail then ErrorWithPos( "Unrecognized scan type" ); return false; fi; current_line := current_line{ [ pos + 1 .. Length( current_line ) ] }; while PositionSublist( current_line, "," ) = fail and PositionSublist( current_line, ");" ) = fail do current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( "unterminated declaration header" ); fi; od; current_line := StripBeginEnd( current_line, " " ); name := current_line{ [ 1 .. DeclarationDelimiterPosition( current_line ) - 1 ] }; name := StripBeginEnd( ReplacedString( 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(CurrentItem()!.coll_suffix) then if EndsWith(name, "Collection") then name := name{[1..Length(name)-6]}; fi; if EndsWith(name, "Coll") then CurrentItem()!.coll_suffix := "Coll"; else CurrentItem()!.coll_suffix := "Collection"; fi; Append(name, CurrentItem()!.coll_suffix); fi; CurrentItem()!.name := name; current_line := current_line{ [ DeclarationDelimiterPosition( current_line ) + 1 .. Length( current_line ) ] }; filter_string := "for "; if filter_style = "single" or filter_style = "pair" then for i in [ 1 .. 2 ] do if filter_style = "single" and i = 2 then break; fi; while PositionSublist( current_line, "," ) = fail and PositionSublist( current_line, ");" ) = fail do Append( filter_string, StripBeginEnd( current_line, " " ) ); current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( "unterminated declaration filter list" ); fi; od; current_line_positition_for_filter := DeclarationDelimiterPosition( 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; if filter_style = "pair" and i = 1 then Append( filter_string, ", " ); fi; od; elif filter_style = "list" then filter_string := ReadBracketedFilterString( "unterminated declaration filter list", true ); else filter_string := false; fi; ApplyFilterInfoToCurrentItem( filter_string, filter_style ); FinishCurrentManItem(); return true; end; ScanInstallMethodPart := function( declare_position ) local filter_string, name, pos; CurrentOrNewManItem(); if not IsBound( CurrentItem()!.item_type ) then CurrentItem()!.item_type := "Meth"; else CurrentItem()!.item_type := NormalizeItemType( CurrentItem()!.item_type ); fi; pos := PositionSublist( current_line, "(" ); current_line := current_line{ [ pos + 1 .. Length( current_line ) ] }; name := ""; pos := PositionSublist( current_line, "," ); while pos = fail do Append( name, current_line ); current_line := NormalizedReadLine( filestream ); if current_line = fail then ErrorWithPos( "unterminated InstallMethod declaration header" ); fi; pos := PositionSublist( current_line, "," ); od; Append( name, current_line{[ 1 .. pos - 1 ]} ); NormalizeWhitespace( name ); name := StripBeginEnd( name, " " ); name := ReplacedString( name, "\"", "" ); CurrentItem()!.name := name; filter_string := ReadInstallMethodFilterString( ); if CurrentItem()!.tester_names = fail then CurrentItem()!.tester_names := ReplacedString( filter_string, "\"", "" ); fi; if not IsBound( CurrentItem()!.arguments ) then filter_string := ReadInstallMethodArguments( ); if filter_string <> fail then CurrentItem()!.arguments := filter_string; fi; fi; if not IsBound( CurrentItem()!.arguments ) then CurrentItem()!.arguments := Length( SplitString( CurrentItem()!.tester_names, "," ) ); CurrentItem()!.arguments := JoinStringsWithSeparator( List( [ 1 .. CurrentItem()!.arguments ], i -> Concatenation( "arg", String( i ) ) ), "," ); fi; FinishCurrentManItem(); return true; end; Reset := function( ) chapter_info := [ ]; context_stack := [ ]; plain_text_mode := false; markdown_fence := fail; xml_comment_mode := false; end; ScanForDeclarationPart := function() local declare_position; ## fail is bigger than every integer declare_position := Minimum( [ PositionSublist( current_line, "Declare" ), PositionSublist( current_line, "KeyDependentOperation" ) ] ); if declare_position <> fail then return ScanDeclarePart( declare_position ); fi; declare_position := Minimum( [ PositionSublist( current_line, "InstallMethod" ), PositionSublist( current_line, "InstallOtherMethod" ) ] ); ## Fail is larger than every integer. if declare_position <> fail then return ScanInstallMethodPart( declare_position ); fi; return false; end; ReadCode := function( ) local code_node, temp_curr_line, temp_line_info, temp_command; code_node := DocumentationVerbatim( "Listing", rec( Type := "Code" ), [ ] ); while true do temp_curr_line := ReadLineWithLineCount( filestream ); temp_line_info := NormalizeInputLine( temp_curr_line ); if temp_line_info.is_autodoc then temp_command := Scan_for_AutoDoc_Part( temp_line_info.text ); if temp_command[ 1 ] = "@EndCode" then break; fi; Add( code_node!.content, Chomp( temp_line_info.text ) ); continue; fi; Add( code_node!.content, Chomp( temp_curr_line ) ); od; return code_node; end; ReadExample := function( element_name ) local temp_string_list, temp_curr_line, temp_pos_comment, is_following_line, item_temp, example_node, end_command; example_node := DocumentationExample( element_name ); temp_string_list := example_node!.content; end_command := Concatenation( "@End", element_name ); is_following_line := false; while true do temp_curr_line := Chomp( ReadLineWithLineCount( filestream ) ); if PositionSublist( temp_curr_line, end_command ) <> fail then break; fi; ##if is comment, simply remove comments. temp_pos_comment := AUTODOC_PositionPrefixShebang( 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; ReadSessionExample := function( element_name, plain_text_mode ) local temp_string_list, temp_curr_line, temp_pos_comment, is_following_line, item_temp, example_node, incorporate_this_line, end_command; example_node := DocumentationExample( element_name ); temp_string_list := example_node!.content; end_command := Concatenation( "@End", element_name, "Session" ); while true do temp_curr_line := Chomp( ReadLineWithLineCount( filestream ) ); if PositionSublist( temp_curr_line, end_command ) <> fail then break; fi; incorporate_this_line := plain_text_mode; if not plain_text_mode then temp_pos_comment := AUTODOC_PositionPrefixShebang( 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; command_function_record := rec( @DoNotReadRestOfFile := function() Reset(); rest_of_file_skipped := true; end, @Chapter := function() local scope_chapter; scope_chapter := ReplacedString( current_command[ 2 ], " ", "_" ); SetCurrentItem( ChapterInTree( tree, scope_chapter ) ); Unbind( chapter_info[ 2 ] ); Unbind( chapter_info[ 3 ] ); chapter_info[ 1 ] := scope_chapter; end, @Appendix := function() local scope_appendix; scope_appendix := ReplacedString( current_command[ 2 ], " ", "_" ); SetCurrentItem( AppendixInTree( tree, scope_appendix ) ); Unbind( chapter_info[ 2 ] ); Unbind( chapter_info[ 3 ] ); chapter_info[ 1 ] := scope_appendix; 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 := AUTODOC_NormalizeGeneratedLabel( current_command[ 2 ] ); scope_chapter := ChapterInTree( tree, chapter_info[ 1 ] ); SetLabel( scope_chapter, 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 ]; scope_chapter!.title_string_source_position := CurrentSourcePosition(); 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 ], " ", "_" ); SetCurrentItem( 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 := AUTODOC_NormalizeGeneratedLabel( current_command[ 2 ] ); scope_section := SectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ] ); SetLabel( scope_section, 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 ]; scope_section!.title_string_source_position := CurrentSourcePosition(); 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 ], " ", "_" ); SetCurrentItem( 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 := AUTODOC_NormalizeGeneratedLabel( current_command[ 2 ] ); scope_subsection := SubsectionInTree( tree, chapter_info[ 1 ], chapter_info[ 2 ], chapter_info[ 3 ] ); SetLabel( scope_subsection, 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 ]; scope_subsection!.title_string_source_position := CurrentSourcePosition(); 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() CurrentOrNewManItem(); CurrentItem()!.content := CurrentItem()!.description; CurrentItem()!.content_source_field := "description_source_positions"; NormalizeWhitespace( current_command[ 2 ] ); if current_command[ 2 ] <> "" then Add( CurrentItem(), current_command[ 2 ] ); RecordStringSourcePosition( CurrentItem() ); fi; end, @Returns := function() CurrentOrNewManItem(); CurrentItem()!.content := CurrentItem()!.return_value; CurrentItem()!.content_source_field := "return_value_source_positions"; if IsBound( CurrentItem()!.item_type ) and CurrentItem()!.item_type = "Var" then CurrentItem()!.item_type := "Func"; if not IsBound( CurrentItem()!.arguments ) or CurrentItem()!.arguments = fail then CurrentItem()!.arguments := "arg"; fi; CurrentItem()!.return_value := [ ]; CurrentItem()!.return_value_source_positions := [ ]; elif not IsBound( CurrentItem()!.item_type ) then CurrentItem()!.declaration_is_function := true; fi; if current_command[ 2 ] <> "" then Add( CurrentItem(), current_command[ 2 ] ); RecordStringSourcePosition( CurrentItem() ); fi; end, @Arguments := function() CurrentOrNewManItem(); if IsBound( CurrentItem()!.item_type ) and CurrentItem()!.item_type = "Var" then CurrentItem()!.item_type := "Func"; elif not IsBound( CurrentItem()!.item_type ) then CurrentItem()!.declaration_is_function := true; fi; CurrentItem()!.arguments := current_command[ 2 ]; end, @ItemType := function() CurrentOrNewManItem(); CurrentItem()!.item_type := NormalizeItemType( current_command[ 2 ] ); end, @Label := function() CurrentOrNewManItem(); CurrentItem()!.tester_names := current_command[ 2 ]; end, @Group := function() local group_name; CurrentOrNewManItem(); group_name := ReplacedString( current_command[ 2 ], " ", "_" ); SetGroupName( CurrentItem(), group_name ); end, @GroupTitle := function() local group_name, chap_info, group_obj; CurrentOrNewManItem(); if not HasGroupName( CurrentItem() ) then ErrorWithPos( "found @GroupTitle with no Group set" ); fi; group_name := GroupName( CurrentItem() ); chap_info := fail; if HasChapterInfo( CurrentItem() ) then chap_info := ChapterInfo( CurrentItem() ); elif IsBound( CurrentItem()!.chapter_info ) then chap_info := CurrentItem()!.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 ]; group_obj!.title_string_source_position := CurrentSourcePosition(); end, @ChapterInfo := function() local current_chapter_info; CurrentOrNewManItem(); current_chapter_info := SplitString( current_command[ 2 ], "," ); current_chapter_info := List( current_chapter_info, i -> ReplacedString( StripBeginEnd( i, " " ), " ", "_" ) ); SetChapterInfo( CurrentItem(), current_chapter_info ); end, @BREAK := function() ErrorWithPos( current_command[ 2 ] ); end, @Index := function() local argument, split_pos, key, entry, c, escaped_quote_pos, key_string, key_escaped; if not HasCurrentItem() then ErrorWithPos( "found @Index with no active documentation item" ); fi; argument := StripBeginEnd( current_command[ 2 ], " \t\r\n" ); if argument = "" then ErrorWithPos( "found @Index without arguments" ); fi; entry := ""; if argument[ 1 ] = '"' then escaped_quote_pos := 2; while escaped_quote_pos <= Length( argument ) and argument[ escaped_quote_pos ] <> '"' do escaped_quote_pos := escaped_quote_pos + 1; od; if escaped_quote_pos > Length( argument ) then ErrorWithPos( "found @Index with unterminated quoted key" ); fi; key := argument{ [ 2 .. escaped_quote_pos - 1 ] }; split_pos := escaped_quote_pos + 1; while split_pos <= Length( argument ) and argument[ split_pos ] in " \t\r\n" do split_pos := split_pos + 1; od; if split_pos <= Length( argument ) then entry := argument{ [ split_pos .. Length( argument ) ] }; fi; else split_pos := PositionProperty( argument, c -> c in " \t\r\n" ); if split_pos = fail then key := argument; else key := argument{ [ 1 .. split_pos - 1 ] }; while split_pos <= Length( argument ) and argument[ split_pos ] in " \t\r\n" do split_pos := split_pos + 1; od; if split_pos <= Length( argument ) then entry := argument{ [ split_pos .. Length( argument ) ] }; fi; fi; fi; key_string := key; key_escaped := ""; while key_string <> "" do split_pos := PositionProperty( key_string, c -> c in "&\"<>" ); if split_pos = fail then Append( key_escaped, key_string ); break; elif split_pos > 1 then Append( key_escaped, key_string{ [ 1 .. split_pos - 1 ] } ); key_string := key_string{ [ split_pos .. Length( key_string ) ] }; fi; c := Remove(key_string, 1); if c = '&' then Append( key_escaped, "&" ); elif c = '"' then Append( key_escaped, """ ); elif c = '<' then Append( key_escaped, "<" ); else # c = '>' Append( key_escaped, ">" ); fi; od; if key_escaped = "" then ErrorWithPos( "found @Index with empty key" ); fi; Add( CurrentItem(), Concatenation( "", entry, "" ) ); end, @InsertChunk := function() local label_name; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); Add( CurrentItem(), DocumentationChunk( tree, label_name ) ); end, @BeginChunk := function() local label_name; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); Add( context_stack, DocumentationChunk( tree, label_name ) ); CurrentItem()!.is_defined := true; end, @Chunk := ~.@BeginChunk, @EndChunk := function() autodoc_read_line := false; Remove( context_stack ); end, @BeginCode := function() local label_name, tmp_system; label_name := ReplacedString( current_command[ 2 ], " ", "_" ); tmp_system := DocumentationChunk( tree, label_name ); tmp_system!.is_defined := true; Add( tmp_system!.content, ReadCode() ); end, @Code := ~.@BeginCode, @InsertCode := ~.@InsertChunk, @BeginExample := function() local example_node; example_node := ReadExample( "Example" ); Add( CurrentItem(), example_node ); end, @Example := ~.@BeginExample, @BeginLog := function() local example_node; example_node := ReadExample( "Log" ); Add( CurrentItem(), example_node ); end, @Log := ~.@BeginLog, STRING := function() if not HasCurrentItem() then return; fi; if active_title_item_name <> fail and active_title_item_is_multiline = false then return; fi; Add( CurrentItem(), current_command[ 2 ] ); RecordStringSourcePosition( CurrentItem() ); end, @BeginLatexOnly := function() local alt_node; alt_node := DocumentationVerbatim( "Alt", rec( Only := "LaTeX" ), [ ] ); Add( CurrentItem(), alt_node ); Add( context_stack, alt_node!.content ); if current_command[ 2 ] <> "" then Add( CurrentItem(), current_command[ 2 ] ); fi; end, @EndLatexOnly := function() autodoc_read_line := false; Remove( context_stack ); end, @LatexOnly := function() Add( CurrentItem(), DocumentationVerbatim( "Alt", rec( Only := "LaTeX" ), [ current_command[ 2 ] ] ) ); end, @BeginNotLatex := function() local alt_node; alt_node := DocumentationVerbatim( "Alt", rec( Not := "LaTeX" ), [ ] ); Add( CurrentItem(), alt_node ); Add( context_stack, alt_node!.content ); if current_command[ 2 ] <> "" then Add( CurrentItem(), current_command[ 2 ] ); fi; end, @EndNotLatex := function() autodoc_read_line := false; Remove( context_stack ); end, @NotLatex := function() Add( CurrentItem(), DocumentationVerbatim( "Alt", rec( Not := "LaTeX" ), [ current_command[ 2 ] ] ) ); 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, @ExampleSession := function() local example_node; example_node := ReadSessionExample( "Example", plain_text_mode ); Add( CurrentItem(), example_node ); end, @BeginExampleSession := ~.@ExampleSession, @LogSession := function() local example_node; example_node := ReadSessionExample( "Log", plain_text_mode ); Add( CurrentItem(), 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" ]; single_line_title_item_list := [ "Title", "Subtitle", "Version", "Author", "Date" ]; CreateTitleItemFunction := function( name ) return function() if not IsBound( tree!.TitlePage.( name ) ) then tree!.TitlePage.( name ) := [ ]; fi; SetCurrentItem( tree!.TitlePage.( name ) ); active_title_item_name := name; active_title_item_is_multiline := Position( single_line_title_item_list, name ) = fail; Add( CurrentItem(), current_command[ 2 ] ); end; end; ## Note that we need to create these functions in the helper function ## CreateTitleItemFunction 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 ) ) := CreateTitleItemFunction( title_item ); od; rest_of_file_skipped := false; ##Now read the files. for filename in filename_list do if IsString( filename ) then display_filename := filename; else display_filename := filename.display; filename := filename.path; fi; Reset(); ##Need to set autodoc_read_line to false again since we now look at a new file. autodoc_read_line := false; ## 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 ); current_line_info := NormalizeInputLine( current_line_unedited ); NormalizeWhitespace( current_line ); if plain_text_mode then if xml_comment_mode then current_command := [ "STRING", current_line_unedited ]; if PositionSublist( current_line_unedited, "-->" ) <> fail then xml_comment_mode := false; fi; command_function_record.STRING(); continue; fi; comment_start_pos := PositionSublist( current_line_unedited, "" ) = fail then xml_comment_mode := true; fi; command_function_record.STRING(); continue; fi; fi; if current_line_info.is_autodoc then current_line_fence := MarkdownFenceFromLine( current_line_info.text ); current_command := Scan_for_AutoDoc_Part( current_line_info.text ); else current_line_fence := fail; current_command := [ false, current_line ]; fi; current_line_is_fence_delimiter := false; if current_line_fence <> fail then if markdown_fence = fail then current_line_is_fence_delimiter := true; else current_line_is_fence_delimiter := IsMatchingMarkdownFence( markdown_fence, current_line_fence ); fi; fi; if current_line_is_fence_delimiter then current_command := [ "STRING", current_line_info.text ]; elif markdown_fence <> fail and current_command[ 1 ] <> false then current_command := [ "STRING", current_line_info.text ]; fi; if current_command[ 1 ] <> false then autodoc_read_line := current_line_info.allows_declaration_scan; if Position( title_item_list, current_command[ 1 ]{ [ 2 .. Length( current_command[ 1 ] ) ] } ) = fail and current_command[ 1 ] <> "STRING" then active_title_item_name := fail; active_title_item_is_multiline := false; 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 ])(); if current_line_is_fence_delimiter then if markdown_fence = fail then markdown_fence := current_line_fence; else markdown_fence := fail; fi; fi; continue; fi; current_line := current_command[ 2 ]; if autodoc_read_line then autodoc_read_line := false; ScanForDeclarationPart( ); fi; od; CloseStream( filestream ); od; end ); AutoDoc-2026.05.03/gap/ToolFunctions.gd0000644000000000000000000000157115175510000014264 0ustar00# 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_LineStartsCDATA" ); DeclareGlobalFunction( "AUTODOC_LineEndsCDATA" ); DeclareGlobalFunction( "AUTODOC_EscapeCDATAContent" ); DeclareGlobalFunction( "AUTODOC_OutputTextFile" ); DeclareGlobalFunction( "AUTODOC_WriteDocumentationListWithSource" ); DeclareGlobalFunction( "AUTODOC_WriteStringListWithSource" ); DeclareGlobalFunction( "AutoDoc_WriteDocEntry" ); DeclareGlobalFunction( "AUTODOC_Diff" ); DeclareGlobalFunction( "AUTODOC_TestWorkSheet" ); DeclareGlobalFunction( "AUTODOC_FormatDate" ); DeclareGlobalFunction( "AUTODOC_ParseDate" ); AutoDoc-2026.05.03/gap/ToolFunctions.gi0000644000000000000000000004607715175510000014303 0ustar00# 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 result, JoinRelativePath, AddMatchingFiles, d_rel; result := []; JoinRelativePath := function( dir, entry ) if dir = "" then return entry; fi; return Concatenation( dir, "/", entry ); end; AddMatchingFiles := function( abs_dir, rel_dir, recursive ) local abs_dir_obj, entries, entry, abs_entry, rel_entry; abs_dir_obj := Directory( abs_dir ); entries := DirectoryContents( abs_dir_obj ); Sort( entries ); for entry in entries do if entry = "." or entry = ".." then continue; fi; abs_entry := Filename( abs_dir_obj, entry ); rel_entry := JoinRelativePath( rel_dir, entry ); if IsDirectoryPath( abs_entry ) then if recursive then AddMatchingFiles( abs_entry, rel_entry, true ); fi; elif AUTODOC_GetSuffix( entry ) in extensions and IsReadableFile( abs_entry ) then Add( result, rel_entry ); fi; od; end; for d_rel in subdirs do if d_rel = "" or d_rel = "." then AddMatchingFiles( Filename( pkgdir, "" ), "", false ); elif not IsDirectoryPath( Filename( pkgdir, d_rel ) ) then continue; else AddMatchingFiles( Filename( pkgdir, d_rel ), d_rel, true ); fi; od; return result; end ); # Ensure that the directory named by the given path string exists, creating any # missing parent directories on the way. Relative paths are accepted and `.` / # `..` components are normalized before creating directories. InstallGlobalFunction( "AUTODOC_CreateDirIfMissing", function(d) local tmp, components, normalized, current, component; if not IsDirectoryPath(d) then components := SplitString( d, "/" ); normalized := [ ]; for component in components do if component = "" or component = "." then continue; elif component = ".." then if StartsWith( d, "/" ) then if Length( normalized ) > 0 then Remove( normalized ); fi; elif Length( normalized ) > 0 and Last( normalized ) <> ".." then Remove( normalized ); else Add( normalized, component ); fi; else Add( normalized, component ); fi; od; current := ""; if StartsWith( d, "/" ) then current := "/"; fi; for component in normalized do Append( current, component ); Append( current, "/" ); if not IsDirectoryPath( current ) then tmp := CreateDir( current ); # Note: CreateDir is currently undocumented if tmp = fail then Error("Cannot create directory ", current, "\n", "Error message: ", LastSystemError().message, "\n"); return false; fi; fi; od; 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_LineStartsCDATA", function(line) # Phase 1 keeps CDATA encoded as raw strings; Parser.gi still injects such # fragments directly, so other layers must continue to detect them. return PositionSublist(line, " fail; end); InstallGlobalFunction( "AUTODOC_LineEndsCDATA", function(line) return PositionSublist(line, "]]>") <> fail; end); InstallGlobalFunction( "AUTODOC_EscapeCDATAContent", function(text) return ReplacedString(text, "]]>", "]]]]>"); 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 ) local return_value, return_value_sources, description, description_sources, current_description, labels, i, item_type_info; # 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; return_value_sources := i!.return_value_source_positions; break; elif IsBool( i!.return_value ) then return_value := i!.return_value; return_value_sources := [ ]; break; fi; fi; od; if not IsBound( return_value ) then return_value := false; return_value_sources := [ ]; 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 := [ ]; description_sources := [ ]; for i in list_of_records do current_description := i!.description; if IsString( current_description ) then current_description := [ current_description ]; fi; Append( description, current_description ); Append( description_sources, i!.description_source_positions ); 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 item_type_info := AUTODOC_ITEM_TYPE_INFO.( i!.item_type ); if IsBound( item_type_info.item_type_override ) then AppendTo( filestream, " <", item_type_info.item_type_override, " " ); else AppendTo( filestream, " <", i!.item_type, " " ); fi; if item_type_info.is_function_like and i!.arguments <> fail then AppendTo( filestream, "Arg=\"", i!.arguments, "\" " ); fi; if IsBound( item_type_info.filter_type ) then AppendTo( filestream, "Type=\"", item_type_info.filter_type, "\" " ); 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, " " ); AUTODOC_WriteDocumentationListWithSource( return_value, return_value_sources, filestream ); AppendTo( filestream, "\n" ); fi; AppendTo( filestream, " \n" ); AUTODOC_WriteDocumentationListWithSource( description, description_sources, filestream ); AppendTo( filestream, " \n" ); AppendTo( filestream, "\n\n" ); end ); InstallGlobalFunction( AUTODOC_WriteDocumentationListWithSource, function( node_list, source_positions, filestream ) local current_source_positions, current_string_list, i, next_source_index, FlushConvertedStrings; FlushConvertedStrings := function() AUTODOC_WriteStringListWithSource( current_string_list, current_source_positions, filestream ); current_string_list := [ ]; current_source_positions := [ ]; end; current_string_list := [ ]; current_source_positions := [ ]; next_source_index := 1; for i in [ 1 .. Length( node_list ) ] do if IsString( node_list[ i ] ) then Add( current_string_list, ShallowCopy( node_list[ i ] ) ); if source_positions = fail or next_source_index > Length( source_positions ) then Add( current_source_positions, fail ); else Add( current_source_positions, source_positions[ next_source_index ] ); fi; next_source_index := next_source_index + 1; else FlushConvertedStrings(); WriteDocumentation( node_list[ i ], filestream ); fi; od; FlushConvertedStrings(); end ); InstallGlobalFunction( AUTODOC_WriteStringListWithSource, function( string_list, source_positions, filestream ) local converted_string_list, in_cdata, item; if string_list = [ ] then return; fi; converted_string_list := AUTODOC_ConvertMarkdownToGAPDocXML( string_list, source_positions ); in_cdata := false; for item in converted_string_list do if not IsString( item ) then WriteDocumentation( item, filestream ); continue; fi; if AUTODOC_LineStartsCDATA( item ) then in_cdata := true; fi; if in_cdata = true then AppendTo( filestream, Chomp( item ), "\n" ); else WriteDocumentation( item, filestream ); fi; if AUTODOC_LineEndsCDATA( item ) then in_cdata := false; fi; od; 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 first 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. An optional second argument can be used # to override the options passed to AutoDocWorksheet for a single test case. # # Then AUTODOC_TestWorkSheet will again run AutoDocWorksheet, storing the # output in a temporary directory; it recursively compares all files present in # the expected output tree so worksheet fixtures can cover nested generated # output as well. If no differences exist, it outputs nothing. InstallGlobalFunction( AUTODOC_TestWorkSheet, function(arg...) local ws, options, wsdir, sheetdir, expecteddir, actualdir, filenames, old, tmpdir, compare_files, worksheet_options, key; if Length( arg ) = 0 or Length( arg ) > 2 then Error("usage: AUTODOC_TestWorkSheet( [, ] )"); fi; ws := arg[1]; if Length( arg ) = 2 then options := arg[2]; else options := rec( ); fi; # Recurse into expected subdirectories so worksheet fixtures can verify # nested output trees such as generated test files below `tst/generated`. compare_files := function(expected, actual) local names, f, expected_path, actual_path; if IsDirectoryPath(expected) then if not IsDirectoryPath(actual) then Error("expected directory ", actual); fi; expected := Directory(expected); actual := Directory(actual); names := DirectoryContents(expected); names := Filtered(names, f -> f <> "." and f <> ".."); Sort(names); for f in names do expected_path := Filename(expected, f); actual_path := Filename(actual, f); if not IsDirectoryPath(actual_path) and not IsReadableFile(actual_path) then Error("missing generated file ", actual_path); fi; compare_files(expected_path, actual_path); od; return; fi; if not IsReadableFile(actual) then Error("missing generated file ", actual); fi; if 0 <> AUTODOC_Diff("-u", expected, actual) then Error("diff detected in file ", actual); fi; end; # 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 in a writable temporary location tmpdir := Filename(DirectoryTemporary(), Concatenation("autodoc-", ws, ".actual")); if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; AUTODOC_CreateDirIfMissing(tmpdir); actualdir := tmpdir; 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); # Start from the standard worksheet test options, then apply any # per-test overrides supplied by the caller. worksheet_options := rec( dir := actualdir, extract_examples := true ); for key in RecNames( options ) do worksheet_options.( key ) := options.( key ); od; AutoDocWorksheet(filenames, worksheet_options : nopdf); SetInfoLevel(InfoGAPDoc, old); # Check the results compare_files(expecteddir, actualdir); RemoveDirectoryRecursively(tmpdir); end); # Parse a date given as a string. Currently only supports the two formats # allowed in PackageInfo.g, namely "DD/MM/YYYY" or "YYYY-MM-DD". Returns a # record with entries `year`, `month`, `day` bound to the corresponding # integers extracted from the input string. # # Returns `fail` if the input could not be parsed. InstallGlobalFunction( AUTODOC_ParseDate, function(date) local day, month, year; if Length(date) <> 10 then return fail; fi; if date{[3,6]} = "//" then day := Int(date{[1,2]}); month := Int(date{[4,5]}); year := Int(date{[7..10]}); elif date{[5,8]} = "--" then day := Int(date{[9,10]}); month := Int(date{[6,7]}); year := Int(date{[1..4]}); else return fail; fi; if day = fail or month = fail or year = fail then return fail; fi; return rec( day := day, month := month, year := year ); 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]]) # - AUTODOC_FormatDate(date_str) where date_str is a string of the form "DD/MM/YYYY" or "YYYY-MM-DD" # 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) = 1 and IsString(arg[1]) then date := AUTODOC_ParseDate(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) or date = fail 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-2026.05.03/init.g0000644000000000000000000000076315175510000011510 0ustar00# 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-2026.05.03/makedoc.g0000644000000000000000000000116615175510000012146 0ustar00# 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 := rec( files := [ "doc/Overview.autodoc", "doc/Tutorials.autodoc", "doc/Comments.autodoc" ], ), gapdoc := rec( LaTeXOptions := rec( EarlyExtraPreamble := """ \usepackage{a4wide} \newcommand{\bbZ}{\mathbb{Z}} """ ) ), scaffold := rec( bib := "bib.xml", ) )); AutoDoc-2026.05.03/read.g0000644000000000000000000000076315175510000011460 0ustar00# 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-2026.05.03/regen_tests.g0000644000000000000000000001536215175510000013070 0ustar00if fail = LoadPackage("AutoDoc") then Error("failed to load AutoDoc package"); fi; LoadPackage("io", false); SetInfoLevel(InfoAutoDoc, 1); SetInfoLevel(InfoGAPDoc, 0); AUTODOC_IsGeneratedXMLFile := function(path) local content, name; if not IsReadableFile(path) or PositionSublist(path, ".xml") <> Length(path) - 3 then return false; fi; name := Last(SplitString(path, "/")); if name in [ "_Chunks.xml", "_entities.xml" ] then return true; fi; content := StringFile(path); return PositionSublist(content, "This is an automatically generated file") <> fail; end; AUTODOC_RegenWorkSheetExpected := function(wsdir, ws) local sheetdir, expecteddir, tmpdir, actualdir, filenames, old, f, tstfiles, x, actualtstdir, expectedtstdir; sheetdir := Filename(wsdir, Concatenation(ws, ".sheet")); if not IsString(sheetdir) or not IsDirectoryPath(sheetdir) then Error("could not access tst/worksheets/", ws, ".sheet/"); fi; sheetdir := Directory(sheetdir); expecteddir := Filename(wsdir, Concatenation(ws, ".expected")); if IsDirectoryPath(expecteddir) then RemoveDirectoryRecursively(expecteddir); fi; AUTODOC_CreateDirIfMissing(expecteddir); expecteddir := Directory(expecteddir); # Generate worksheet output outside the package tree so GAPDoc resolves # _Chunks.xml relative to the output dir instead of re-prefixing the # package-local path. tmpdir := Filename(DirectoryTemporary(), Concatenation("autodoc-regen-", ws, ".expected")); if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; AUTODOC_CreateDirIfMissing(tmpdir); actualdir := Directory(tmpdir); filenames := DirectoryContents(sheetdir); filenames := Filtered(filenames, f -> f <> "." and f <> ".."); filenames := Filtered(filenames, f -> not IsDirectoryPath(Filename(sheetdir, f))); Sort(filenames); filenames := List(filenames, f -> Filename(sheetdir, f)); old := InfoLevel(InfoGAPDoc); SetInfoLevel(InfoGAPDoc, 0); AutoDocWorksheet(filenames, rec(dir := actualdir, extract_examples := true) : nopdf); SetInfoLevel(InfoGAPDoc, old); # Keep only deterministic reference outputs. filenames := DirectoryContents(actualdir); filenames := Filtered(filenames, f -> f <> "." and f <> ".."); for f in filenames do if f = "tst" then AUTODOC_CreateDirIfMissing(Filename(expecteddir, "tst")); actualtstdir := Directory(Filename(actualdir, "tst")); expectedtstdir := Directory(Filename(expecteddir, "tst")); tstfiles := DirectoryContents(actualtstdir); tstfiles := Filtered(tstfiles, x -> x <> "." and x <> ".."); for x in tstfiles do if PositionSublist(x, ".tst") = Length(x) - 3 then Exec(Concatenation( "cp \"", Filename(actualtstdir, x), "\" \"", Filename(expectedtstdir, x), "\"" )); fi; od; continue; fi; if PositionSublist(f, ".xml") = Length(f) - 3 then Exec(Concatenation( "cp \"", Filename(actualdir, f), "\" \"", Filename(expecteddir, f), "\"" )); fi; od; RemoveDirectoryRecursively(tmpdir); end; AUTODOC_DetectedWorkSheets := function(wsdir) local entries; entries := DirectoryContents(wsdir); entries := Filtered(entries, f -> f <> "." and f <> ".."); entries := Filtered(entries, f -> IsDirectoryPath(Filename(wsdir, f)) and Length(f) > 6 and PositionSublist(f, ".sheet") = Length(f) - 5); Sort(entries); # Ignore empty placeholder directories which are not runnable worksheets. entries := Filtered(entries, f -> Length(Filtered(DirectoryContents(Filename(wsdir, f)), x -> x <> "." and x <> "..")) > 0); return List(entries, f -> f{[1 .. Length(f) - 6]}); end; AUTODOC_RegenAllWorkSheetExpected := function() local wsdir, ws; wsdir := DirectoriesPackageLibrary("AutoDoc", "tst/worksheets"); wsdir := wsdir[1]; if not IsDirectoryPath(wsdir) then Error("could not access tst/worksheets/"); fi; for ws in AUTODOC_DetectedWorkSheets(wsdir) do Print("Now processing sheet tst/worksheets/", ws, ".sheet/\n"); AUTODOC_RegenWorkSheetExpected(wsdir, ws); od; end; AUTODOC_RegenManualExpected := function(pkgdir) local olddir, tempdir, expecteddir, files, old_gapdoc_level, old_warning_level, file, docdir; if not IsDirectoryPath(pkgdir) then Error("could not access package directory"); fi; olddir := AUTODOC_CurrentDirectory(); tempdir := Filename(DirectoryTemporary(), "autodoc-manual-expected"); if IsDirectoryPath(tempdir) then RemoveDirectoryRecursively(tempdir); fi; Exec(Concatenation("cp -R \"", Filename(pkgdir, ""), "\" \"", tempdir, "\"")); if not IsDirectoryPath(tempdir) then Error("failed to create temporary package copy"); fi; docdir := Concatenation(tempdir, "/doc"); files := DirectoryContents(docdir); files := Filtered(files, f -> f <> "." and f <> ".." and AUTODOC_IsGeneratedXMLFile(Concatenation(docdir, "/", f))); for file in files do RemoveFile(Concatenation(docdir, "/", file)); od; old_gapdoc_level := InfoLevel(InfoGAPDoc); old_warning_level := InfoLevel(InfoWarning); SetInfoLevel(InfoGAPDoc, 0); SetInfoLevel(InfoWarning, 0); ChangeDirectoryCurrent(tempdir); Read("makedoc.g" : nopdf); ChangeDirectoryCurrent(olddir); SetInfoLevel(InfoGAPDoc, old_gapdoc_level); SetInfoLevel(InfoWarning, old_warning_level); expecteddir := Filename(pkgdir, "tst/manual.expected"); if IsDirectoryPath(expecteddir) then RemoveDirectoryRecursively(expecteddir); fi; AUTODOC_CreateDirIfMissing(expecteddir); docdir := Concatenation(tempdir, "/doc"); files := DirectoryContents(docdir); files := Filtered(files, f -> f <> "." and f <> ".." and AUTODOC_IsGeneratedXMLFile(Concatenation(docdir, "/", f))); Sort(files); for file in files do Exec(Concatenation( "cp \"", docdir, "/", file, "\" \"", expecteddir, "/", file, "\"" )); od; RemoveDirectoryRecursively(tempdir); end; AUTODOC_RegenAllWorkSheetExpected(); AUTODOC_RegenManualExpected(DirectoriesPackageLibrary("AutoDoc", "")[1]); AUTODOC_RegenManualExpected(DirectoriesPackageLibrary("AutoDoc", "tst/AutoDocTest")[1]); TestDirectory( DirectoriesPackageLibrary("AutoDoc", "tst"), rec(rewriteToFile := true ) ); QUIT_GAP(0); AutoDoc-2026.05.03/tst/0000755000000000000000000000000015175510000011201 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/0000755000000000000000000000000015175510000013377 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/.gitignore0000644000000000000000000000006015175510000015363 0ustar00/doc/_*.xml /doc/AutoDocTest.xml /doc/title.xml AutoDoc-2026.05.03/tst/AutoDocTest/Makefile0000644000000000000000000000034015175510000015034 0ustar00.PHONY: doc html check GAP ?= gap GAP_ARGS = -q --quitonbreak --packagedirs . doc: $(GAP) $(GAP_ARGS) makedoc.g -c 'QUIT;' html: NOPDF=1 $(GAP) $(GAP_ARGS) makedoc.g -c 'QUIT;' check: $(GAP) $(GAP_ARGS) tst/testall.g AutoDoc-2026.05.03/tst/AutoDocTest/PackageInfo.g0000644000000000000000000000415615175510000015724 0ustar00# # AutoDocTest: A minimal GAP package for testing AutoDoc features # # This file contains package meta data. For additional information on # the meaning and correct usage of these fields, please consult the # manual of the "Example" package as well as the comments in its # PackageInfo.g file. # SetPackageInfo( rec( PackageName := "AutoDocTest", Subtitle := "A minimal GAP package for testing AutoDoc features", Version := "0.1", Date := "11/03/2026", # dd/mm/yyyy format License := "GPL-2.0-or-later", Persons := [ rec( IsAuthor := true, IsMaintainer := true, FirstNames := "Active", LastName := "Author", WWWHome := "https://AutoDocTest.gap-system.org/~author", Email := "a.author@AutoDocTest.gap-system.org", ), rec( IsAuthor := true, IsMaintainer := false, FirstNames := "Retired", LastName := "Author", Email := "r.author@AutoDocTest.gap-system.org", ), rec( IsAuthor := false, IsMaintainer := true, FirstNames := "Only", LastName := "Maintainer", WWWHome := "https://AutoDocTest.gap-system.org/~maintainer", ), rec( IsAuthor := false, IsMaintainer := false, FirstNames := "Some", LastName := "Contributor", ), ], #SourceRepository := rec( Type := "TODO", URL := "URL" ), #IssueTrackerURL := "TODO", #SupportEmail := "TODO", PackageWWWHome := "https://AutoDocTest.gap-system.org/", PackageInfoURL := Concatenation( ~.PackageWWWHome, "PackageInfo.g" ), README_URL := Concatenation( ~.PackageWWWHome, "README.md" ), ArchiveURL := Concatenation( ~.PackageWWWHome, "/", ~.PackageName, "-", ~.Version ), ArchiveFormats := ".tar.gz", AbstractHTML := "", PackageDoc := rec( BookName := "AutoDocTest", ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := "A minimal GAP package for testing AutoDoc features", ), Dependencies := rec( GAP := ">= 4.9", NeededOtherPackages := [ ], SuggestedOtherPackages := [ ], ExternalConditions := [ ], ), AvailabilityTest := ReturnTrue, TestFile := "tst/testall.g", )); AutoDoc-2026.05.03/tst/AutoDocTest/README.md0000644000000000000000000000013715175510000014657 0ustar00# The GAP 4 package `AutoDocTest` This is a minimal GAP package for testing AutoDoc features. AutoDoc-2026.05.03/tst/AutoDocTest/doc/0000755000000000000000000000000015175510000014144 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/doc/AutoDocTest.bib0000644000000000000000000000026715175510000017025 0ustar00@manual{GAP4, organization = {The GAP Group}, title = {GAP -- Groups, Algorithms, and Programming, Version 4.15.1}, year = {2025}, note = {\url{https://www.gap-system.org}} } AutoDoc-2026.05.03/tst/AutoDocTest/doc/appendix.autodoc0000644000000000000000000000021615175510000017333 0ustar00@Appendix Plain-text appendix This appendix is written in `.autodoc` format and is expected to be included through scaffold.appendix. AutoDoc-2026.05.03/tst/AutoDocTest/doc/appendix1.xml0000644000000000000000000000042415175510000016557 0ustar00 XML fixture appendix

This hand-written XML appendix exercises the existing scaffold.appendix hook alongside generated @Appendix content. AutoDoc-2026.05.03/tst/AutoDocTest/doc/chapter1.xml0000644000000000000000000000102715175510000016375 0ustar00 XML fixture chapter

This hand-written XML chapter keeps one explicit include in the AutoDocTest manual and cites the main &GAP; reference .

Purpose

The content is intentionally short, but it gives the package-context tests a deterministic chapter to compare against stored reference XML.

AutoDoc-2026.05.03/tst/AutoDocTest/doc/chapter2.autodoc0000644000000000000000000000112415175510000017232 0ustar00@Chapter Plain-text fixture chapter @ChapterLabel PlainTextFixture @Section Cross references @SectionLabel PlainTextCrossRefs This `.autodoc` chapter cross-references and mentions AutoDocTest_Operation, AutoDocTest_Attribute, and AutoDocTest_Property. It therefore checks that `makedoc.g` also scans the package source files. @Section Short example @SectionLabel PlainTextExample The source-backed entries are supplemented by this small plain-text chapter so the fixture package covers both hand-written XML and `.autodoc` input. AutoDoc-2026.05.03/tst/AutoDocTest/doc/extract-examples.xml0000644000000000000000000000126715175510000020162 0ustar00 Extract examples fixture
Empty section

This section intentionally contains no examples, so tests can check skip_empty_in_numbering.

First example section

2 + 3; 5 ]]>

Second example section

6 * 7; 42 ]]>

AutoDoc-2026.05.03/tst/AutoDocTest/gap/0000755000000000000000000000000015175510000014146 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/gap/AutoDocTest.gd0000644000000000000000000000174115175510000016663 0ustar00# # AutoDocTest: A minimal GAP package for testing AutoDoc features # # Declarations # #! #! @Chapter Source API #! @ChapterLabel SourceAPI #! @Section Declarations #! @SectionLabel SourceDeclarations #! `AutoDocTest_GlobalFunction` is a documented placeholder used by the #! package-context regression manual. DeclareGlobalFunction( "AutoDocTest_GlobalFunction" ); #! #! `AutoDocTest_Operation` takes an object together with a positive integer #! and returns that integer unchanged. DeclareOperation( "AutoDocTest_Operation", [ IsObject, IsInt ] ); #! #! `AutoDocTest_Attribute` records a small attribute entry for solvable groups. DeclareAttribute( "AutoDocTest_Attribute", IsGroup ); #! #! `AutoDocTest_Property` is a tiny property used to exercise method docs. DeclareProperty( "AutoDocTest_Property", IsGroup ); #! #! `AutoDocTest_Method` is declared separately so the fixture package loads #! cleanly when building its manual. DeclareOperation( "AutoDocTest_Method", [ IsGroup ] ); AutoDoc-2026.05.03/tst/AutoDocTest/gap/AutoDocTest.gi0000644000000000000000000000203015175510000016660 0ustar00# # AutoDocTest: A minimal GAP package for testing AutoDoc features # # Implementations # #! #! @Chapter Source API #! @ChapterLabel SourceAPI #! @Section Implementations #! @SectionLabel SourceImplementations #! The global function prints a stable sentence so it is easy to mention in the #! mock manual. InstallGlobalFunction( AutoDocTest_GlobalFunction, function() Print( "This is a placeholder function, replace it with your own code.\n" ); end ); #! #! The method for `AutoDocTest_Operation` returns the second argument. #! @ItemType Oper InstallMethod( AutoDocTest_Operation, [ IsGroup, IsPosInt ], { G, n } -> n ); #! #! The attribute method simply returns the group itself. #! @ItemType Attr InstallMethod( AutoDocTest_Attribute, [ IsSolvableGroup ], G -> G ); #! #! The property method reuses `IsAbelian` for nilpotent groups. #! @ItemType Prop InstallMethod( AutoDocTest_Property, [ IsNilpotentGroup ], IsAbelian ); #! #! A method installation without an itemtype InstallMethod( AutoDocTest_Method, [ IsPerfectGroup ], G -> G ); AutoDoc-2026.05.03/tst/AutoDocTest/init.g0000644000000000000000000000006315175510000014511 0ustar00ReadPackage( "AutoDocTest", "gap/AutoDocTest.gd"); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-entities-list.g0000644000000000000000000000076415175510000017754 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc", "doc/appendix.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], appendix := [ "appendix1.xml" ], bib := "AutoDocTest.bib", bibstyle := "alphaurl", entities := [ "Legacy Package", [ "Package", "LegacyListEntity" ], [ "Phrase", "legacy list entity" ], ], ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-entities-record.g0000644000000000000000000000075415175510000020256 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc", "doc/appendix.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], appendix := [ "appendix1.xml" ], bib := "AutoDocTest.bib", bibstyle := "alphaurl", entities := rec( AutoDocTestTag := "RecordEntity", RECORDNOTE := "record entity", ), ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-examples-chapter.g0000644000000000000000000000030615175510000020411 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := false, gapdoc := rec( files := [ ], ), scaffold := rec( includes := [ "extract-examples.xml" ], ), extract_examples := true, )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-examples-section-keepempty.g0000644000000000000000000000041015175510000022424 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := false, gapdoc := rec( files := [ ], ), scaffold := rec( includes := [ "extract-examples.xml" ], ), extract_examples := rec( units := "Section", skip_empty_in_numbering := false, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-examples-section-skipempty.g0000644000000000000000000000040715175510000022454 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := false, gapdoc := rec( files := [ ], ), scaffold := rec( includes := [ "extract-examples.xml" ], ), extract_examples := rec( units := "Section", skip_empty_in_numbering := true, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-examples-section.g0000644000000000000000000000034215175510000020427 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := false, gapdoc := rec( files := [ ], ), scaffold := rec( includes := [ "extract-examples.xml" ], ), extract_examples := rec( units := "Section", ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-notitle-main.g0000644000000000000000000000050515175510000017550 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], bib := "AutoDocTest.bib", TitlePage := false, MainPage := true, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-notitle-nomain.g0000644000000000000000000000050615175510000020106 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], bib := "AutoDocTest.bib", TitlePage := false, MainPage := false, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-title-main.g0000644000000000000000000000050515175510000017213 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], bib := "AutoDocTest.bib", TitlePage := rec(), MainPage := true, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc-title-nomain.g0000644000000000000000000000050615175510000017551 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], bib := "AutoDocTest.bib", TitlePage := rec(), MainPage := false, ), )); AutoDoc-2026.05.03/tst/AutoDocTest/makedoc.g0000644000000000000000000000056015175510000015153 0ustar00LoadPackage("AutoDoc"); AutoDoc(rec( autodoc := rec( files := [ "doc/chapter2.autodoc", "doc/appendix.autodoc" ], ), gapdoc := rec( files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ], ), scaffold := rec( includes := [ "chapter1.xml" ], appendix := [ "appendix1.xml" ], bib := "AutoDocTest.bib", bibstyle := "alphaurl", ), )); AutoDoc-2026.05.03/tst/AutoDocTest/read.g0000644000000000000000000000006315175510000014461 0ustar00ReadPackage( "AutoDocTest", "gap/AutoDocTest.gi"); AutoDoc-2026.05.03/tst/AutoDocTest/tst/0000755000000000000000000000000015175510000014211 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-chapter.expected/0000755000000000000000000000000015175510000021253 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-chapter.expected/autodoctest01.tst0000644000000000000000000000113715175510000024510 0ustar00# AutoDocTest, 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("autodoctest01.tst"); # doc/extract-examples.xml:14-17 gap> 2 + 3; 5 # doc/extract-examples.xml:22-25 gap> 6 * 7; 42 # gap> STOP_TEST("autodoctest01.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-keepempty.expected/0000755000000000000000000000000015175510000023272 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-keepempty.expected/autodoctest02.tst0000644000000000000000000000105615175510000026530 0ustar00# AutoDocTest, section 2 # # 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("autodoctest02.tst"); # doc/extract-examples.xml:14-17 gap> 2 + 3; 5 # gap> STOP_TEST("autodoctest02.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-keepempty.expected/autodoctest03.tst0000644000000000000000000000105715175510000026532 0ustar00# AutoDocTest, section 3 # # 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("autodoctest03.tst"); # doc/extract-examples.xml:22-25 gap> 6 * 7; 42 # gap> STOP_TEST("autodoctest03.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-skipempty.expected/0000755000000000000000000000000015175510000023314 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-skipempty.expected/autodoctest01.tst0000644000000000000000000000105615175510000026551 0ustar00# AutoDocTest, section 2 # # 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("autodoctest01.tst"); # doc/extract-examples.xml:14-17 gap> 2 + 3; 5 # gap> STOP_TEST("autodoctest01.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section-skipempty.expected/autodoctest02.tst0000644000000000000000000000105715175510000026553 0ustar00# AutoDocTest, section 3 # # 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("autodoctest02.tst"); # doc/extract-examples.xml:22-25 gap> 6 * 7; 42 # gap> STOP_TEST("autodoctest02.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section.expected/0000755000000000000000000000000015175510000021271 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section.expected/autodoctest01.tst0000644000000000000000000000105615175510000024526 0ustar00# AutoDocTest, section 2 # # 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("autodoctest01.tst"); # doc/extract-examples.xml:14-17 gap> 2 + 3; 5 # gap> STOP_TEST("autodoctest01.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/examples-section.expected/autodoctest02.tst0000644000000000000000000000105715175510000024530 0ustar00# AutoDocTest, section 3 # # 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("autodoctest02.tst"); # doc/extract-examples.xml:22-25 gap> 6 * 7; 42 # gap> STOP_TEST("autodoctest02.tst", 1); AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/0000755000000000000000000000000015175510000022061 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/PaxHeaders/_Appendix_Plain-text0000644000000000000000000000016015175510000030151 xustar00112 path=AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_Appendix_Plain-text_appendix.xml AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_Appendix_Plain-text_appendix.x0000644000000000000000000000047615175510000030165 0ustar00 Plain-text appendix

This appendix is written in .autodoc format and is expected to be included through scaffold.appendix. AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_AutoDocAppendicesMainFile.xml0000644000000000000000000000022015175510000027673 0ustar00 <#Include SYSTEM "_Appendix_Plain-text_appendix.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_AutoDocMainFile.xml0000644000000000000000000000026715175510000025712 0ustar00 <#Include SYSTEM "_Chapter_PlainTextFixture.xml"> <#Include SYSTEM "_Chapter_SourceAPI.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_Chapter_PlainTextFixture.xml0000644000000000000000000000151015175510000027664 0ustar00 Plain-text fixture chapter

Cross references

This .autodoc chapter cross-references and mentions AutoDocTest_Operation, AutoDocTest_Attribute, and AutoDocTest_Property. It therefore checks that makedoc.g also scans the package source files.

Short example

The source-backed entries are supplemented by this small plain-text chapter so the fixture package covers both hand-written XML and .autodoc input.

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_Chapter_SourceAPI.xml0000644000000000000000000000476715175510000026220 0ustar00 Source API
Declarations AutoDocTest_GlobalFunction is a documented placeholder used by the package-context regression manual.

AutoDocTest_Operation takes an object together with a positive integer and returns that integer unchanged.

AutoDocTest_Attribute records a small attribute entry for solvable groups.

AutoDocTest_Property is a tiny property used to exercise method docs. true or false

AutoDocTest_Method is declared separately so the fixture package loads cleanly when building its manual.

Implementations The global function prints a stable sentence so it is easy to mention in the mock manual.

The method for AutoDocTest_Operation returns the second argument.

The attribute method simply returns the group itself.

The property method reuses IsAbelian for nilpotent groups.

A method installation without an itemtype

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_Chunks.xml0000644000000000000000000000000015175510000024163 0ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_entities.xml0000644000000000000000000000052315175510000024566 0ustar00AutoDocTest'> Legacy Package'> LegacyListEntity'> legacy list entity'> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/_main.xml0000644000000000000000000000076315175510000023674 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "chapter1.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> <#Include SYSTEM "appendix1.xml"> <#Include SYSTEM "_AutoDocAppendicesMainFile.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-list.expected/title.xml0000644000000000000000000000105415175510000023724 0ustar00 AutoDocTest A minimal &GAP; package for testing AutoDoc features 0.1 Active Author a.author@AutoDocTest.gap-system.org https://AutoDocTest.gap-system.org/~author Retired Author r.author@AutoDocTest.gap-system.org 11 March 2026 AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/0000755000000000000000000000000015175510000022364 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/PaxHeaders/_Appendix_Plain-te0000644000000000000000000000016215175510000030102 xustar00114 path=AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_Appendix_Plain-text_appendix.xml AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_Appendix_Plain-text_appendix0000644000000000000000000000047615175510000030222 0ustar00 Plain-text appendix

This appendix is written in .autodoc format and is expected to be included through scaffold.appendix. AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/PaxHeaders/_AutoDocAppendices0000644000000000000000000000015715175510000030137 xustar00111 path=AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_AutoDocAppendicesMainFile.xml AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_AutoDocAppendicesMainFile.xm0000644000000000000000000000022015175510000030022 0ustar00 <#Include SYSTEM "_Appendix_Plain-text_appendix.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_AutoDocMainFile.xml0000644000000000000000000000026715175510000026215 0ustar00 <#Include SYSTEM "_Chapter_PlainTextFixture.xml"> <#Include SYSTEM "_Chapter_SourceAPI.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_Chapter_PlainTextFixture.xml0000644000000000000000000000151015175510000030167 0ustar00 Plain-text fixture chapter

Cross references

This .autodoc chapter cross-references and mentions AutoDocTest_Operation, AutoDocTest_Attribute, and AutoDocTest_Property. It therefore checks that makedoc.g also scans the package source files.

Short example

The source-backed entries are supplemented by this small plain-text chapter so the fixture package covers both hand-written XML and .autodoc input.

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_Chapter_SourceAPI.xml0000644000000000000000000000476715175510000026523 0ustar00 Source API
Declarations AutoDocTest_GlobalFunction is a documented placeholder used by the package-context regression manual.

AutoDocTest_Operation takes an object together with a positive integer and returns that integer unchanged.

AutoDocTest_Attribute records a small attribute entry for solvable groups.

AutoDocTest_Property is a tiny property used to exercise method docs. true or false

AutoDocTest_Method is declared separately so the fixture package loads cleanly when building its manual.

Implementations The global function prints a stable sentence so it is easy to mention in the mock manual.

The method for AutoDocTest_Operation returns the second argument.

The attribute method simply returns the group itself.

The property method reuses IsAbelian for nilpotent groups.

A method installation without an itemtype

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_Chunks.xml0000644000000000000000000000000015175510000024466 0ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_entities.xml0000644000000000000000000000036215175510000025072 0ustar00AutoDocTest'> RecordEntity'> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/_main.xml0000644000000000000000000000076315175510000024177 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "chapter1.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> <#Include SYSTEM "appendix1.xml"> <#Include SYSTEM "_AutoDocAppendicesMainFile.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual-entities-record.expected/title.xml0000644000000000000000000000105415175510000024227 0ustar00 AutoDocTest A minimal &GAP; package for testing AutoDoc features 0.1 Active Author a.author@AutoDocTest.gap-system.org https://AutoDocTest.gap-system.org/~author Retired Author r.author@AutoDocTest.gap-system.org 11 March 2026 AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/0000755000000000000000000000000015175510000017266 5ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_Appendix_Plain-text_appendix.xml0000644000000000000000000000047615175510000025723 0ustar00 Plain-text appendix

This appendix is written in .autodoc format and is expected to be included through scaffold.appendix. AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_AutoDocAppendicesMainFile.xml0000644000000000000000000000022015175510000025100 0ustar00 <#Include SYSTEM "_Appendix_Plain-text_appendix.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_AutoDocMainFile.xml0000644000000000000000000000026715175510000023117 0ustar00 <#Include SYSTEM "_Chapter_PlainTextFixture.xml"> <#Include SYSTEM "_Chapter_SourceAPI.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_Chapter_PlainTextFixture.xml0000644000000000000000000000151015175510000025071 0ustar00 Plain-text fixture chapter

Cross references

This .autodoc chapter cross-references and mentions AutoDocTest_Operation, AutoDocTest_Attribute, and AutoDocTest_Property. It therefore checks that makedoc.g also scans the package source files.

Short example

The source-backed entries are supplemented by this small plain-text chapter so the fixture package covers both hand-written XML and .autodoc input.

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_Chapter_SourceAPI.xml0000644000000000000000000000476715175510000023425 0ustar00 Source API
Declarations AutoDocTest_GlobalFunction is a documented placeholder used by the package-context regression manual.

AutoDocTest_Operation takes an object together with a positive integer and returns that integer unchanged.

AutoDocTest_Attribute records a small attribute entry for solvable groups.

AutoDocTest_Property is a tiny property used to exercise method docs. true or false

AutoDocTest_Method is declared separately so the fixture package loads cleanly when building its manual.

Implementations The global function prints a stable sentence so it is easy to mention in the mock manual.

The method for AutoDocTest_Operation returns the second argument.

The attribute method simply returns the group itself.

The property method reuses IsAbelian for nilpotent groups.

A method installation without an itemtype

AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_Chunks.xml0000644000000000000000000000000015175510000021370 0ustar00AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_entities.xml0000644000000000000000000000022215175510000021767 0ustar00AutoDocTest'> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/_main.xml0000644000000000000000000000076315175510000021101 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "chapter1.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> <#Include SYSTEM "appendix1.xml"> <#Include SYSTEM "_AutoDocAppendicesMainFile.xml"> AutoDoc-2026.05.03/tst/AutoDocTest/tst/manual.expected/title.xml0000644000000000000000000000105415175510000021131 0ustar00 AutoDocTest A minimal &GAP; package for testing AutoDoc features 0.1 Active Author a.author@AutoDocTest.gap-system.org https://AutoDocTest.gap-system.org/~author Retired Author r.author@AutoDocTest.gap-system.org 11 March 2026 AutoDoc-2026.05.03/tst/AutoDocTest/tst/testall.g0000644000000000000000000000026515175510000016034 0ustar00LoadPackage( "AutoDocTest" ); TestDirectory(DirectoriesPackageLibrary( "AutoDocTest", "tst" ), rec(exitGAP := true)); ForceQuitGap(1); # if we ever get here, there was an error AutoDoc-2026.05.03/tst/autodoc-parser-installmethod.g0000644000000000000000000000026715175510000017153 0ustar00#! @Chapter Parser #! @Section InstallMethod #! @ItemType Func InstallMethod( "MyOp", [ IsInt, IsString ], function( x, y ) return x; end ); AutoDoc-2026.05.03/tst/autodoctest-manual.tst0000644000000000000000000000743715175510000015561 0ustar00############################################################################# ## ## AutoDoc package ## ## Test the behavior of AutoDoc on the minimal AutoDocTest package ## ############################################################################# gap> START_TEST( "autodoctest-manual.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 ); # prepare a temporary package copy and run there gap> olddir := AUTODOC_CurrentDirectory();; gap> pkgdir := DirectoriesPackageLibrary( "AutoDoc", "tst/AutoDocTest" );; gap> pkgdir := pkgdir[1];; gap> pkgdir := Filename( pkgdir, "" );; gap> if not StartsWith( pkgdir, "/" ) then > pkgdir := Concatenation( olddir, "/", pkgdir ); > fi; gap> ReadPackage( "AutoDoc", "tst/utils.g" ); true # baseline manual output gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "manual", > makedoc := "makedoc.g", > doc_expected := "tst/manual.expected", > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "manual-parent-relative", > makedoc := "../../makedoc.g", > workdir := "doc/build", > doc_expected := "tst/manual.expected", > ) ); # entities option variants gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "entities-record", > makedoc := "makedoc-entities-record.g", > doc_expected := "tst/manual-entities-record.expected", > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "entities-list", > makedoc := "makedoc-entities-list.g", > doc_expected := "tst/manual-entities-list.expected", > ) ); # title/main page combinations gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "title-main", > makedoc := "makedoc-title-main.g", > stub_gapdoc := true, > doc_present := [ "_entities.xml", "_main.xml", "title.xml" ], > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "notitle-main", > makedoc := "makedoc-notitle-main.g", > stub_gapdoc := true, > doc_present := [ "_entities.xml", "_main.xml" ], > doc_absent := [ "title.xml" ], > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "title-nomain", > makedoc := "makedoc-title-nomain.g", > stub_gapdoc := true, > doc_present := [ "_entities.xml", "title.xml" ], > doc_absent := [ "_main.xml" ], > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "notitle-nomain", > makedoc := "makedoc-notitle-nomain.g", > stub_gapdoc := true, > doc_present := [ "_entities.xml" ], > doc_absent := [ "_main.xml", "title.xml" ], > ) ); # extract_examples variants gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "examples-chapter", > makedoc := "makedoc-examples-chapter.g", > tst_expected := "tst/examples-chapter.expected", > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "examples-section", > makedoc := "makedoc-examples-section.g", > tst_expected := "tst/examples-section.expected", > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "examples-section-keepempty", > makedoc := "makedoc-examples-section-keepempty.g", > tst_expected := "tst/examples-section-keepempty.expected", > ) ); gap> AUTODOC_RunPackageScenario( pkgdir, olddir, rec( > name := "examples-section-skipempty", > makedoc := "makedoc-examples-section-skipempty.g", > tst_expected := "tst/examples-section-skipempty.expected", > ) ); # restore info levels and current directory gap> SetInfoLevel( InfoGAPDoc, oldGAPDocLevel ); gap> SetInfoLevel( InfoWarning, oldWarningLevel ); gap> ChangeDirectoryCurrent(olddir); true # gap> STOP_TEST( "autodoctest-manual.tst" ); AutoDoc-2026.05.03/tst/dogfood.tst0000644000000000000000000000426115175510000013361 0ustar00############################################################################# ## ## 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 ); # prepare a temporary package copy and run there gap> olddir := AUTODOC_CurrentDirectory();; gap> pkgdir := DirectoriesPackageLibrary( "AutoDoc", "");; # run in a temporary copy, so the package source tree can stay read-only gap> tempdir := Filename(DirectoryTemporary(), "autodoc-dogfood");; gap> if IsDirectoryPath(tempdir) then RemoveDirectoryRecursively(tempdir); fi; gap> Exec(Concatenation("cp -R \"", Filename(pkgdir, ""), "\" \"", tempdir, "\"")); gap> ChangeDirectoryCurrent(tempdir); true # regenerate the manual using AutoDoc gap> Read("makedoc.g" : nopdf); # 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 gap> docdir := Directory(Concatenation(tempdir, "/doc"));; gap> ex_dir := DirectoriesPackageLibrary( "AutoDoc", "tst/manual.expected" );; gap> ex_dir := ex_dir[1];; # check all expected generated files gap> files := DirectoryContents(ex_dir);; gap> files := Filtered(files, f -> f <> "." and f <> "..");; gap> Sort(files); gap> for f in files do > expected := Filename(ex_dir, f);; > actual := Filename(docdir, f);; > if not IsReadableFile(actual) then > Error("missing generated file ", f); > fi; > if 0 <> AUTODOC_Diff("-u", expected, actual) then > Error("diff detected in file ", f); > fi; > od; # gap> RemoveDirectoryRecursively(tempdir); true # gap> STOP_TEST( "dogfood.tst" ); AutoDoc-2026.05.03/tst/errorwithpos/0000755000000000000000000000000015175510000013750 5ustar00AutoDoc-2026.05.03/tst/errorwithpos/break.g0000644000000000000000000000004315175510000015201 0ustar00#! @BREAK parser requested failure AutoDoc-2026.05.03/tst/errorwithpos/chapterlabel-no-chapter.g0000644000000000000000000000003115175510000020576 0ustar00#! @ChapterLabel Missing AutoDoc-2026.05.03/tst/errorwithpos/chaptertitle-no-chapter.g0000644000000000000000000000003115175510000020640 0ustar00#! @ChapterTitle Missing AutoDoc-2026.05.03/tst/errorwithpos/declaration-outside-section.g0000644000000000000000000000013115175510000021514 0ustar00#! keep declaration scanning enabled DeclareOperation( "MissingSection", [ IsObject ] ); AutoDoc-2026.05.03/tst/errorwithpos/declaration-unrecognized-type.g0000644000000000000000000000010015175510000022045 0ustar00#! @Chapter Parser #! @Section Broken DeclareBogus( "Broken" ); AutoDoc-2026.05.03/tst/errorwithpos/declaration-unterminated-filter-list.g0000644000000000000000000000011715175510000023335 0ustar00#! @Chapter Parser #! @Section Broken DeclareOperation( "Broken", [ IsObject AutoDoc-2026.05.03/tst/errorwithpos/declaration-unterminated-header.g0000644000000000000000000000010115175510000022320 0ustar00#! @Chapter Parser #! @Section Broken DeclareOperation( "Broken" AutoDoc-2026.05.03/tst/errorwithpos/grouptitle-no-group.g0000644000000000000000000000007515175510000020064 0ustar00#! @Chapter Parser #! @Section Broken #! @GroupTitle Missing AutoDoc-2026.05.03/tst/errorwithpos/grouptitle-outside-section.g0000644000000000000000000000005115175510000021426 0ustar00#! @Group Example #! @GroupTitle Missing AutoDoc-2026.05.03/tst/errorwithpos/index-empty-key.g0000644000000000000000000000011015175510000017141 0ustar00#! @Chapter Parser #! @Section Broken #! @Description Text #! @Index "" AutoDoc-2026.05.03/tst/errorwithpos/index-no-arguments.g0000644000000000000000000000010515175510000017640 0ustar00#! @Chapter Parser #! @Section Broken #! @Description Text #! @Index AutoDoc-2026.05.03/tst/errorwithpos/index-no-item.g0000644000000000000000000000002015175510000016565 0ustar00#! @Index entry AutoDoc-2026.05.03/tst/errorwithpos/index-unterminated-quoted-key.g0000644000000000000000000000012315175510000022005 0ustar00#! @Chapter Parser #! @Section Broken #! @Description Text #! @Index "unterminated AutoDoc-2026.05.03/tst/errorwithpos/installmethod-unterminated-arguments.g0000644000000000000000000000013115175510000023462 0ustar00#! @Chapter Parser #! @Section Broken InstallMethod( "Broken", [ IsObject ], function( x AutoDoc-2026.05.03/tst/errorwithpos/installmethod-unterminated-declaration.g0000644000000000000000000000011415175510000023743 0ustar00#! @Chapter Parser #! @Section Broken InstallMethod( "Broken", [ IsObject ] AutoDoc-2026.05.03/tst/errorwithpos/installmethod-unterminated-filter-list.g0000644000000000000000000000013115175510000023713 0ustar00#! @Chapter Parser #! @Section Broken InstallMethod( "Broken", [ IsObject AutoDoc-2026.05.03/tst/errorwithpos/installmethod-unterminated-header.g0000644000000000000000000000007615175510000022715 0ustar00#! @Chapter Parser #! @Section Broken InstallMethod( "Broken" AutoDoc-2026.05.03/tst/errorwithpos/itemtype-unknown.g0000644000000000000000000000017015175510000017453 0ustar00#! @Chapter Parser #! @Section InvalidItemType #! @ItemType Method InstallMethod( "Broken", [ IsObject ], obj -> obj ); AutoDoc-2026.05.03/tst/errorwithpos/markdown-backtick-unbalanced.g0000644000000000000000000000021015175510000021576 0ustar00#! @Chapter Parser #! @Section Markdown errors #! @Description Text with `unterminated code span DeclareGlobalFunction( "BacktickOp" ); AutoDoc-2026.05.03/tst/errorwithpos/markdown-emph-unbalanced.g0000644000000000000000000000020415175510000020757 0ustar00#! @Chapter Parser #! @Section Markdown errors #! @Description Text with **unterminated emphasis DeclareGlobalFunction( "EmphOp" ); AutoDoc-2026.05.03/tst/errorwithpos/section-without-chapter.g0000644000000000000000000000002415175510000020705 0ustar00#! @Section Missing AutoDoc-2026.05.03/tst/errorwithpos/sectionlabel-no-section.g0000644000000000000000000000005415175510000020637 0ustar00#! @Chapter Parser #! @SectionLabel Missing AutoDoc-2026.05.03/tst/errorwithpos/sectiontitle-no-section.g0000644000000000000000000000005415175510000020701 0ustar00#! @Chapter Parser #! @SectionTitle Missing AutoDoc-2026.05.03/tst/errorwithpos/subsection-no-section.g0000644000000000000000000000005215175510000020347 0ustar00#! @Chapter Parser #! @Subsection Missing AutoDoc-2026.05.03/tst/errorwithpos/subsectionlabel-no-subsection.g0000644000000000000000000000010315175510000022056 0ustar00#! @Chapter Parser #! @Section Present #! @SubsectionLabel Missing AutoDoc-2026.05.03/tst/errorwithpos/subsectiontitle-no-subsection.g0000644000000000000000000000010315175510000022120 0ustar00#! @Chapter Parser #! @Section Present #! @SubsectionTitle Missing AutoDoc-2026.05.03/tst/errorwithpos/unknown-command.g0000644000000000000000000000003015175510000017224 0ustar00#! @NotACommand mystery AutoDoc-2026.05.03/tst/errorwithpos/valid.g0000644000000000000000000000011715175510000015216 0ustar00#! @Chapter Parser #! @Section Valid DeclareOperation( "MyOp", [ IsObject ] ); AutoDoc-2026.05.03/tst/errorwithpos.tst0000644000000000000000000001477315175510000014520 0ustar00# # test parser error reporting with ErrorWithPos gap> autodoc_pkgroot := Filename( DirectoriesPackageLibrary( "AutoDoc", "" ), "" );; gap> if not StartsWith( autodoc_pkgroot, "/" ) then > autodoc_pkgroot := Filename( > Directory( AUTODOC_CurrentDirectory() ), > autodoc_pkgroot > ); > fi; gap> ParseFixture := function( arg ) > local tree, default_chapter_data, file; > tree := DocumentationTree(); > if Length( arg ) > 1 then > default_chapter_data := arg[ 2 ]; > else > default_chapter_data := CreateDefaultChapterData( "Pkg" ); > fi; > file := rec( > path := Filename( Directory( autodoc_pkgroot ), arg[ 1 ] ), > display := arg[ 1 ] > ); > AutoDoc_Parser_ReadFiles( [ file ], tree, default_chapter_data ); > return tree; > end;; gap> RenderFixtureDescription := function( file, item_name ) > local tree, section, item, rendered, stream; > tree := ParseFixture( file ); > section := SectionInTree( tree, "Parser", "Markdown_errors" ); > item := First( section!.content, > x -> IsBound( x!.name ) and x!.name = item_name ); > rendered := ""; > stream := OutputTextString( rendered, true ); > SetPrintFormattingStatus( stream, false ); > AUTODOC_WriteStringListWithSource( > item!.description, > item!.description_source_positions, > stream ); > CloseStream( stream ); > return rendered; > end;; # # control: valid parser input still works # gap> tree := ParseFixture( "tst/errorwithpos/valid.g" );; gap> section := SectionInTree( tree, "Parser", "Valid" );; gap> item := section!.content[ 1 ];; gap> item!.name; "MyOp" # # structural command/context errors # gap> ParseFixture( "tst/errorwithpos/chapterlabel-no-chapter.g" ); Error, found @ChapterLabel with no active chapter, at tst/errorwithpos/chapterlabel-no-chapter.g:1 gap> ParseFixture( "tst/errorwithpos/chaptertitle-no-chapter.g" ); Error, found @ChapterTitle with no active chapter, at tst/errorwithpos/chaptertitle-no-chapter.g:1 gap> ParseFixture( "tst/errorwithpos/section-without-chapter.g" ); Error, found @Section with no active chapter, at tst/errorwithpos/section-without-chapter.g:1 gap> ParseFixture( "tst/errorwithpos/sectionlabel-no-section.g" ); Error, found @SectionLabel with no active section, at tst/errorwithpos/sectionlabel-no-section.g:2 gap> ParseFixture( "tst/errorwithpos/sectiontitle-no-section.g" ); Error, found @SectionTitle with no active section, at tst/errorwithpos/sectiontitle-no-section.g:2 gap> ParseFixture( "tst/errorwithpos/subsection-no-section.g" ); Error, found @Subsection with no active section, at tst/errorwithpos/subsection-no-section.g:2 gap> ParseFixture( "tst/errorwithpos/subsectionlabel-no-subsection.g" ); Error, found @SubsectionLabel with no active subsection, at tst/errorwithpos/subsectionlabel-no-subsection.g:3 gap> ParseFixture( "tst/errorwithpos/subsectiontitle-no-subsection.g" ); Error, found @SubsectionTitle with no active subsection, at tst/errorwithpos/subsectiontitle-no-subsection.g:3 # # declaration parsing errors # gap> ParseFixture( "tst/errorwithpos/declaration-outside-section.g", > rec( > categories := [ ], > methods := [ ], > attributes := [ ], > properties := [ ], > global_functions := [ ], > global_variables := [ ], > info_classes := [ ] ) ); Error, declarations must be documented within a section, at tst/errorwithpos/declaration-outside-section.g:2 gap> ParseFixture( "tst/errorwithpos/declaration-unterminated-header.g" ); Error, unterminated declaration header, at tst/errorwithpos/declaration-unterminated-header.g:4 gap> ParseFixture( "tst/errorwithpos/declaration-unterminated-filter-list.g" ); Error, unterminated declaration filter list, at tst/errorwithpos/declaration-unterminated-filter-list.g:5 gap> ParseFixture( "tst/errorwithpos/declaration-unrecognized-type.g" ); Error, Unrecognized scan type, at tst/errorwithpos/declaration-unrecognized-type.g:3 # # InstallMethod parsing errors # gap> ParseFixture( "tst/errorwithpos/installmethod-unterminated-header.g" ); Error, unterminated InstallMethod declaration header, at tst/errorwithpos/installmethod-unterminated-header.g:4 gap> ParseFixture( "tst/errorwithpos/installmethod-unterminated-filter-list.g" ); Error, unterminated InstallMethod filter list, at tst/errorwithpos/installmethod-unterminated-filter-list.g:5 gap> ParseFixture( "tst/errorwithpos/installmethod-unterminated-declaration.g" ); Error, unterminated InstallMethod declaration, at tst/errorwithpos/installmethod-unterminated-declaration.g:4 gap> ParseFixture( "tst/errorwithpos/installmethod-unterminated-arguments.g" ); Error, unterminated argument list in InstallMethod declaration, at tst/errorwithpos/installmethod-unterminated-arguments.g:4 gap> ParseFixture( "tst/errorwithpos/itemtype-unknown.g" ); Error, unknown @ItemType Method; expected one of Attr, Cat, Coll, Constr, Fam,\ Filt, Func, InfoClass, Meth, Oper, Prop, Repr, Var, at tst/errorwithpos/itemtype-unknown.g:3 # # GroupTitle, Index, BREAK, and unknown command errors # gap> ParseFixture( "tst/errorwithpos/grouptitle-no-group.g" ); Error, found @GroupTitle with no Group set, at tst/errorwithpos/grouptitle-no-group.g:3 gap> ParseFixture( "tst/errorwithpos/grouptitle-outside-section.g" ); Error, can only set @GroupTitle within a Chapter and Section., at tst/errorwithpos/grouptitle-outside-section.g:2 gap> ParseFixture( "tst/errorwithpos/index-no-item.g" ); Error, found @Index with no active documentation item, at tst/errorwithpos/index-no-item.g:1 gap> ParseFixture( "tst/errorwithpos/index-no-arguments.g" ); Error, found @Index without arguments, at tst/errorwithpos/index-no-arguments.g:4 gap> ParseFixture( "tst/errorwithpos/index-unterminated-quoted-key.g" ); Error, found @Index with unterminated quoted key, at tst/errorwithpos/index-unterminated-quoted-key.g:4 gap> ParseFixture( "tst/errorwithpos/index-empty-key.g" ); Error, found @Index with empty key, at tst/errorwithpos/index-empty-key.g:4 gap> ParseFixture( "tst/errorwithpos/break.g" ); Error, parser requested failure, at tst/errorwithpos/break.g:1 gap> ParseFixture( "tst/errorwithpos/unknown-command.g" ); Error, unknown AutoDoc command @NotACommand, at tst/errorwithpos/unknown-command.g:1 # # markdown syntax errors should also report file and line # gap> RenderFixtureDescription( > "tst/errorwithpos/markdown-backtick-unbalanced.g", > "BacktickOp" ); Error, did you forget some `, at tst/errorwithpos/markdown-backtick-unbalanced.g:3 gap> RenderFixtureDescription( > "tst/errorwithpos/markdown-emph-unbalanced.g", > "EmphOp" ); Error, did you forget some **, at tst/errorwithpos/markdown-emph-unbalanced.g:3 AutoDoc-2026.05.03/tst/manual.expected/0000755000000000000000000000000015175510000014256 5ustar00AutoDoc-2026.05.03/tst/manual.expected/_AutoDocMainFile.xml0000644000000000000000000000040415175510000020100 0ustar00 <#Include SYSTEM "_Chapter_Overview.xml"> <#Include SYSTEM "_Chapter_Tutorials.xml"> <#Include SYSTEM "_Chapter_Comments.xml"> <#Include SYSTEM "_Chapter_Reference.xml"> AutoDoc-2026.05.03/tst/manual.expected/_Chapter_Comments.xml0000644000000000000000000010567215175510000020405 0ustar00 &AutoDoc; documentation comments

You can document declarations of global functions and variables, operations, attributes etc. by inserting &AutoDoc; comments into your sources before these declarations. 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.

For declaration documentation, the associated declaration must appear immediately after the &AutoDoc; comment block. In particular, do not insert other code (such as if false then or assignments) between the comment block and the Declare... statement.

This also works for InstallMethod and InstallOtherMethod. In that case, &AutoDoc; uses the installed method's name and filter list to create a manual entry for the implemented item.

Inside of &AutoDoc; comments, &AutoDoc; commands starting with @ can be used to control the output &AutoDoc; produces. Any comment line that does not start with an &AutoDoc; command is treated as regular documentation text and may contain (almost) arbitrary &GAPDoc; XML markup, such as <Ref>, <A>, <List>, and similar tags. This lets you use the normal &GAPDoc; formatting toolbox directly inside &AutoDoc; comments.

For example:

for setup details. #! The argument obj must satisfy IsObject. ]]>

As explained in chapter , you can combine &AutoDoc; comments with hand-written XML and classic &GAPDoc; comments. For practical setup and migration workflows, see chapter .

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.

For DeclareGlobalName, using @Arguments or @Returns also makes &AutoDoc; document the item as a function. This is useful because DeclareGlobalName itself does not reveal whether the name denotes a function or a variable.

@ItemType kind

@ItemType kind Overrides the kind of manual item created for the following declaration or installed method. The supported values are Attr, Cat, Coll, Constr, Fam, Filt, Func, InfoClass, Meth, Oper, Prop, Repr, and Var.

The values Cat, Coll, and Repr are &AutoDoc;-specific aliases. They emit Filt entries with the corresponding &GAPDoc; filter type.

This is useful when the source code alone does not determine which manual item kind should be emitted. For many declarations such as DeclareAttribute or DeclareProperty, &AutoDoc; already knows the intended type from the declaration itself.

It is useful for DeclareGlobalName, because that declaration can refer to either a function or a variable. &AutoDoc; defaults such entries to Var, but switches to Func as soon as @Arguments or @Returns indicates function-style documentation. You can still use @ItemType to override this explicitly.

It is useful for DeclareSynonym, because that declaration can document a function synonym or one of several filter-like synonyms. Use @ItemType Filt, Cat, Coll, or Repr to control which kind of filter entry should be emitted.

For example:

This makes &AutoDoc; emit a <Filt Type="Representation" .../> manual entry.

@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 chapter, section

@ChapterInfo 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 name

@Chapter @ChapterLabel @ChapterTitle 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.

@Appendix name

@Appendix This is analogous to @Chapter, but generates Appendix elements instead of Chapter elements. When scaffolding generates the main XML file, appendices created this way are included automatically after any files listed in scaffold.appendix.

Example:

@Section name

@Section @SectionLabel @SectionTitle 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 name

@Subsection @SubsectionLabel @SubsectionTitle 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 [grpname]

@BeginGroup 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 title

@GroupTitle 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.

@BeginExample and @EndExample

@BeginExample @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. If you enable extract_examples := true when calling , these examples can also be turned into .tst files (see Section ).

@BeginExampleSession and @EndExampleSession

@BeginExampleSession @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 and @EndLog

@BeginLog @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 and @EndLogSession

@BeginLogSession @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, and @InsertChunk name

@BeginChunk name @EndChunk @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, and @InsertCode name

@BeginCode name @EndCode @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, and @EndLatexOnly

@LatexOnly text @BeginLatexOnly @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, and @EndNotLatex

@NotLatex text @BeginNotLatex @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.

@Index key [entry text]

@Index key [entry text] Adds an index entry to the current documentation text. The command @Index key entry text generates <Index Key="key">entry text</Index>. If no entry text is provided, then the entry text is empty. To use keys containing spaces, wrap the key in double quotes, e.g. @Index "my key" entry text. The entry text is processed like normal documentation text, so markdown-like inline code such as true is supported.

Title page commands

The following commands can be used to add corresponding parts to the title page of a document generated by &AutoDoc;. @Title @Subtitle @Version @TitleComment @Author @Date @Address @Abstract @Copyright @Acknowledgements @Colophon Many of these values can (and for package manuals typically should) be extracted from PackageInfo.g. If you set them explicitly in comments, they override extracted or scaffold-defined values. This is usually most useful 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 or one of their subdirectories, are treated as standalone &AutoDoc; input files. They are meant for manual text that does not belong next to a single declaration: chapters, sections, tutorials, worked examples, index entries, chunks, title-page metadata, and similar prose-heavy material.

Conceptually, a .autodoc file uses the same parser as &AutoDoc; comments, but without the comment marker. In a .autodoc file, lines do not need to start with #! and in fact usually should not. This makes .autodoc files one convenient way to replace hand-written XML chapters when you prefer &AutoDoc;'s command syntax and Markdown-like text features. However, it is not the only supported style: chapter and section commands inside source comments remain fully supported, and &AutoDoc; itself still uses that style in files such as gap/Magic.gd. For the surrounding workflow, see Chapter .

The most important difference from declaration comments is that a plain text file does not document a declaration by adjacency. There is no following Declare... or InstallMethod statement for &AutoDoc; to inspect. So commands whose meaning depends on such a declaration only make sense in source comments immediately before that declaration.

In practice, this gives the following rule of thumb.

Use source comments beginning with #! to document declarations. This is the mode for @Description, @Returns, @Arguments, @Label, @Group, and @ChapterInfo. Use either .autodoc files or source comments for standalone manual structure and prose. Commands such as @Chapter, @Section, @Subsection, grouping commands, examples and logs, chunks and code insertion, @Index, title-page commands, Markdown-style headings, fenced code blocks, and ordinary &GAPDoc; XML markup work in both styles.

As a concrete example, the following file can serve as a complete chapter written in .autodoc format.

arg or . @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession @Index "Worksheet Autoplain" Plain worksheet index entry with `true` ]]>

This is essentially the style used in the worksheet fixture tst/worksheets/autoplain.sheet/plain.autodoc.

The same structural commands can also be used inside source comments, for example:

This source-comment style is still fully supported and is used in gap/Magic.gd.

The mixed-workflow case is equally common. Suppose an existing manual still has a hand-written main XML file and perhaps some hand-written XML chapters. Then you can keep those files, include _AutoDocMainFile.xml from the main XML file as described in Chapter , and add one or more .autodoc files via autodoc.files or autodoc.scan_dirs. Those files can provide tutorial chapters or appendices, while declaration documentation continues to live in source comments and older XML chapters remain unchanged.

One caveat is worth keeping in mind. If you want a standalone .autodoc file to pause and resume around declaration documentation that is written in source comments, the current workaround is to use chunks. That interleaving workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

So, while .autodoc files and source comments share most of the same text syntax, they can be combined freely. The main distinction is simply that declaration-bound commands attach metadata to a following declaration, while standalone manual text can live wherever you find it most convenient.

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. ]]>

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.

Fenced code blocks

One can insert verbatim code blocks by placing the code between lines containing at least three backticks or at least three tildes. The opening fence may optionally be followed by an info string. The values @listing, @example, and @log select the corresponding GAPDoc element; any other value is currently ignored. If nothing is specified the default is to generate <Listing>. Example:

[ 1 .. 3 ] ^ 2; #! [ 1, 4, 9 ] #! ~~~ #! ```@log #! #I some log message #! ``` ]]>

This produces the following output:

[ 1 .. 3 ] ^ 2; [ 1, 4, 9 ] ]]>

Deprecated commands

The following commands used to be supported, but are not supported anymore.

@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 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-2026.05.03/tst/manual.expected/_Chapter_Overview.xml0000644000000000000000000000524015175510000020414 0ustar00 What &AutoDoc; offers

&AutoDoc; helps you create and maintain package manuals for &GAP;. It is built on top of &GAPDoc; and generates the XML input that &GAPDoc; consumes. So &AutoDoc; complements &GAPDoc; instead of replacing it.

The package is designed for a mix and match workflow: you can adopt only the parts that help you today, and add more over time.

Core features

Build package manuals via one reproducible command, usually gap makedoc.g. Generate and maintain a title page from metadata in PackageInfo.g. Generate and maintain a main XML file that includes your chapters. Extract manual examples into .tst files via extract_examples := true. Document declarations directly in source files via &AutoDoc; comments beginning with #!. Organize chapter and section text either in source comments or in standalone .autodoc files. Combine &AutoDoc; comments, classic &GAPDoc; source comments, and hand-written XML chapters in one manual.

Adopting &AutoDoc; incrementally

You do not have to switch everything at once. Typical adoption paths include: Use only to rebuild an existing &GAPDoc; manual. Enable only title-page generation, while keeping your custom main XML. Keep your existing title page but use generated entities such as &VERSION;, &RELEASEYEAR;, and &RELEASEDATE;. Add &AutoDoc; comments only for new code, and leave old documentation as-is. Keep existing XML chapters, or gradually add source comments and .autodoc files where they fit your preferred workflow. Later, gradually move chapters or source documentation to your preferred style.

This flexibility is central: &AutoDoc; should make your current setup better, without forcing a full rewrite first.

Where to continue

For practical setup and migration workflows, continue with chapter . For the command reference of documentation comments, including standalone .autodoc files, see chapter .

AutoDoc-2026.05.03/tst/manual.expected/_Chapter_Reference.xml0000644000000000000000000005604715175510000020517 0ustar00 Reference
AutoDoc worksheets The purpose of this function is to create stand-alone PDF and HTML files using &AutoDoc; without associating them with a package.

Instead of a package directory, you pass one filename or a list of filenames containing &AutoDoc; text from which the document is created. Settings are supplied via an optional record using the same entries as the optrec argument of . Alternatively, you may omit filenames and specify the files via optrec.autodoc.files.

A simple worksheet file can define title-page information and chapter content directly in the source file, including example blocks. If this is stored in worksheet.g, you can generate documentation via This creates documentation in a doc subdirectory of the current directory.

Since worksheets do not have a PackageInfo.g, title-page fields are specified directly in the worksheet file.

For backwards compatibility, worksheet calls still accept GAP global options for specifying the option-record entries such as dir, scaffold, autodoc, gapdoc, and extract_examples. However, this feature is deprecated.

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/_main.xml 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, using documentation comments and commands. This produces additional 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 ). These tasks can be enabled independently, so you can use as much or as little of &AutoDoc; as your package currently needs. For more information and some examples, please refer to Chapter .

The parameters have the following meanings: pkgdir This optional parameter is used to determine the package directory in which &AutoDoc; will operate, and to find the metadata concerning the package being documented. If given, it should be an IsDirectory object. If the argument is omitted, then &AutoDoc; checks if it was called from a makedoc.g file or similar, and if so, uses the directory this is contained in. Otherwise the current directory is used. In both 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.

For backwards compatibility, it is also possible to pass a package name as this argument, which then is resolved to the package directory of the first instance of this package &GAP; knows about. However, this is deprecated, as it is unreliable in the presence of multiple copies of a package.

Note that when using AutoDocWorksheet (see ), there is no parameter corresponding to pkgdir 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 written directly in &GAPDoc; XML. Appendices created with @Appendix are included automatically after these files when scaffolding generates the main XML file. 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. bibstyle Overrides the bibliography style used for LaTeX output. This is written as the Style attribute of the generated <Bibliography .../> element, so valid values are the bibliography style names understood by &GAPDoc; and BibTeX, such as alpha, alphaurl, or plain. 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.

Note that &AutoDoc; predefines several entities: VERSION Set to the Version field of your package info record. RELEASEYEAR Set to a string containing the release year, as derived from the Date field of your package info record. RELEASEDATE Derived from the Date field of your package info record. SomePackage The precise name of this entity is derived from the PackageName field of your package info record. Note that it is case sensitive. The content is defined as suggested by the example above. TitlePage A record with extra title-page fields for the generated manual. Field names are interpreted as title-page XML element names, and their values are written as element content. For example, you can set a custom acknowledgements block with

If this is set in PackageInfo.g as PkgInfo.AutoDoc.TitlePage, it has the same meaning as this option; see subsection in chapter for details and an example.

For the list of valid title-page elements, see 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 recursively for .gi, .gd, .g, and .autodoc files; all of these files are then scanned for &AutoDoc; documentation comments. The special entries "." and "" still only scan the package root itself. This controls where &AutoDoc; looks for source comments beginning with #! and for standalone .autodoc files. It does not affect where &GAPDoc; looks for GAPDoc comments; that is controlled separately by gapdoc.scan_dirs.
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: _main.xml when scaffolding is enabled for package manuals, otherwise 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 recursively for .gi, .gd and .g files; all of these files are then scanned for &GAPDoc; documentation comments. The special entries "." and "" still only scan the package root itself. This controls only where &GAPDoc; comments are searched for. It does not affect where &AutoDoc; looks for source comments beginning with #! or for .autodoc files; use autodoc.scan_dirs for that.
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.

If set to a record, it may contain the following entries: subdir A string or Directory() object selecting where the generated .tst files are written. The default is tst. If a string is given, it is interpreted relative to the package directory, so values such as tst/generated are supported. 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.

The function also checks the following GAP global options, i.e. options supplied via GAP's value-option syntax and visible through nested calls. These are not entries of optrec. See for more information about GAP's global options system. nopdf If this global option is set to true, then &AutoDoc; tells &GAPDoc; not to build the PDF version of the manual. HTML and text output are still generated.

This is useful on systems without a working pdflatex installation, or when you only need the non-PDF outputs while iterating on the manual.

For example:

Also, if the environment variable NOPDF is set, then &AutoDoc; behaves as if the global option nopdf had been enabled. relativePath This has the same effect as gapdoc.gap_root_relative_path, but as a GAP global option. It takes precedence over that record entry if both are specified.

If relativePath is true, then the default relative path ../../.. is used. If it is a string, then that string is used as the relative path from the documentation directory to the GAP root.

For example:

In particular, a call such as sets both global options to true, and they remain visible to the call inside makedoc.g.

Info class for the AutoDoc package. Set this to 0 to suppress info messages, 1 to allow most messages, and 2 to allow all messages including those that contain file paths.

This can be set by calling, for example, SetInfoLevel(InfoAutoDoc, 0). Default value is 1.

AutoDoc-2026.05.03/tst/manual.expected/_Chapter_Tutorials.xml0000644000000000000000000006723415175510000020607 0ustar00 Getting started using &AutoDoc;

This chapter gives practical workflows for adding &AutoDoc; to a package. For a high-level feature overview and adoption strategy, see chapter .

Choose your workflow

You can use &AutoDoc; in several ways, and it is fine to combine them: Start a new package manual from scratch (Section ). Integrate &AutoDoc; into an existing &GAPDoc; manual (Section ). Use only selected features, such as title-page generation or example extraction, while keeping everything else unchanged.

This incremental approach is encouraged: start with the smallest helpful step, then adopt additional features when useful.

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:

When called from a file such as makedoc.g, &AutoDoc; uses the directory containing that file as the package directory. Otherwise, it falls back to the current directory. In either case it then reads the PackageInfo.g file from that package directory. It extracts information about the package from it (such as its name and version, see Section ). It then creates two XML files doc/_main.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:

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:

Then you can regenerate the package manual from the command line with the following command:

If you also want regression tests from your manual examples, enable extract_examples := true; this is explained in Section .

Documenting code with &AutoDoc;

&AutoDoc; supports several equally supported ways to organize your manual text. You can put chapter and section material directly into #! comments inside .g, .gd, or .gi files, you can put it into standalone .autodoc files, and you can mix either style with existing &GAPDoc; XML. Which arrangement is best is mostly a matter of taste and convenience. The detailed command reference for these styles is in chapter , especially Section .

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:

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:

Important: the comment block must be immediately followed by the declaration it documents. Do not place other code between the comment block and the Declare... statement.

conv. DeclareOperation( "ToricVariety", [ IsConvexObject ] ); ]]>

In these comment lines, you can freely use normal &GAPDoc; XML markup (with the usual exceptions for lines starting with @, which are interpreted as &AutoDoc; commands). So, for instance, tags like <Ref>, <A>, <K>, <List>, etc. can be written directly in #! comment text.

For chapter text, tutorial material, worked examples, and similar prose, some authors prefer to keep the material next to their code using #! @Chapter, #! @Section, and related commands, while others prefer standalone .autodoc files. In an .autodoc file you write the same commands without the #! prefix, and you list the file in autodoc.files or place it in a directory scanned via autodoc.scan_dirs. AutoDoc itself still uses the source-comment style in places, for example in gap/Magic.gd.

One caveat applies if you decide to keep prose in a standalone .autodoc file but want to interrupt it with the documentation of a declaration that is written in source comments. Today that requires the chunk mechanism, and that workflow is currently limited; see issue #60 in the AutoDoc issue tracker.

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.:

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 and standalone .autodoc files. Just make sure to first edit the main XML file of your documentation, and insert the line

]]> in a suitable place. This means that you can mix &AutoDoc; documentation comments and .autodoc files 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 then runs &GAPDoc; to produce HTML and PDF output, but does not touch your documentation XML files otherwise.

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, with &AutoDoc; it 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 this purpose only, e.g. &io; and orb.

In particular, this setup works well if you want to keep your existing manual structure and only adopt selected &AutoDoc; features first; for example automatic title-page data and predefined entities such as &VERSION;, &RELEASEYEAR; and &RELEASEDATE; (see Section ).

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; session started in the root directory of your package:

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

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

If you prefer to keep generated tests in a separate location, set extract_examples.subdir to a path relative to the package root:

This writes the extracted examples into tst/generated/ instead.

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

&AutoDoc; can scan directories for documentation input automatically. In fact there are two separate scanning steps. The option autodoc.scan_dirs controls where it looks for source comments beginning with #! and for standalone .autodoc files. By default, it scans the package root directory and the subdirectories gap, lib, examples and examples/doc; the listed subdirectories are scanned recursively, while the package root itself is only scanned at top level. If you keep that kind of input in other directories, adjust autodoc.scan_dirs. The following example instructs &AutoDoc; to only search in the subdirectory package_sources of the package's root directory for those files.

The separate option gapdoc.scan_dirs serves a different purpose: it controls where &GAPDoc; comments are searched for.

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:

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

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

The same behavior is also available via the global option relativePath. This is particularly convenient in a short makedoc.g script, and it overrides gapdoc.gap_root_relative_path if both are given. Since this is a GAP global option, you can also set it outside the eventual call and let it propagate through nested calls; see for more information about GAP's global options system:

If you pass relativePath := true, then &AutoDoc; uses the default relative path ../../...

For example, if your makedoc.g reads the manual via , then the following command sets both relativePath and nopdf to true for that nested call:

Finally, if you only want HTML and text output, you can suppress PDF generation with the global option nopdf:

This is useful if pdflatex is unavailable, or when you want a faster documentation rebuild while editing.

You can also request the same behavior from the shell by setting the environment variable NOPDF before invoking makedoc.g. For example:

If NOPDF is set, &AutoDoc; skips PDF generation even if no nopdf option is given in the GAP code.

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/_main.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. However, note that this only works in the PDF version of the file. 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.) In the entities record enter any entities previously stored in your manual.xml. (Again, if you have none, you may safely delete this record.) To illustrate this option the &AutoDoc; file PackageInfo.g defines entities for the names of packages &io; and &PackageName;. 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.

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.

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

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 record controls extra settings used by &AutoDoc; while generating the manual. In particular, PkgInfo.AutoDoc.TitlePage lets you add or override title-page elements coming from package metadata.

Typical fields you may set there include TitleComment, Abstract, Copyright, Acknowledgements and Colophon. For example, in PackageInfo.g:

This inserts <Copyright> and <Acknowledgements> blocks into the generated title.xml.

PkgInfo.AutoDoc.TitlePage has exactly the same meaning as scaffold.TitlePage in . The function documentation for scaffold.TitlePage points back to this subsection.

Entities from PackageInfo.g and scaffold options

Besides title-page fields, you can define custom entities in AutoDoc.entities inside PackageInfo.g. They are written to doc/_entities.xml, so they can be used both by generated main files and by hand-written main XML files.

In addition, &AutoDoc; predefines the entities VERSION, RELEASEYEAR and RELEASEDATE, derived from package metadata. This is useful if you keep a custom title page or custom chapters and still want release information to stay synchronized with PackageInfo.g.

You can specify scaffold-related settings in PackageInfo.g and in your makedoc.g call at the same time; both records are merged, and values from makedoc.g take precedence when both define the same key.

Worksheets

For stand-alone documents that are not tied to a package, use . Its documentation and examples are in Section of chapter .

AutoDoc-2026.05.03/tst/manual.expected/_Chunks.xml0000644000000000000000000000000015175510000016360 0ustar00AutoDoc-2026.05.03/tst/manual.expected/_entities.xml0000644000000000000000000000035215175510000016763 0ustar00AutoDoc'> PackageName'> io'> AutoDoc-2026.05.03/tst/manual.expected/_main.xml0000644000000000000000000000054015175510000016062 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/manual.expected/title.xml0000644000000000000000000000256515175510000016131 0ustar00 AutoDoc Generate documentation from &GAP; source code 2026.05.03 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
3 May 2026 &AutoDoc; is a &GAP; package whose purpose is to aid &GAP; package authors in creating and maintaining the documentation of their packages. ©right; 2012-2026 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-2026.05.03/tst/markdown.tst0000644000000000000000000000772315175510000013570 0ustar00# # test markdown-related functionality # gap> START_TEST( "markdown.tst" ); # fenced code blocks and inline code in Markdown-like text # gap> AUTODOC_FencedMarkdownElement("@example"); "Example" gap> AUTODOC_FencedMarkdownElement("@log"); "Log" gap> AUTODOC_FencedMarkdownElement("gap"); "Listing" gap> AUTODOC_LineStartsCDATA(" AUTODOC_LineStartsCDATA("plain text"); false gap> AUTODOC_LineEndsCDATA("]]>"); true gap> AUTODOC_LineEndsCDATA("plain text"); false gap> AUTODOC_EscapeCDATAContent("a]]>b"); "a]]]]>b" gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "```@example", > "gap> 1 + 1;", > "2", > "```" > ], fail);; gap> Length(markdown_verbatim); 1 gap> IsTreeForDocumentationNode(markdown_verbatim[1]); true gap> markdown_verbatim[1]!.element_name; "Example" gap> markdown_verbatim[1]!.content; [ "gap> 1 + 1;", "2" ] gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "Before", > "```gap", > "if x = 2 then", > " Print(\"ok\\n\");", > "fi;", > "```", > "After" > ], fail);; gap> markdown_verbatim[1]; "Before" gap> IsTreeForDocumentationNode(markdown_verbatim[2]); true gap> markdown_verbatim[2]!.element_name; "Listing" gap> markdown_verbatim[2]!.content; [ "if x = 2 then", " Print(\"ok\\n\");", "fi;" ] gap> markdown_verbatim[3]; "After" gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "~~~", > "gap> [[2]]>[[1]];", > "~~~" > ], fail);; gap> markdown_verbatim[1]!.content; [ "gap> [[2]]>[[1]];" ] gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "```@example", > "gap> 1 + 1;", > "2", > "```" > ], fail);; gap> markdown_verbatim[1]!.element_name; "Example" gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "```@log", > "#I some log message", > "```" > ], fail);; gap> markdown_verbatim[1]!.element_name; "Log" gap> markdown_verbatim := AUTODOC_ConvertMarkdownToGAPDocXML([ > "```@listing", > "#! @BeginCode Increment", > "i := i + 1;", > "#! @EndCode", > "", > "#! @InsertCode Increment", > "## Code is inserted here.", > "```" > ], fail);; gap> markdown_verbatim[1]!.content; [ "#! @BeginCode Increment", "i := i + 1;", "#! @EndCode", "", "#! @InsertCode Increment", "## Code is inserted here." ] gap> AUTODOC_ConvertMarkdownToGAPDocXML([ > "` & more`" > ], fail) = [ > "<Log attr="x"> & more" > ]; true gap> tree_cdata := DocumentationTree();; gap> verbatim_node := DocumentationVerbatim( > "Listing", > rec( Type := "Code" ), > [ "gap> Print(\"]]>\");" ] > );; gap> rendered := "";; gap> stream := OutputTextString(rendered, true);; gap> SetPrintFormattingStatus(stream, false); gap> WriteDocumentation(verbatim_node, stream); gap> CloseStream(stream); gap> rendered = Concatenation( > "

"gap> Print(\"]]]]>\");\n", > "]]>\n" > ); true gap> example_node := DocumentationExample( "Example" );; gap> Add( example_node!.content, "gap> Print(\"]]>\");" );; gap> rendered := "";; gap> stream := OutputTextString(rendered, true);; gap> SetPrintFormattingStatus(stream, false); gap> WriteDocumentation(example_node, stream); gap> CloseStream(stream); gap> rendered = Concatenation( > " "gap> Print(\"]]]]>\");\n", > "]]>\n\n" > ); true gap> rendered := "";; gap> stream := OutputTextString(rendered, true);; gap> SetPrintFormattingStatus(stream, false); gap> WriteDocumentation([ > "```@listing", > "#! @BeginCode Increment", > "i := i + 1;", > "#! @EndCode", > "", > "#! @InsertCode Increment", > "## Code is inserted here.", > "```" > ], stream); gap> CloseStream(stream); gap> rendered = Concatenation( > " "#! @BeginCode Increment\n", > "i := i + 1;\n", > "#! @EndCode\n", > "\n", > "#! @InsertCode Increment\n", > "## Code is inserted here.\n", > "]]>\n" > ); true # gap> STOP_TEST( "markdown.tst" ); AutoDoc-2026.05.03/tst/misc.tst0000644000000000000000000003755515175510000012707 0ustar00# # 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_ParseDate # gap> AUTODOC_ParseDate("2019-03-01"); rec( day := 1, month := 3, year := 2019 ) gap> AUTODOC_ParseDate("01/03/2019"); rec( day := 1, month := 3, year := 2019 ) gap> AUTODOC_ParseDate("01.03.2019"); fail # # 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("2019-03-01"); "1 March 2019" gap> AUTODOC_FormatDate("01/03/2019"); "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 # # AUTODOC_PositionPrefixShebang # gap> AUTODOC_PositionPrefixShebang( "#! @Chapter Intro" ); 1 gap> AUTODOC_PositionPrefixShebang( " #! @Section One" ); 4 gap> AUTODOC_PositionPrefixShebang( "\t#! @Subsection Two" ); 2 gap> AUTODOC_PositionPrefixShebang( "" ); fail gap> AUTODOC_PositionPrefixShebang( "#" ); fail gap> AUTODOC_PositionPrefixShebang( " " ); fail gap> AUTODOC_PositionPrefixShebang( "x #! @Chapter NotPrefix" ); fail gap> AUTODOC_PositionPrefixShebang( " x#! @Chapter NotPrefix" ); fail gap> AUTODOC_PositionPrefixShebang( " # ! not-a-shebang" ); fail # # Scan_for_AutoDoc_Part: robust command splitting # gap> Scan_for_AutoDoc_Part( "plain text @Section Intro" ); [ "STRING", "plain text @Section Intro" ] gap> Scan_for_AutoDoc_Part( " @Chapter My Chapter" ); [ "@Chapter", "My Chapter" ] gap> Scan_for_AutoDoc_Part( " @Section My Section" ); [ "@Section", "My Section" ] gap> Scan_for_AutoDoc_Part( " @Subsection My Subsection" ); [ "@Subsection", "My Subsection" ] gap> Scan_for_AutoDoc_Part( " @NoArg" ); [ "@NoArg", "" ] gap> Scan_for_AutoDoc_Part( "no command here" ); [ "STRING", "no command here" ] gap> Scan_for_AutoDoc_Part( "# Heading chapter" ); [ "@Chapter", "Heading chapter" ] gap> Scan_for_AutoDoc_Part( "## Heading section" ); [ "@Section", "Heading section" ] gap> Scan_for_AutoDoc_Part( "### Heading subsection" ); [ "@Subsection", "Heading subsection" ] # # AUTODOC_CreateDirIfMissing: nested paths and `..` normalization # gap> LoadPackage("io", false); true gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-createdir-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "alpha/beta/gamma")); true gap> IsDirectoryPath(Filename(tmpdir_obj, "alpha")); true gap> IsDirectoryPath(Filename(tmpdir_obj, "alpha/beta")); true gap> IsDirectoryPath(Filename(tmpdir_obj, "alpha/beta/gamma")); true gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "one/two/../three")); true gap> IsDirectoryPath(Filename(tmpdir_obj, "one/three")); true gap> IsDirectoryPath(Filename(tmpdir_obj, "one/two")); false gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "work/current")); true gap> olddir := AUTODOC_CurrentDirectory();; gap> ChangeDirectoryCurrent(Filename(tmpdir_obj, "work/current")); true gap> AUTODOC_CreateDirIfMissing("../sibling/nested"); true gap> ChangeDirectoryCurrent(olddir); true gap> IsDirectoryPath(Filename(tmpdir_obj, "work/sibling/nested")); true gap> RemoveDirectoryRecursively(tmpdir); true # # AUTODOC_FindMatchingFiles: recursive scan_dirs traversal # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-findmatchingfiles-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "gap")); true gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "gap/sub")); true gap> AUTODOC_CreateDirIfMissing(Filename(tmpdir_obj, "lib")); true gap> stream := OutputTextFile(Filename(tmpdir_obj, "gap/top.gd"), false);; gap> CloseStream(stream); gap> stream := OutputTextFile(Filename(tmpdir_obj, "gap/sub/nested.gi"), false);; gap> CloseStream(stream); gap> stream := OutputTextFile(Filename(tmpdir_obj, "lib/extra.g"), false);; gap> CloseStream(stream); gap> stream := OutputTextFile(Filename(tmpdir_obj, "gap/sub/ignore.txt"), false);; gap> CloseStream(stream); gap> AUTODOC_FindMatchingFiles(tmpdir_obj, ["gap", "lib"], ["g", "gi", "gd"]); [ "gap/sub/nested.gi", "gap/top.gd", "lib/extra.g" ] gap> RemoveDirectoryRecursively(tmpdir); true # # AutoDoc_Parser_ReadFiles: multiline InstallMethod parsing # gap> autodoc_pkgroot := Filename( DirectoriesPackageLibrary( "AutoDoc", "" ), "" );; gap> if not StartsWith( autodoc_pkgroot, "/" ) then > autodoc_pkgroot := Filename( > Directory( AUTODOC_CurrentDirectory() ), > autodoc_pkgroot > ); > fi; gap> parser_fixture := rec( > path := Filename( > Directory( autodoc_pkgroot ), > "tst/autodoc-parser-installmethod.g" > ), > display := "tst/autodoc-parser-installmethod.g" > );; gap> tree := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles( [ parser_fixture ], tree, rec() ); gap> section := SectionInTree( tree, "Parser", "InstallMethod" );; gap> item := section!.content[ 1 ];; gap> item!.item_type; "Func" gap> item!.name; "MyOp" gap> item!.tester_names; "for IsInt,IsString" gap> item!.arguments; "x,y" gap> olddir := Filename(DirectoryCurrent(), "");; gap> ChangeDirectoryCurrent(Filename(DirectoryTemporary(), "")); true gap> tree := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles( > [ parser_fixture ], > tree, > rec() > ); gap> ChangeDirectoryCurrent(olddir); true gap> section := SectionInTree( tree, "Parser", "InstallMethod" );; gap> item := section!.content[ 1 ];; gap> item!.item_type; "Func" gap> item!.name; "MyOp" gap> item!.tester_names; "for IsInt,IsString" gap> item!.arguments; "x,y" # # AutoDoc_Parser_ReadFiles: DeclareGlobalName defaults and overrides # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-globalname-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file := Filename(tmpdir_obj, "globalname.gd");; gap> stream := OutputTextFile(file, false);; gap> AppendTo(stream, "#! @Chapter Parser\n");; gap> AppendTo(stream, "#! @Section GlobalName\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "DeclareGlobalName( \"DefaultGlobalName\" );\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "#! @Arguments x\n");; gap> AppendTo(stream, "DeclareGlobalName( \"ArgumentGlobalName\" );\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "#! @Returns a value\n");; gap> AppendTo(stream, "DeclareGlobalName( \"ReturnGlobalName\" );\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "#! @ItemType Var\n");; gap> AppendTo(stream, "DeclareGlobalName( \"VariableGlobalName\" );\n");; gap> CloseStream(stream); gap> tree := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles( [ file ], tree, rec() ); gap> section := SectionInTree( tree, "Parser", "GlobalName" );; gap> section!.content[ 1 ]!.item_type; "Var" gap> section!.content[ 1 ]!.arguments = fail; true gap> section!.content[ 2 ]!.item_type; "Func" gap> section!.content[ 2 ]!.arguments; "x" gap> section!.content[ 3 ]!.item_type; "Func" gap> section!.content[ 3 ]!.arguments; "arg" gap> section!.content[ 4 ]!.item_type; "Var" gap> section!.content[ 4 ]!.arguments = fail; true gap> RemoveDirectoryRecursively(tmpdir); true # # AutoDoc_Parser_ReadFiles: bare tester label keeps an empty argument list # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-empty-args-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file := Filename(tmpdir_obj, "emptyargs.gd");; gap> stream := OutputTextFile(file, false);; gap> AppendTo(stream, "#! @Chapter Parser\n");; gap> AppendTo(stream, "#! @Section Empty Arguments\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "DeclareOperation( \"EmptyArgsOp\", [ ] );\n");; gap> CloseStream(stream); gap> tree := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles( [ file ], tree, rec() ); gap> section := SectionInTree( tree, "Parser", "Empty Arguments" );; gap> item := section!.content[ 1 ];; gap> item!.tester_names = fail; true gap> item!.arguments; "" gap> RemoveDirectoryRecursively(tmpdir); true # # warn about defined-but-never-inserted chunks # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-unusedchunk-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tree2 := DocumentationTree();; gap> chunk := DocumentationChunk(tree2, "NeverUsed");; gap> chunk!.is_defined := true;; gap> Add(chunk!.content, "Some text");; gap> WriteDocumentation(tree2, Directory(tmpdir)); #I WARNING: chunk NeverUsed was defined but never inserted gap> RemoveDirectoryRecursively(tmpdir); true # # warn about inserted-but-never-defined chunks # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-missingchunk-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tree3 := DocumentationTree();; gap> chunk := DocumentationChunk(tree3, "MissingChunk");; gap> chunk!.is_inserted := true;; gap> WriteDocumentation(tree3, Directory(tmpdir)); #I WARNING: chunk MissingChunk was inserted but never defined gap> RemoveDirectoryRecursively(tmpdir); true # # mixed explicit and implicit chapter info with grouped declarations # see # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-mixed-context-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file1 := Filename(tmpdir_obj, "explicit.gd");; gap> stream := OutputTextFile(file1, false);; gap> AppendTo(stream, "#! @Chapter Explicit\n");; gap> AppendTo(stream, "#! @Section Intro\n");; gap> CloseStream(stream); gap> file2 := Filename(tmpdir_obj, "implicit.gd");; gap> stream := OutputTextFile(file2, false);; gap> AppendTo(stream, "#! @BeginGroup grouped\n");; gap> AppendTo(stream, "DeclareOperation( \"MixedOp\", [ IsObject ] );\n");; gap> CloseStream(stream); gap> tree4 := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles([file1, file2], tree4, CreateDefaultChapterData("Pkg")); gap> auto_section := SectionInTree(tree4, > "Pkg_automatic_generated_documentation", > "Pkg_automatic_generated_documentation_of_methods");; gap> group := auto_section!.content[1];; gap> Label(group); "GROUP_grouped" gap> group!.content[1]!.name; "MixedOp" gap> RemoveDirectoryRecursively(tmpdir); true # # context stack drives nested parser targets # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-context-stack-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file1 := Filename(tmpdir_obj, "context.gd");; gap> stream := OutputTextFile(file1, false);; gap> AppendTo(stream, "#! @Title Parser Stack Test\n");; gap> AppendTo(stream, "#! @Chapter Parser\n");; gap> AppendTo(stream, "#! @Section Context Stack\n");; gap> AppendTo(stream, "#! Intro before chunk.\n");; gap> AppendTo(stream, "#! @BeginChunk Stored\n");; gap> AppendTo(stream, "#! chunk line 1\n");; gap> AppendTo(stream, "#! @BeginLatexOnly\n");; gap> AppendTo(stream, "#! latex only\n");; gap> AppendTo(stream, "#! @EndLatexOnly\n");; gap> AppendTo(stream, "#! chunk line 2\n");; gap> AppendTo(stream, "#! @EndChunk\n");; gap> AppendTo(stream, "#! @InsertChunk Stored\n");; gap> AppendTo(stream, "#! Outro after chunk.\n");; gap> CloseStream(stream); gap> tree5 := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles([file1], tree5, rec()); gap> tree5!.TitlePage.Title; [ "Parser Stack Test" ] gap> section := SectionInTree(tree5, "Parser", "Context_Stack");; gap> section!.content[1]; " Intro before chunk.\n" gap> chunk := section!.content[2];; gap> HasLabel(chunk); true gap> chunk!.content[1]; " chunk line 1\n" gap> chunk!.content[2]!.element_name; "Alt" gap> chunk!.content[2]!.attributes; rec( Only := "LaTeX" ) gap> chunk!.content[2]!.content; [ " latex only\n" ] gap> chunk!.content[3]; " chunk line 2\n" gap> section!.content[3]; " Outro after chunk.\n" gap> RemoveDirectoryRecursively(tmpdir); true # # only the first declaration after an AutoDoc comment is documented # see https://github.com/gap-packages/AutoDoc/issues/169 # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-consecutive-declarations-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file1 := Filename(tmpdir_obj, "consecutive.gd");; gap> stream := OutputTextFile(file1, false);; gap> AppendTo(stream, "#! @Chapter Parser\n");; gap> AppendTo(stream, "#! @Section Consecutive Declarations\n");; gap> AppendTo(stream, "#! @Description\n");; gap> AppendTo(stream, "#! Only this declaration should be documented.\n");; gap> AppendTo(stream, "DeclareGlobalFunction( \"Foo\" );\n");; gap> AppendTo(stream, "DeclareGlobalFunction( \"Bar\" );\n");; gap> CloseStream(stream); gap> tree6 := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles([file1], tree6, rec()); gap> section := SectionInTree(tree6, "Parser", "Consecutive_Declarations");; gap> Length(section!.content); 1 gap> item := section!.content[1];; gap> item!.name; "Foo" gap> item!.description; [ " Only this declaration should be documented.\n" ] gap> RemoveDirectoryRecursively(tmpdir); true # # example and log blocks require matching end markers # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-example-end-marker-test");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> file1 := Filename(tmpdir_obj, "example-end-markers.gd");; gap> stream := OutputTextFile(file1, false);; gap> AppendTo(stream, "#! @Chapter Parser\n");; gap> AppendTo(stream, "#! @Section End Markers\n");; gap> AppendTo(stream, "#! @BeginExample\n");; gap> AppendTo(stream, "1 + 1;\n");; gap> AppendTo(stream, "#! @EndLog\n");; gap> AppendTo(stream, "#! still example output\n");; gap> AppendTo(stream, "#! @EndExample\n");; gap> AppendTo(stream, "#! @BeginExampleSession\n");; gap> AppendTo(stream, "#! gap> 2 + 2;\n");; gap> AppendTo(stream, "#! @EndLogSession\n");; gap> AppendTo(stream, "#! 4\n");; gap> AppendTo(stream, "#! @EndExampleSession\n");; gap> CloseStream(stream); gap> tree7 := DocumentationTree();; gap> AutoDoc_Parser_ReadFiles([file1], tree7, rec()); gap> section := SectionInTree(tree7, "Parser", "End_Markers");; gap> example := section!.content[1];; gap> example!.element_name; "Example" gap> example!.content; [ "gap> 1 + 1;", "@EndLog", "still example output" ] gap> session_example := section!.content[2];; gap> session_example!.element_name; "Example" gap> session_example!.content; [ "gap> 2 + 2;", "@EndLogSession", "4" ] gap> RemoveDirectoryRecursively(tmpdir); true # gap> STOP_TEST( "misc.tst" ); AutoDoc-2026.05.03/tst/testall.g0000644000000000000000000000027515175510000013025 0ustar00LoadPackage( "AutoDoc" ); SetInfoLevel(InfoAutoDoc, 1); SetInfoLevel(InfoGAPDoc, 0); TestDirectory( DirectoriesPackageLibrary("AutoDoc", "tst"), rec(exitGAP := true ) ); FORCE_QUIT_GAP(1); AutoDoc-2026.05.03/tst/utils.g0000644000000000000000000001616215175510000012517 0ustar00# Helpers shared by the package-level AutoDoc regression tests. # # AUTODOC_RunPackageScenario runs one makedoc-based scenario for the # tst/AutoDocTest fixture package in an isolated temporary copy. # Arguments: # pkgdir absolute path to tst/AutoDocTest/ # olddir caller's original working directory, restored on exit # scenario record describing the scenario to run; it must contain # `name` and `makedoc`, and may additionally specify: # - `workdir := "subdir"` to run Read(makedoc) from a nested cwd # - `stub_gapdoc := true` to skip the expensive GAPDoc post-pass # - `doc_expected := "tst/...expected"` for full doc-file diffs # - `tst_expected := "tst/...expected"` for extracted-test diffs # - `doc_present := [ ... ]` / `doc_absent := [ ... ]` for # presence/absence checks AUTODOC_RunPackageScenario := function( pkgdir, olddir, scenario ) local tempdir, docdir, tstdir, ex_dir, files, expected, actual, old_makegapdocdoc, old_copyhtmlstylefiles, old_manuallab, old_autodoc_level, old_gapdoc_level, old_warning_level, f, source_doc_files, source_tst_files, workdir; tempdir := Filename( DirectoryTemporary(), Concatenation( "autodoctest-", scenario.name ) ); if IsDirectoryPath( tempdir ) then RemoveDirectoryRecursively( tempdir ); fi; # Work in a temporary package copy so the checked-in fixture tree stays # untouched and the scenario can freely create/remove generated files. Exec( Concatenation( "cp -R \"", pkgdir, "\" \"", tempdir, "\"" ) ); ChangeDirectoryCurrent( tempdir ); docdir := Directory( Concatenation( tempdir, "/doc" ) ); # Keep only handwritten fixture inputs in doc/. Any pre-existing generated # output would otherwise make presence/absence checks depend on stale files # from the repository checkout instead of this scenario run. source_doc_files := [ "AutoDocTest.bib", "appendix.autodoc", "appendix1.xml", "chapter1.xml", "chapter2.autodoc", "extract-examples.xml", "manual.six", ]; for f in DirectoryContents( docdir ) do if f = "." or f = ".." or f in source_doc_files then continue; fi; RemoveFile( Filename( docdir, f ) ); od; tstdir := Directory( Concatenation( tempdir, "/tst" ) ); # Likewise, keep the package's test driver but remove any generated .tst # files so extract_examples checks only inspect fresh output. source_tst_files := [ "testall.g" ]; for f in DirectoryContents( tstdir ) do if f = "." or f = ".." or f in source_tst_files then continue; fi; RemoveFile( Filename( tstdir, f ) ); od; if IsBound( scenario.stub_gapdoc ) and scenario.stub_gapdoc then # These scenarios only care about scaffold-side file creation, not the # full GAPDoc build. Stub the GAPDoc entry points to keep the test fast # and to avoid requiring files that are intentionally not generated. old_makegapdocdoc := MakeGAPDocDoc; old_copyhtmlstylefiles := CopyHTMLStyleFiles; old_manuallab := GAPDocManualLabFromSixFile; MakeReadWriteGlobal( "MakeGAPDocDoc" ); MakeReadWriteGlobal( "CopyHTMLStyleFiles" ); MakeReadWriteGlobal( "GAPDocManualLabFromSixFile" ); MakeGAPDocDoc := function( arg... ) return true; end; CopyHTMLStyleFiles := function( arg... ) return true; end; GAPDocManualLabFromSixFile := function( arg... ) return true; end; # AutoDoc checks that manual.six is readable before calling the # stubbed GAPDocManualLabFromSixFile hook. actual := OutputTextFile( Filename( docdir, "manual.six" ), false ); CloseStream( actual ); fi; old_autodoc_level := InfoLevel( InfoAutoDoc ); old_gapdoc_level := InfoLevel( InfoGAPDoc ); old_warning_level := InfoLevel( InfoWarning ); SetInfoLevel( InfoAutoDoc, 0 ); SetInfoLevel( InfoGAPDoc, 0 ); SetInfoLevel( InfoWarning, 0 ); if IsBound( scenario.workdir ) then workdir := Filename( Directory( tempdir ), scenario.workdir ); AUTODOC_CreateDirIfMissing( workdir ); ChangeDirectoryCurrent( workdir ); fi; Read( scenario.makedoc : nopdf ); SetInfoLevel( InfoAutoDoc, old_autodoc_level ); SetInfoLevel( InfoGAPDoc, old_gapdoc_level ); SetInfoLevel( InfoWarning, old_warning_level ); if IsBound( scenario.stub_gapdoc ) and scenario.stub_gapdoc then # Restore the real GAPDoc hooks before the next scenario runs. MakeGAPDocDoc := old_makegapdocdoc; CopyHTMLStyleFiles := old_copyhtmlstylefiles; GAPDocManualLabFromSixFile := old_manuallab; fi; if IsBound( scenario.doc_expected ) then # Compare the generated documentation tree against a stored fixture. ex_dir := Directory( Concatenation( pkgdir, scenario.doc_expected ) ); files := DirectoryContents( ex_dir ); files := Filtered( files, file -> file <> "." and file <> ".." ); Sort( files ); for f in files do expected := Filename( ex_dir, f ); actual := Filename( docdir, f ); if not IsReadableFile( actual ) then Error( "missing generated file ", f, " in scenario ", scenario.name ); fi; if 0 <> AUTODOC_Diff( "-u", expected, actual ) then Error( "diff detected in scenario ", scenario.name, " for file ", f ); fi; od; fi; if IsBound( scenario.tst_expected ) then # Compare extracted example tests against stored expected .tst files. ex_dir := Directory( Concatenation( pkgdir, scenario.tst_expected ) ); files := DirectoryContents( ex_dir ); files := Filtered( files, file -> file <> "." and file <> ".." ); Sort( files ); for f in files do expected := Filename( ex_dir, f ); actual := Filename( tstdir, f ); if not IsReadableFile( actual ) then Error( "missing extracted test ", f, " in scenario ", scenario.name ); fi; if 0 <> AUTODOC_Diff( "-u", expected, actual ) then Error( "diff detected in scenario ", scenario.name, " for test ", f ); fi; od; fi; if IsBound( scenario.doc_present ) then # Some scenarios only care whether specific files were generated. for f in scenario.doc_present do actual := Filename( docdir, f ); if not IsReadableFile( actual ) then Error( "missing expected generated file ", f, " in scenario ", scenario.name ); fi; od; fi; if IsBound( scenario.doc_absent ) then # And some assert that a file was intentionally not generated. for f in scenario.doc_absent do actual := Filename( docdir, f ); if IsExistingFile( actual ) then Error( "unexpected generated file ", f, " in scenario ", scenario.name ); fi; od; fi; ChangeDirectoryCurrent( olddir ); RemoveDirectoryRecursively( tempdir ); end; AutoDoc-2026.05.03/tst/worksheets/0000755000000000000000000000000015175510000013377 5ustar00AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/0000755000000000000000000000000015175510000017173 5ustar00AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/Plain_file.autodoc_Test.xml0000644000000000000000000000050015175510000024406 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/_AutoDocMainFile.xml0000644000000000000000000000020015175510000023007 0ustar00 <#Include SYSTEM "_Chapter_Test.xml"> AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/_Chapter_Test.xml0000644000000000000000000000326115175510000022443 0ustar00 Test Does AutoDoc have a way to allow that header block not to appear in the documentation generated from a .autodoc file like this?
First Section First Subsection S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 ]]> Some text between two examples Plain worksheet index entry with true ampersand key less-than key indented command parsing works A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 ]]> plain_mode_value := 6 * > 9; 54 ]]> A plain-text line mentioning @Section InlineMention should stay plain text. And an unfenced .autodoc line beginning with #! should stay literal: #! PlainAutodocLiteral And fenced listings in .autodoc files should also keep would-be comments literal: Also, markdown-like inline true should become a keyword tag. And XML comments should pass through verbatim: And we wrap up with some dummy text
AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/_Chunks.xml0000644000000000000000000000000015175510000021275 0ustar00AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/_entities.xml0000644000000000000000000000011715175510000021677 0ustar00Plain_file.autodoc_Test'> AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/title.xml0000644000000000000000000000031115175510000021031 0ustar00 Plain file.autodoc Test 8 March 2026 AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/tst/0000755000000000000000000000000015175510000020005 5ustar00AutoDoc-2026.05.03/tst/worksheets/autoplain.expected/tst/plain_file.autodoc_test01.tst0000644000000000000000000000144115175510000025500 0ustar00# 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:15-20 gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 # _Chapter_Test.xml:28-33 gap> A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 # _Chapter_Test.xml:35-39 gap> plain_mode_value := 6 * > 9; 54 # gap> STOP_TEST("plain_file.autodoc_test01.tst", 1); AutoDoc-2026.05.03/tst/worksheets/autoplain.sheet/0000755000000000000000000000000015175510000016502 5ustar00AutoDoc-2026.05.03/tst/worksheets/autoplain.sheet/plain.autodoc0000644000000000000000000000241615175510000021170 0ustar00@Title Plain file.autodoc Test @Date 8 March 2026 # Test Does AutoDoc have a way to allow that header block not to appear in the documentation generated from a .autodoc file like this? ## First Section ### First Subsection @BeginExampleSession gap> S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 @EndExampleSession Some text between two examples @Index "Worksheet Autoplain" Plain worksheet index entry with `true` @Index WorksheetAutoplainKeyOnly @Index A&B ampersand key @Index A A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 @EndExampleSession @BeginExample plain_mode_value := 6 * 9; #! 54 @EndExample A plain-text line mentioning @Section InlineMention should stay plain text. And an unfenced .autodoc line beginning with #! should stay literal: #! PlainAutodocLiteral And fenced listings in .autodoc files should also keep would-be comments literal: ```@listing @Section PlainTextFenceLiteral #! PlainFenceLiteral ``` Also, markdown-like inline `true` should become a keyword tag. And XML comments should pass through verbatim: And we wrap up with some dummy text AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/0000755000000000000000000000000015175510000022174 5ustar00AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/PaxHeaders/Consecutive_Declarati0000644000000000000000000000015715175510000030515 xustar00111 path=AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/Consecutive_Declarations_Test.xml AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/Consecutive_Declarations_Test.xm0000644000000000000000000000050615175510000030521 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/_AutoDocMainFile.xml0000644000000000000000000000021715175510000026020 0ustar00 <#Include SYSTEM "_Chapter_Consecutive_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/_Chapter_Consecutive_Chapter.xml0000644000000000000000000000122315175510000030456 0ustar00 Consecutive Chapter
Consecutive Section Worksheet regression for issue #169. First declaration stays documented. Third declaration has its own comment block.
AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/_Chunks.xml0000644000000000000000000000000015175510000024276 0ustar00AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/_entities.xml0000644000000000000000000000013315175510000024676 0ustar00Consecutive_Declarations_Test'> AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.expected/title.xml0000644000000000000000000000032015175510000024032 0ustar00 Consecutive Declarations Test 12 March 2026 AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.sheet/0000755000000000000000000000000015175510000021503 5ustar00AutoDoc-2026.05.03/tst/worksheets/consecutive-declarations.sheet/worksheet.g0000644000000000000000000000067515175510000023676 0ustar00#! @Title Consecutive Declarations Test #! @Date 2026-03-12 #! @Chapter Consecutive Chapter #! @Section Consecutive Section #! Worksheet regression for issue #169. #! @Description #! First declaration stays documented. DeclareGlobalFunction( "FirstConsecutiveFunction" ); DeclareGlobalFunction( "SecondConsecutiveFunction" ); #! @Description #! Third declaration has its own comment block. DeclareGlobalFunction( "ThirdConsecutiveFunction" ); AutoDoc-2026.05.03/tst/worksheets/general.expected/0000755000000000000000000000000015175510000016614 5ustar00AutoDoc-2026.05.03/tst/worksheets/general.expected/General_Test.xml0000644000000000000000000000046515175510000021717 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/general.expected/_AutoDocMainFile.xml0000644000000000000000000000026515175510000022443 0ustar00 <#Include SYSTEM "_Chapter_SomeChapter.xml"> <#Include SYSTEM "_Chapter_labelChapter.xml"> AutoDoc-2026.05.03/tst/worksheets/general.expected/_Chapter_SomeChapter.xml0000644000000000000000000001461515175510000023364 0ustar00 SomeChapter This is dummy text S5 := SymmetricGroup(5); Sym( [ 1 .. 5 ] ) gap> Size(S5); 120 ]]> Some text between two examples General worksheet index entry with true greater-than key quote key A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 gap> # Test whether ]]]]> can be used safely gap> [[2]]]]>[[1]]; true ]]> comment_mode_value := 6 * > 7; 42 ]]> 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. This is true in a list item.

All of this can also be used outside of a list. And fenced listings should keep would-be commands literal:

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 documented as a variable by default A global name documented as a function once arguments are given true or false 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-2026.05.03/tst/worksheets/general.expected/_Chapter_labelChapter.xml0000644000000000000000000000067515175510000023541 0ustar00 Label test chapter This is dummy text

Label test section This is dummy text

Label test subsection This is dummy text

AutoDoc-2026.05.03/tst/worksheets/general.expected/_Chunks.xml0000644000000000000000000000042415175510000020730 0ustar00<#GAPDoc Label="MyChunk"> Hello, world. This line is indented! <#/GAPDoc> <#GAPDoc Label="MyCode"> 2"); fi; ]]> <#/GAPDoc> AutoDoc-2026.05.03/tst/worksheets/general.expected/_entities.xml0000644000000000000000000000007115175510000021317 0ustar00General_Test'> AutoDoc-2026.05.03/tst/worksheets/general.expected/title.xml0000644000000000000000000000030015175510000020450 0ustar00 General Test 30 August 2018 AutoDoc-2026.05.03/tst/worksheets/general.expected/tst/0000755000000000000000000000000015175510000017426 5ustar00AutoDoc-2026.05.03/tst/worksheets/general.expected/tst/general_test01.tst0000644000000000000000000000153015175510000022776 0ustar00# 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:20-28 gap> A5 := AlternatingGroup(5); Alt( [ 1 .. 5 ] ) gap> Size(A5); 60 gap> # Test whether ]]> can be used safely gap> [[2]]>[[1]]; true # _Chapter_SomeChapter.xml:30-34 gap> comment_mode_value := 6 * > 7; 42 # gap> STOP_TEST("general_test01.tst", 1); AutoDoc-2026.05.03/tst/worksheets/general.sheet/0000755000000000000000000000000015175510000016123 5ustar00AutoDoc-2026.05.03/tst/worksheets/general.sheet/worksheet.g0000644000000000000000000001351715175510000020315 0ustar00############################################################################# ## ## 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 #! @Index "Worksheet General" General worksheet index entry with `true` #! @Index WorksheetGeneralKeyOnly #! @Index A>B greater-than key #! @Index A"B quote key #! @BeginExampleSession #! gap> A5 := AlternatingGroup(5); #! Alt( [ 1 .. 5 ] ) #! gap> Size(A5); #! 60 #! gap> # Test whether ]]> can be used safely #! gap> [[2]]>[[1]]; #! true #! @EndExampleSession #! @BeginExample comment_mode_value := 6 * 7; #! 42 #! @EndExample #! And we wrap up with some dummy text ############################################################################# #! @Section Some categories #! Intro text DeclareCategory("MyThings", IsObject); #! @Description DeclareCategoryCollections("MyThings"); #! @Description 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. #! * This is `true` in a list item. #! #! All of this can **also** be __used__ outside of a `list`. #! And fenced listings should keep would-be commands literal: #! ```@listing #! @Section ThisMustStayLiteral #! #! AlsoLiteral #! ``` #! @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 documented as a variable by default DeclareGlobalName( "SomeGlobalName" ); #! @Description #! A global name documented as a function once arguments are given #! @Arguments x DeclareGlobalName( "SomeGlobalNameFunction" ); #! @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. #! @Chapter Label test chapter #! @ChapterLabel labelChapter #! This is dummy text #! #! @Section Label test section #! @SectionLabel labelSection #! This is dummy text #! #! @Subsection Label test subsection #! @SubsectionLabel labelSubsection #! This is dummy text AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/0000755000000000000000000000000015175510000020672 5ustar00AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/Item_Type_Metadata_Test.xml0000644000000000000000000000050015175510000026105 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/_AutoDocMainFile.xml0000644000000000000000000000021615175510000024515 0ustar00 <#Include SYSTEM "_Chapter_Item_Types_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/_Chapter_Item_Types_Chapter.xml0000644000000000000000000000431015175510000026747 0ustar00 Item Types Chapter
Type Overrides Worksheet regression for item-type metadata and issue #174. A synonym documented as a function by default. true or false A synonym documented as a filter. true or false A synonym documented as a category. true or false A synonym documented as a collection. true or false A synonym documented as a representation. A family-like global name. An info class-like global name. A method documented as a method by default. A method documented as a constructor. An explicit method override. A synonym attribute.
AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/_Chunks.xml0000644000000000000000000000000015175510000022774 0ustar00AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/_entities.xml0000644000000000000000000000011715175510000023376 0ustar00Item_Type_Metadata_Test'> AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.expected/title.xml0000644000000000000000000000031215175510000022531 0ustar00 Item Type Metadata Test 12 March 2026 AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.sheet/0000755000000000000000000000000015175510000020201 5ustar00AutoDoc-2026.05.03/tst/worksheets/item-type-metadata.sheet/worksheet.g0000644000000000000000000000343015175510000022364 0ustar00#! @Title Item Type Metadata Test #! @Date 2026-03-12 #! @Chapter Item Types Chapter #! @Section Type Overrides #! Worksheet regression for item-type metadata and issue #174. #! @Description #! A synonym documented as a function by default. DeclareSynonym( "SomeFunctionAlias", SomeFunction ); #! @Description #! @ItemType Filt #! A synonym documented as a filter. DeclareSynonym( "IsSomeFilterAlias", IsObject ); #! @Description #! @ItemType Cat #! A synonym documented as a category. DeclareSynonym( "IsSomeCategoryAlias", IsObject ); #! @Description #! @ItemType Coll #! A synonym documented as a collection. DeclareSynonym( "IsSomeCollectionAlias", IsObject ); #! @Description #! @ItemType Repr #! A synonym documented as a representation. DeclareSynonym( "IsSomeRepresentationAlias", IsComponentObjectRep ); #! @Description #! A family-like global name. #! @ItemType Fam DeclareGlobalName( "SomeFamilyAlias" ); #! @Description #! An info class-like global name. #! @ItemType InfoClass DeclareGlobalName( "SomeInfoClassAlias" ); #! @Description #! A method documented as a method by default. InstallMethod( "SomeInstalledMethod", [ IsObject, IsInt ], function( obj, n ) return obj; end ); #! @Description #! @ItemType Constr #! A method documented as a constructor. InstallMethod( "SomeInstalledConstructor", [ IsObject ], function( obj ) return obj; end ); #! @Description #! @ItemType Meth #! An explicit method override. InstallMethod( "SomeExplicitMethod", [ IsObject ], function( obj ) return obj; end ); #! @Description #! A synonym attribute. DeclareSynonymAttr( "SomeAttributeAlias", SomeAttribute ); AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/0000755000000000000000000000000015175510000020100 5ustar00AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/Label_Entities_Test.xml0000644000000000000000000000047415175510000024511 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/_AutoDocMainFile.xml0000644000000000000000000000021015175510000023715 0ustar00 <#Include SYSTEM "_Chapter_Introduction.xml"> AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/_Chapter_Introduction.xml0000644000000000000000000000074715175510000025120 0ustar00 Introduction

What is &GAP;?

Entity-driven heading text should stay unchanged.

Explicit label section

Explicit label text should also stay unchanged.

AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/_Chunks.xml0000644000000000000000000000000015175510000022202 0ustar00AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/_entities.xml0000644000000000000000000000010715175510000022603 0ustar00Label_Entities_Test'> AutoDoc-2026.05.03/tst/worksheets/label-entities.expected/title.xml0000644000000000000000000000030615175510000021742 0ustar00 Label Entities Test 11 March 2026 AutoDoc-2026.05.03/tst/worksheets/label-entities.sheet/0000755000000000000000000000000015175510000017407 5ustar00AutoDoc-2026.05.03/tst/worksheets/label-entities.sheet/plain.autodoc0000644000000000000000000000037315175510000022075 0ustar00@Title Label Entities Test @Date 2026-03-11 @Chapter Introduction @Section What is &GAP;? Entity-driven heading text should stay unchanged. @Section Explicit label section @SectionLabel A&B "D" Explicit label text should also stay unchanged. AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/0000755000000000000000000000000015175510000021710 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/Paired_Blocks_Test.xml0000644000000000000000000000047315175510000026136 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/_AutoDocMainFile.xml0000644000000000000000000000021215175510000025527 0ustar00 <#Include SYSTEM "_Chapter_Blocks_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/_Chapter_Blocks_Chapter.xml0000644000000000000000000000240615175510000027124 0ustar00 Blocks Chapter
Primary Blocks Section Intro text for the block-oriented worksheet.

Injected Section This section exists so the paired structure stays aligned.

Utility Blocks Section

Text before inserting the stored chunk. <#Include Label="StoredChunk">

Text before inserting the stored code. <#Include Label="StoredCode">

Stop Here This text should appear before the parser stops.

AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/_Chunks.xml0000644000000000000000000000042015175510000024020 0ustar00<#GAPDoc Label="StoredChunk"> Chunk line one. Chunk line two with inline code. <#/GAPDoc> <#GAPDoc Label="StoredCode"> 10 then Print("block code reached\n"); fi; ]]> <#/GAPDoc> AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/_entities.xml0000644000000000000000000000010515175510000024411 0ustar00Paired_Blocks_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.expected/title.xml0000644000000000000000000000030415175510000023550 0ustar00 Paired Blocks Test 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.sheet/0000755000000000000000000000000015175510000021217 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-blocks-autoplain.sheet/plain.autodoc0000644000000000000000000000165615175510000023712 0ustar00@Title Paired Blocks Test @Date 2026-03-07 @Chapter Blocks Chapter @Section Primary Blocks Section Intro text for the block-oriented worksheet. @Section Injected Section This section exists so the paired structure stays aligned. @Section Utility Blocks Section @BeginChunk StoredChunk Chunk line one. Chunk line two with `inline code`. @EndChunk Text before inserting the stored chunk. @InsertChunk StoredChunk @BeginCode StoredCode block_value := 11; if block_value > 10 then Print("block code reached\n"); fi; @EndCode Text before inserting the stored code. @InsertCode StoredCode @LatexOnly \textbf{Latex-only inline text.} @BeginLatexOnly \emph{Latex-only block text.} @EndLatexOnly @NotLatex HTML-and-text inline output. @BeginNotLatex HTML-and-text block output. @EndNotLatex @Subsection Stop Here This text should appear before the parser stops. @DoNotReadRestOfFile This trailing text should never reach the expected XML. AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/0000755000000000000000000000000015175510000017716 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/Paired_Blocks_Test.xml0000644000000000000000000000047315175510000024144 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/_AutoDocMainFile.xml0000644000000000000000000000021215175510000023535 0ustar00 <#Include SYSTEM "_Chapter_Blocks_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/_Chapter_Blocks_Chapter.xml0000644000000000000000000000375015175510000025135 0ustar00 Blocks Chapter
Primary Blocks Section Intro text for the block-oriented worksheet. Block Group Title an object First grouped operation description. Second grouped declaration stays in the implicit group. This property joins the earlier group explicitly.
Injected Section This section exists so @ChapterInfo has a concrete destination. a record This attribute is redirected into the injected section.
Utility Blocks Section Text before inserting the stored chunk. <#Include Label="StoredChunk"> Text before inserting the stored code. <#Include Label="StoredCode"> Stop Here This text should appear before the parser stops.
AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/_Chunks.xml0000644000000000000000000000042215175510000022030 0ustar00<#GAPDoc Label="StoredChunk"> Chunk line one. Chunk line two with inline code. <#/GAPDoc> <#GAPDoc Label="StoredCode"> 10 then Print("block code reached\n"); fi; ]]> <#/GAPDoc> AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/_entities.xml0000644000000000000000000000010515175510000022417 0ustar00Paired_Blocks_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-blocks.expected/title.xml0000644000000000000000000000030415175510000021556 0ustar00 Paired Blocks Test 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-blocks.sheet/0000755000000000000000000000000015175510000017225 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-blocks.sheet/worksheet.g0000644000000000000000000000352015175510000021410 0ustar00#! @Title Paired Blocks Test #! @Date 2026-03-07 #! @Chapter Blocks Chapter #! @Section Primary Blocks Section #! Intro text for the block-oriented worksheet. #! @BeginGroup block-group #! @GroupTitle Block Group Title #! @Description #! First grouped operation description. #! @Returns an object #! @Arguments obj[, flag]: eager := true #! @Label grouped-operation-label DeclareOperation( "GroupedBlockOperation", [ IsObject ] ); #! @Description #! Second grouped declaration stays in the implicit group. DeclareAttribute( "GroupedBlockAttribute", IsObject ); #! @EndGroup #! @Description #! This property joins the earlier group explicitly. #! @Returns true or false #! @Arguments obj #! @Group block-group DeclareProperty( "LateJoinedBlockProperty", IsObject ); #! @Section Injected Section #! This section exists so @ChapterInfo has a concrete destination. #! @Section Utility Blocks Section #! @Description #! This attribute is redirected into the injected section. #! @Returns a record #! @Arguments source #! @ChapterInfo Blocks Chapter, Injected Section DeclareAttribute( "RedirectedBlockAttribute", IsObject ); #! @BeginChunk StoredChunk #! Chunk line one. #! Chunk line two with `inline code`. #! @EndChunk #! Text before inserting the stored chunk. #! @InsertChunk StoredChunk #! @BeginCode StoredCode block_value := 11; if block_value > 10 then Print("block code reached\n"); fi; #! @EndCode #! Text before inserting the stored code. #! @InsertCode StoredCode #! @LatexOnly \textbf{Latex-only inline text.} #! @BeginLatexOnly #! \emph{Latex-only block text.} #! @EndLatexOnly #! @NotLatex HTML-and-text inline output. #! @BeginNotLatex #! HTML-and-text block output. #! @EndNotLatex #! @Subsection Stop Here #! This text should appear before the parser stops. #! @DoNotReadRestOfFile #! This trailing text should never reach the expected XML. AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/0000755000000000000000000000000015175510000022251 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/Paired_Examples_Test.xml0000644000000000000000000000047515175510000027042 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/_AutoDocMainFile.xml0000644000000000000000000000021415175510000026072 0ustar00 <#Include SYSTEM "_Chapter_Examples_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/_Chapter_Examples_Chapter.xml0000644000000000000000000000227315175510000030030 0ustar00 Examples Chapter
Examples Section This worksheet exercises example and log commands in plain-text mode.

Tested examples plain_example_value := 2 + 3; 5 ]]>

plain_alias_example := 3 + 4; 7 ]]>

10 - 3; 7 ]]>

6 * 7; 42 ]]>

Untested logs plain_log_value := 9; 9 ]]>

plain_alias_log := 11; 11 ]]>

"plain log session"; "plain log session" ]]>

"plain alias log session"; "plain alias log session" ]]>

AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/_Chunks.xml0000644000000000000000000000000015175510000024353 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/_entities.xml0000644000000000000000000000011115175510000024747 0ustar00Paired_Examples_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/title.xml0000644000000000000000000000030615175510000024113 0ustar00 Paired Examples Test 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/tst/0000755000000000000000000000000015175510000023063 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.expected/tst/paired_examples_test01.tst0000644000000000000000000000143515175510000030164 0ustar00# Paired Examples 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("paired_examples_test01.tst"); # _Chapter_Examples_Chapter.xml:15-18 gap> plain_example_value := 2 + 3; 5 # _Chapter_Examples_Chapter.xml:21-24 gap> plain_alias_example := 3 + 4; 7 # _Chapter_Examples_Chapter.xml:27-30 gap> 10 - 3; 7 # _Chapter_Examples_Chapter.xml:33-36 gap> 6 * 7; 42 # gap> STOP_TEST("paired_examples_test01.tst", 1); AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.sheet/0000755000000000000000000000000015175510000021560 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples-autoplain.sheet/plain.autodoc0000644000000000000000000000127515175510000024250 0ustar00@Title Paired Examples Test @Date 2026-03-07 @Chapter Examples Chapter @Section Examples Section This worksheet exercises example and log commands in plain-text mode. @Subsection Tested examples @BeginExample plain_example_value := 2 + 3; #! 5 @EndExample @Example plain_alias_example := 3 + 4; #! 7 @EndExample @BeginExampleSession gap> 10 - 3; 7 @EndExampleSession @ExampleSession gap> 6 * 7; 42 @EndExampleSession @Subsection Untested logs @BeginLog plain_log_value := 9; #! 9 @EndLog @Log plain_alias_log := 11; #! 11 @EndLog @BeginLogSession gap> "plain log session"; "plain log session" @EndLogSession @LogSession gap> "plain alias log session"; "plain alias log session" @EndLogSession AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/0000755000000000000000000000000015175510000020257 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/Paired_Examples_Test.xml0000644000000000000000000000047515175510000025050 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/_AutoDocMainFile.xml0000644000000000000000000000021415175510000024100 0ustar00 <#Include SYSTEM "_Chapter_Examples_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/_Chapter_Examples_Chapter.xml0000644000000000000000000000224115175510000026031 0ustar00 Examples Chapter
Examples Section This worksheet exercises example and log commands in comment mode. Tested examples comment_example_value := 2 + 3; 5 ]]> comment_alias_example := 3 + 4; 7 ]]> 10 - 3; 7 ]]> 6 * 7; 42 ]]> Untested logs comment_log_value := 9; 9 ]]> comment_alias_log := 11; 11 ]]> "comment log session"; "comment log session" ]]> "comment alias log session"; "comment alias log session" ]]>
AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/_Chunks.xml0000644000000000000000000000000015175510000022361 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/_entities.xml0000644000000000000000000000011115175510000022755 0ustar00Paired_Examples_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/title.xml0000644000000000000000000000030615175510000022121 0ustar00 Paired Examples Test 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/tst/0000755000000000000000000000000015175510000021071 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples.expected/tst/paired_examples_test01.tst0000644000000000000000000000144115175510000026167 0ustar00# Paired Examples 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("paired_examples_test01.tst"); # _Chapter_Examples_Chapter.xml:14-17 gap> comment_example_value := 2 + 3; 5 # _Chapter_Examples_Chapter.xml:19-22 gap> comment_alias_example := 3 + 4; 7 # _Chapter_Examples_Chapter.xml:24-27 gap> 10 - 3; 7 # _Chapter_Examples_Chapter.xml:29-32 gap> 6 * 7; 42 # gap> STOP_TEST("paired_examples_test01.tst", 1); AutoDoc-2026.05.03/tst/worksheets/paired-examples.sheet/0000755000000000000000000000000015175510000017566 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-examples.sheet/worksheet.g0000644000000000000000000000144715175510000021757 0ustar00#! @Title Paired Examples Test #! @Date 2026-03-07 #! @Chapter Examples Chapter #! @Section Examples Section #! This worksheet exercises example and log commands in comment mode. #! @Subsection Tested examples #! @BeginExample comment_example_value := 2 + 3; #! 5 #! @EndExample #! @Example comment_alias_example := 3 + 4; #! 7 #! @EndExample #! @BeginExampleSession #! gap> 10 - 3; #! 7 #! @EndExampleSession #! @ExampleSession #! gap> 6 * 7; #! 42 #! @EndExampleSession #! @Subsection Untested logs #! @BeginLog comment_log_value := 9; #! 9 #! @EndLog #! @Log comment_alias_log := 11; #! 11 #! @EndLog #! @BeginLogSession #! gap> "comment log session"; #! "comment log session" #! @EndLogSession #! @LogSession #! gap> "comment alias log session"; #! "comment alias log session" #! @EndLogSession AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/0000755000000000000000000000000015175510000022473 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/Paired_Structure_Test.xml0000644000000000000000000000047615175510000027507 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/_AutoDocMainFile.xml0000644000000000000000000000021515175510000026315 0ustar00 <#Include SYSTEM "_Chapter_structure-chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/_Chapter_structure-chapter.xml0000644000000000000000000000141315175510000030505 0ustar00 Structure Chapter Title a^2 This chapter text uses bold, emphasis, and inline code. Chapter index entry with true

Structure Section Title b^2 Section text mentions * plain prose and keywords.

Structure Subsection Title c^2 Subsection text keeps the paired worksheet content aligned.

AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/_Chunks.xml0000644000000000000000000000000015175510000024575 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/_entities.xml0000644000000000000000000000011315175510000025173 0ustar00Paired_Structure_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.expected/title.xml0000644000000000000000000000044715175510000024343 0ustar00 Paired Structure Test Comment mode structure coverage 1.2 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.sheet/0000755000000000000000000000000015175510000022002 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure-autoplain.sheet/plain.autodoc0000644000000000000000000000124315175510000024465 0ustar00@Title Paired Structure Test @Subtitle Comment mode structure coverage @Version 1.2 @Date 2026-03-07 @Chapter Structure Chapter @ChapterLabel structure-chapter @ChapterTitle Structure Chapter Title $a^2$ This chapter text uses **bold**, __emphasis__, and `inline code`. @Index "Paired structure chapter" Chapter index entry with `true` @Section Structure Section @SectionLabel structure-section @SectionTitle Structure Section Title $b^2$ Section text mentions * plain prose and `keywords`. @Subsection Structure Subsection @SubsectionLabel structure-subsection @SubsectionTitle Structure Subsection Title $c^2$ Subsection text keeps the paired worksheet content aligned. AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/0000755000000000000000000000000015175510000020501 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/Paired_Structure_Test.xml0000644000000000000000000000047615175510000025515 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/_AutoDocMainFile.xml0000644000000000000000000000021515175510000024323 0ustar00 <#Include SYSTEM "_Chapter_structure-chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/_Chapter_structure-chapter.xml0000644000000000000000000000140415175510000026513 0ustar00 Structure Chapter Title a^2 This chapter text uses bold, emphasis, and inline code. Chapter index entry with true
Structure Section Title b^2 Section text mentions * plain prose and keywords. Structure Subsection Title c^2 Subsection text keeps the paired worksheet content aligned.
AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/_Chunks.xml0000644000000000000000000000000015175510000022603 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/_entities.xml0000644000000000000000000000011315175510000023201 0ustar00Paired_Structure_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-structure.expected/title.xml0000644000000000000000000000044715175510000022351 0ustar00 Paired Structure Test Comment mode structure coverage 1.2 7 March 2026 AutoDoc-2026.05.03/tst/worksheets/paired-structure.sheet/0000755000000000000000000000000015175510000020010 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-structure.sheet/worksheet.g0000644000000000000000000000132615175510000022175 0ustar00#! @Title Paired Structure Test #! @Subtitle Comment mode structure coverage #! @Version 1.2 #! @Date 2026-03-07 #! @Chapter Structure Chapter #! @ChapterLabel structure-chapter #! @ChapterTitle Structure Chapter Title $a^2$ #! This chapter text uses **bold**, __emphasis__, and `inline code`. #! @Index "Paired structure chapter" Chapter index entry with `true` #! @Section Structure Section #! @SectionLabel structure-section #! @SectionTitle Structure Section Title $b^2$ #! Section text mentions * plain prose and `keywords`. #! @Subsection Structure Subsection #! @SubsectionLabel structure-subsection #! @SubsectionTitle Structure Subsection Title $c^2$ #! Subsection text keeps the paired worksheet content aligned. AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/0000755000000000000000000000000015175510000022411 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/Paired_Titlepage_Test.xml0000644000000000000000000000047615175510000027343 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/_AutoDocMainFile.xml0000644000000000000000000000021515175510000026233 0ustar00 <#Include SYSTEM "_Chapter_Titlepage_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/_Chapter_Titlepage_Chapter.xml0000644000000000000000000000056615175510000030333 0ustar00 Titlepage Chapter
Titlepage Section This worksheet keeps title-page commands visible in a real worksheet.
AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/_Chunks.xml0000644000000000000000000000000015175510000024513 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/_entities.xml0000644000000000000000000000011315175510000025111 0ustar00Paired_Titlepage_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.expected/title.xml0000644000000000000000000000135215175510000024255 0ustar00 Paired Titlepage Test Comment mode title coverage 2.0 Internal worksheet fixture Ada Example 7 March 2026
Example Street 7
This worksheet exercises title-page commands in plain-text mode. 2026 Example Authors Thanks to the worksheet harness. Generated for AutoDoc regression coverage.
AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.sheet/0000755000000000000000000000000015175510000021720 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage-autoplain.sheet/plain.autodoc0000644000000000000000000000102115175510000024375 0ustar00@Title Paired Titlepage Test @Subtitle Comment mode title coverage @Version 2.0 @TitleComment Internal worksheet fixture @Author Ada Example @Date 2026-03-07 @Address Example Street 7 @Abstract This worksheet exercises title-page commands in plain-text mode. @Copyright 2026 Example Authors @Acknowledgements Thanks to the worksheet harness. @Colophon Generated for AutoDoc regression coverage. @Chapter Titlepage Chapter @Section Titlepage Section This worksheet keeps title-page commands visible in a real worksheet. AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/0000755000000000000000000000000015175510000020417 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/Paired_Titlepage_Test.xml0000644000000000000000000000047615175510000025351 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/_AutoDocMainFile.xml0000644000000000000000000000021515175510000024241 0ustar00 <#Include SYSTEM "_Chapter_Titlepage_Chapter.xml"> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/_Chapter_Titlepage_Chapter.xml0000644000000000000000000000056715175510000026342 0ustar00 Titlepage Chapter
Titlepage Section This worksheet keeps title-page commands visible in a real worksheet.
AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/_Chunks.xml0000644000000000000000000000000015175510000022521 0ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/_entities.xml0000644000000000000000000000011315175510000023117 0ustar00Paired_Titlepage_Test'> AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.expected/title.xml0000644000000000000000000000134715175510000022267 0ustar00 Paired Titlepage Test Comment mode title coverage 2.0 Internal worksheet fixture Ada Example 7 March 2026
Example Street 7
This worksheet exercises title-page commands in comment mode. 2026 Example Authors Thanks to the worksheet harness. Generated for AutoDoc regression coverage.
AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.sheet/0000755000000000000000000000000015175510000017726 5ustar00AutoDoc-2026.05.03/tst/worksheets/paired-titlepage.sheet/worksheet.g0000644000000000000000000000105615175510000022113 0ustar00#! @Title Paired Titlepage Test #! @Subtitle Comment mode title coverage #! @Version 2.0 #! @TitleComment Internal worksheet fixture #! @Author Ada Example #! @Date 2026-03-07 #! @Address Example Street 7 #! @Abstract This worksheet exercises title-page commands in comment mode. #! @Copyright 2026 Example Authors #! @Acknowledgements Thanks to the worksheet harness. #! @Colophon Generated for AutoDoc regression coverage. #! @Chapter Titlepage Chapter #! @Section Titlepage Section #! This worksheet keeps title-page commands visible in a real worksheet. AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/0000755000000000000000000000000015175510000021314 5ustar00AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/Punctuated_Filenames_Test.xml0000644000000000000000000000050215175510000027131 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/_AutoDocMainFile.xml0000644000000000000000000000023215175510000025135 0ustar00 <#Include SYSTEM "_Chapter_Alpha+Beta.GammaDeltaSlashBack.xml"> AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/PaxHeaders/_Chapter_Alpha+Beta.Gamma0000644000000000000000000000016515175510000030117 xustar00117 path=AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/_Chapter_Alpha+Beta.GammaDeltaSlashBack.xml AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/_Chapter_Alpha+Beta.GammaDeltaSlashB0000644000000000000000000000071115175510000030027 0ustar00 Alpha+Beta.Gamma:Delta/Slash\Back Chapter text for generated chapter filenames.
Section+Part.One:Two/Three\Four Section text for generated labels.
AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/_Chunks.xml0000644000000000000000000000000015175510000023416 0ustar00AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/_entities.xml0000644000000000000000000000012315175510000024015 0ustar00Punctuated_Filenames_Test'> AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.expected/title.xml0000644000000000000000000000045615175510000023164 0ustar00 Punctuated Filenames Test Relax generated chapter filenames 1.2 11 March 2026 AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.sheet/0000755000000000000000000000000015175510000020623 5ustar00AutoDoc-2026.05.03/tst/worksheets/punctuated-filenames.sheet/worksheet.g0000644000000000000000000000045115175510000023006 0ustar00#! @Title Punctuated Filenames Test #! @Subtitle Relax generated chapter filenames #! @Version 1.2 #! @Date 2026-03-11 #! @Chapter Alpha+Beta.Gamma:Delta/Slash\Back #! Chapter text for generated chapter filenames. #! @Section Section+Part.One:Two/Three\Four #! Section text for generated labels. AutoDoc-2026.05.03/tst/worksheets.tst0000644000000000000000000001025615175510000014137 0ustar00# # test worksheets # gap> START_TEST( "worksheets.tst" ); # gap> AUTODOC_TestWorkSheet("general"); #I Extracting manual examples for General Test package ... #I 2 chapters detected #I Chapter 1... #I extracted 3 examples #I Chapter 2... #I no examples # gap> AUTODOC_TestWorkSheet("consecutive-declarations"); #I Extracting manual examples for Consecutive Declarations Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("item-type-metadata"); #I Extracting manual examples for Item Type Metadata Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("autoplain"); #I Extracting manual examples for Plain file.autodoc Test package ... #I 1 chapters detected #I Chapter 1... #I extracted 3 examples # gap> AUTODOC_TestWorkSheet("label-entities"); #I Extracting manual examples for Label Entities Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-structure"); #I Extracting manual examples for Paired Structure Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-structure-autoplain"); #I Extracting manual examples for Paired Structure Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-blocks"); #I Extracting manual examples for Paired Blocks Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-blocks-autoplain"); #I Extracting manual examples for Paired Blocks Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-examples"); #I Extracting manual examples for Paired Examples Test package ... #I 1 chapters detected #I Chapter 1... #I extracted 4 examples # gap> tmpdir := Filename(DirectoryTemporary(), "autodoc-worksheet-subdir");; gap> if IsDirectoryPath(tmpdir) then RemoveDirectoryRecursively(tmpdir); fi; gap> AUTODOC_CreateDirIfMissing(tmpdir); true gap> tmpdir_obj := Directory(tmpdir);; gap> sheetdir := DirectoriesPackageLibrary( > "AutoDoc", "tst/worksheets/paired-examples.sheet" )[1];; gap> filenames := DirectoryContents(sheetdir);; gap> filenames := Filtered(filenames, f -> f <> "." and f <> "..");; gap> filenames := List(filenames, f -> Filename(sheetdir, f));; gap> old := InfoLevel(InfoAutoDoc);; gap> oldgapdoc := InfoLevel(InfoGAPDoc);; gap> SetInfoLevel(InfoAutoDoc, 0); gap> SetInfoLevel(InfoGAPDoc, 0); gap> AutoDocWorksheet( > filenames, > rec( > dir := tmpdir_obj, > extract_examples := rec(subdir := "tst/generated") > ) : nopdf > ); gap> SetInfoLevel(InfoAutoDoc, old); gap> SetInfoLevel(InfoGAPDoc, oldgapdoc); gap> expecteddir := DirectoriesPackageLibrary( > "AutoDoc", "tst/worksheets/paired-examples.expected/tst" > )[1];; gap> expected := Filename(expecteddir, "paired_examples_test01.tst");; gap> actual := Filename(tmpdir_obj, "tst/generated/paired_examples_test01.tst");; gap> if not IsReadableFile(actual) then > Error("missing generated file ", actual); > fi; gap> if IsReadableFile(Filename(tmpdir_obj, "tst/paired_examples_test01.tst")) then > Error("generated file was written to tst/ instead of the configured subdir"); > fi; gap> if 0 <> AUTODOC_Diff("-u", expected, actual) then > Error("diff detected in generated file ", actual); > fi; gap> RemoveDirectoryRecursively(tmpdir); true # gap> AUTODOC_TestWorkSheet("paired-examples-autoplain"); #I Extracting manual examples for Paired Examples Test package ... #I 1 chapters detected #I Chapter 1... #I extracted 4 examples # gap> AUTODOC_TestWorkSheet("paired-titlepage"); #I Extracting manual examples for Paired Titlepage Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("paired-titlepage-autoplain"); #I Extracting manual examples for Paired Titlepage Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # gap> AUTODOC_TestWorkSheet("punctuated-filenames"); #I Extracting manual examples for Punctuated Filenames Test package ... #I 1 chapters detected #I Chapter 1... #I no examples # # gap> STOP_TEST( "worksheets.tst" );