]> git.proxmox.com Git - pmg-docs.git/commitdiff
Initial commit
authorDietmar Maurer <dietmar@proxmox.com>
Wed, 22 Feb 2017 05:48:17 +0000 (06:48 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 22 Feb 2017 06:15:00 +0000 (07:15 +0100)
34 files changed:
GFDL.adoc [new file with mode: 0644]
Makefile [new file with mode: 0644]
api-viewer/PMGAPI.js [new file with mode: 0644]
api-viewer/apidata.js [new file with mode: 0644]
api-viewer/index.html [new file with mode: 0644]
asciidoc-pmg.in [new file with mode: 0644]
asciidoc/asciidoc-pmg.conf [new file with mode: 0644]
asciidoc/dblatex-custom.sty [new file with mode: 0644]
asciidoc/pmg-dblatex.xsl [new file with mode: 0644]
asciidoc/pmg-docbook.conf [new file with mode: 0644]
asciidoc/pmg-html.conf [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control.in [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/install [new file with mode: 0644]
debian/pmg-doc-generator.control [new file with mode: 0644]
debian/pmg-doc-generator.install [new file with mode: 0644]
debian/pmg-docs.control [new file with mode: 0644]
debian/pmg-docs.install [new file with mode: 0644]
debian/rules [new file with mode: 0755]
docinfo.xml [new file with mode: 0644]
extractapi.pl [new file with mode: 0755]
images/proxmox-ci-header.svg [new file with mode: 0755]
images/proxmox-logo.svg [new file with mode: 0644]
images/screenshot/gui-login-window.png [new file with mode: 0644]
index.adoc [new file with mode: 0644]
pmg-admin-guide-docinfo.xml.in [new file with mode: 0644]
pmg-admin-guide.adoc [new file with mode: 0644]
pmg-copyright.adoc [new file with mode: 0644]
pmg-doc-generator.mk.in [new file with mode: 0644]
pmg-intro.adoc [new file with mode: 0644]
png-verify.pl [new file with mode: 0755]
scan-adoc-refs [new file with mode: 0755]

diff --git a/GFDL.adoc b/GFDL.adoc
new file mode 100644 (file)
index 0000000..467b9a7
--- /dev/null
+++ b/GFDL.adoc
@@ -0,0 +1,424 @@
+GNU Free Documentation License
+==============================
+
+Version 1.3, 3 November 2008
+
+
+Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation,
+Inc. <http://fsf.org/>
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+.0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+.1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+.2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+.3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+.4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+.5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+.6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+.7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+.8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+.9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+.10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation 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.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+.11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 
+license published by Creative Commons Corporation, a not-for-profit 
+corporation with a principal place of business in San Francisco, 
+California, as well as future copyleft versions of that license 
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in 
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this 
+License, and if all works that were first published under this License 
+somewhere other than this MMC, and subsequently incorporated in whole or 
+in part into the MMC, (1) had no cover texts or invariant sections, and 
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..3d94ab1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,198 @@
+DGDIR=.
+ASCIIDOC_PMG=./asciidoc-pmg
+
+GEN_PACKAGE=pmg-doc-generator
+DOC_PACKAGE=pmg-docs
+
+# also update debian/changelog
+PKGREL=1
+
+ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH)
+
+GEN_DEB=${GEN_PACKAGE}_${DOCRELEASE}-${PKGREL}_${ARCH}.deb
+DOC_DEB=${DOC_PACKAGE}_${DOCRELEASE}-${PKGREL}_all.deb
+DOC_BUILDDEPS := dblatex, source-highlight, inkscape, imagemagick
+
+
+all: index.html
+
+.PHONY: verify-images
+verify-images: png-verify.pl
+       for i in ./images/screenshot/*.png; do ./png-verify.pl $$i; done
+
+ADOC_SOURCES_GUESS=$(filter-out %-synopsis.adoc %-opts.adoc %-table.adoc, $(wildcard *.adoc))
+.pmg-doc-depends link-refs.json: ${ADOC_SOURCES_GUESS} scan-adoc-refs
+       ./scan-adoc-refs *.adoc --depends .pmg-doc-depends.tmp > link-refs.json.tmp
+       @cmp --quiet .pmg-doc-depends .pmg-doc-depends.tmp || mv .pmg-doc-depends.tmp .pmg-doc-depends
+       @cmp --quiet link-refs.json link-refs.json.tmp || mv link-refs.json.tmp link-refs.json
+
+pmg-doc-generator.mk: .pmg-doc-depends pmg-doc-generator.mk.in
+       cat pmg-doc-generator.mk.in .pmg-doc-depends > $@.tmp
+       mv $@.tmp $@
+
+include ./pmg-doc-generator.mk
+
+GEN_DEB_SOURCES=                               \
+       pmg-doc-generator.mk                    \
+       ${MANUAL_SOURCES}                       \
+       docinfo.xml
+
+GEN_SCRIPTS=
+
+API_VIEWER_SOURCES=                            \
+       api-viewer/index.html                   \
+       api-viewer/apidoc.js
+
+asciidoc-pmg: asciidoc-pmg.in link-refs.json
+       cat asciidoc-pmg.in link-refs.json >asciidoc-pmg.tmp
+       sed -e s/@RELEASE@/${DOCRELEASE}/ -i asciidoc-pmg.tmp
+       chmod +x asciidoc-pmg.tmp
+       mv asciidoc-pmg.tmp asciidoc-pmg
+
+INDEX_INCLUDES=                                                                \
+       pmg-admin-guide.pdf                                             \
+       pmg-admin-guide.epub                                            \
+       chapter-index-table.adoc                                        \
+       man1-index-table.adoc                                           \
+       man5-index-table.adoc                                           \
+       man8-index-table.adoc                                           \
+       $(sort $(addsuffix .html, ${MANUAL_PAGES}) ${CHAPTER_LIST})
+
+ADOC_STDARG=-b $(shell pwd)/asciidoc/pmg-html -f asciidoc/asciidoc-pmg.conf -a icons -a data-uri -a "date=$(shell date)" -a "revnumber=${DOCRELEASE}"
+
+BROWSER?=xdg-open
+
+
+README.html: README.adoc
+       asciidoc -a toc ${ADOC_STDARG} -o $@ $<
+
+.PHONY: index
+index: index.html
+       $(BROWSER) index.html &
+
+chapter-index-table.adoc: asciidoc-pmg
+       ./asciidoc-pmg chapter-table >$@.tmp
+       mv $@.tmp $@
+
+man1-index-table.adoc: asciidoc-pmg
+       ./asciidoc-pmg man1page-table >$@.tmp
+       mv $@.tmp $@
+
+man5-index-table.adoc: asciidoc-pmg
+       ./asciidoc-pmg man5page-table >$@.tmp
+       mv $@.tmp $@
+
+man8-index-table.adoc: asciidoc-pmg
+       ./asciidoc-pmg man8page-table >$@.tmp
+       mv $@.tmp $@
+
+index.html: index.adoc ${API_VIEWER_SOURCES} ${INDEX_INCLUDES}
+       asciidoc ${ADOC_STDARG} -o $@ index.adoc
+
+pmg-admin-guide.html: ${PMG_ADMIN_GUIDE_ADOCDEPENDS}
+       asciidoc -a pmglogo ${ADOC_STDARG} -o $@ pmg-admin-guide.adoc
+
+pmg-admin-guide.chunked: ${PMG_ADMIN_GUIDE_ADOCDEPENDS}
+       rm -rf pmg-admin-guide.chunked
+       a2x -a docinfo -a docinfo1 -a icons -f chunked pmg-admin-guide.adoc
+
+PMG_DOCBOOK_CONF=-b $(shell pwd)/asciidoc/pmg-docbook -f asciidoc/asciidoc-pmg.conf
+
+pmg-admin-guide-docinfo.xml: pmg-admin-guide-docinfo.xml.in
+       sed -e 's/@RELEASE@/${DOCRELEASE}/' <$< >$@
+
+pmg-admin-guide.pdf: ${PMG_ADMIN_GUIDE_ADOCDEPENDS} docinfo.xml pmg-admin-guide-docinfo.xml
+       inkscape -z -D --export-pdf=proxmox-logo.pdf images/proxmox-logo.svg
+       inkscape -z -D --export-pdf=proxmox-ci-header.pdf images/proxmox-ci-header.svg
+       grep ">Release ${DOCRELEASE}<" pmg-admin-guide-docinfo.xml || (echo "wrong release in  pmg-admin-guide-docinfo.xml" && false);
+       a2x -a docinfo -a docinfo1 -f pdf -L --asciidoc-opts="${PMG_DOCBOOK_CONF}" --dblatex-opts "-p ./asciidoc/pmg-dblatex.xsl -s asciidoc/dblatex-custom.sty" pmg-admin-guide.adoc
+       rm proxmox-logo.pdf proxmox-ci-header.pdf
+
+pmg-admin-guide.epub: ${PMG_ADMIN_GUIDE_ADOCDEPENDS}
+       a2x -f epub --asciidoc-opts="${PMG_DOCBOOK_CONF}" pmg-admin-guide.adoc
+
+api-viewer/apidata.js: extractapi.pl
+       ./extractapi.pl >$@
+
+api-viewer/apidoc.js: api-viewer/apidata.js api-viewer/PMGAPI.js
+       cat api-viewer/apidata.js api-viewer/PMGAPI.js >$@
+
+.PHONY: dinstall
+dinstall: ${GEN_DEB} ${DOC_DEB}
+       dpkg -i ${GEN_DEB} ${DOC_DEB}
+
+.PHONY: deb
+deb:
+       rm -f ${GEN_DEB} ${DOC_DEB}
+       make all-debs
+
+.PHONY: all-debs
+all-debs: ${GEN_DEB} ${DOC_DEB}
+
+.PHONY: clean-build
+clean-build:
+       rm -rf build
+
+define prepare_build
+       rm -rf build-$1
+       mkdir build-$1
+       cp -a debian build-$1/debian
+       mv build-$1/debian/control.in build-$1/debian/control
+       echo >> build-$1/debian/control
+       cat debian/$1.control >> build-$1/debian/control
+       install -dm755 build-$1/usr/share/$1
+       install -dm755 build-$1/usr/share/doc/$1
+endef
+
+.PHONY: gen-deb
+gen-deb: $(GEN_DEB)
+$(GEN_DEB): $(GEN_DEB_SOURCES) asciidoc-pmg
+       $(call prepare_build,$(GEN_PACKAGE))
+       install -dm755 build-$(GEN_PACKAGE)/usr/bin
+       # install files
+       install -m 0644 ${GEN_DEB_SOURCES} build-$(GEN_PACKAGE)/usr/share/${GEN_PACKAGE}
+       #install -m 0755 ${GEN_SCRIPTS} build-$(GEN_PACKAGE)/usr/share/${GEN_PACKAGE}
+       # install asciidoc-pmg
+       install -m 0755 asciidoc-pmg build-$(GEN_PACKAGE)/usr/bin/
+       install -dm755 build-$(GEN_PACKAGE)/usr/share/${GEN_PACKAGE}/asciidoc/
+       install -m 0644 asciidoc/asciidoc-pmg.conf build-$(GEN_PACKAGE)/usr/share/${GEN_PACKAGE}/asciidoc/
+       install -m 0644 asciidoc/pmg-html.conf build-$(GEN_PACKAGE)/usr/share/${GEN_PACKAGE}/asciidoc/
+       cd build-$(GEN_PACKAGE) && dpkg-buildpackage -rfakeroot -b -us -uc
+       lintian ${GEN_DEB}
+
+.PHONY: doc-deb
+doc-deb: $(DOC_DEB)
+$(DOC_DEB): index.html $(API_VIEWER_SOURCES) verify-images
+       $(call prepare_build,$(DOC_PACKAGE))
+       sed -i -e '/^Build-Depends/{s/$$/, $(DOC_BUILDDEPS)/}' build-$(DOC_PACKAGE)/debian/control
+       # install files for pmgdocs package
+       install -dm755 build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}
+       install -dm755 build-$(DOC_PACKAGE)/usr/share/doc/${DOC_PACKAGE}
+       install -m 0644 index.html ${INDEX_INCLUDES} build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}
+       # install screenshot images
+       install -dm755 build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}/images/screenshot
+       install -m 0644 images/screenshot/*.png build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}/images/screenshot
+       # install api doc viewer
+       install -dm755 build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}/api-viewer
+       install -m 0644 ${API_VIEWER_SOURCES} build-$(DOC_PACKAGE)/usr/share/${DOC_PACKAGE}/api-viewer
+       cd build-$(DOC_PACKAGE) && dpkg-buildpackage -rfakeroot -b -us -uc
+       lintian ${DOC_DEB}
+
+.PHONY: upload
+upload: ${GEN_DEB} ${DOC_DEB}
+       tar cf - ${GEN_DEB} ${DOC_DEB} | ssh repoman@repo.proxmox.com upload-pmg
+
+.PHONY: update
+update: clean
+       find . -regex '.*-\(opts\|synopsis\)\.adoc' -exec rm -f \{\} \;
+       rm -f api-viewer/apidata.js
+       make all
+
+clean:
+       find . -name '*~' -exec rm {} ';'
+       rm -rf *.html *.pdf *.epub *.tmp *.1 *.5 *.8
+       rm -f *.deb *.changes *.buildinfo
+       rm -f api-viewer/apidoc.js chapter-*.html *-plain.html chapter-*.html pmg-admin-guide.chunked asciidoc-pmg link-refs.json .asciidoc-pmg-tmp_* 
+       rm -rf .pmg-doc-depends 
+       rm -f pmg-doc-generator.mk chapter-index-table.adoc man1-index-table.adoc man5-index-table.adoc man8-index-table.adoc pmg-admin-guide-docinfo.xml
+       rm -rf build-*
diff --git a/api-viewer/PMGAPI.js b/api-viewer/PMGAPI.js
new file mode 100644 (file)
index 0000000..d42da60
--- /dev/null
@@ -0,0 +1,284 @@
+// avoid errors when running without development tools
+if (!Ext.isDefined(Ext.global.console)) {   
+    var console = { 
+        dir: function() {}, 
+        log: function() {} 
+    };
+}
+
+Ext.onReady(function() {
+
+    Ext.define('pmg-param-schema', {
+        extend: 'Ext.data.Model',
+        fields:  [ 
+           'name', 'type', 'typetext', 'description', 'verbose_description',
+           'enum', 'minimum', 'maximum', 'minLength', 'maxLength',
+           'pattern', 'title', 'requires', 'format', 'default',
+           'disallow', 'extends', 'links',
+           {
+               name: 'optional',
+               type: 'boolean'
+           }
+       ]
+    });
+
+    var store = Ext.create('Ext.data.TreeStore', {
+       model: Ext.define('pmg-api-doc', {
+            extend: 'Ext.data.Model',
+            fields:  [ 
+               'path', 'info', 'text',
+           ]
+       }),
+        proxy: {
+            type: 'memory',
+            data: pmgapi
+        },
+        sorters: [{
+            property: 'leaf',
+            direction: 'ASC'
+        }, {
+            property: 'text',
+            direction: 'ASC'
+        }]
+    });
+    
+    var render_description = function(value, metaData, record) {
+       var pdef = record.data;
+
+       value = pdef.verbose_description || value;
+
+       // TODO: try to render asciidoc correctly
+
+       metaData.style = 'white-space:pre-wrap;'
+
+       return Ext.htmlEncode(value);
+    };
+
+    var render_type = function(value, metaData, record) {
+       var pdef = record.data;
+
+       return pdef['enum'] ? 'enum' : (pdef.type || 'string');
+    };
+
+    var render_format = function(value, metaData, record) {
+       var pdef = record.data;
+
+       metaData.style = 'white-space:normal;'
+
+       if (pdef.typetext)
+           return Ext.htmlEncode(pdef.typetext);
+
+       if (pdef['enum'])
+           return pdef['enum'].join(' | ');
+
+       if (pdef.format) 
+           return pdef.format;
+
+       if (pdef.pattern) 
+           return Ext.htmlEncode(pdef.pattern);
+
+       return '';
+    };
+
+    var render_docu = function(data) {
+       var md = data.info;
+
+       // console.dir(data);
+
+       var items = [];
+
+       var clicmdhash = {
+           GET: 'get',
+           POST: 'create',
+           PUT: 'set',
+           DELETE: 'delete'
+       };
+
+       Ext.Array.each(['GET', 'POST', 'PUT', 'DELETE'], function(method) {
+           var info = md[method];
+           if (info) {
+
+               var usage = "";
+
+               usage += "<table><tr><td>HTTP:&nbsp;&nbsp;&nbsp;</td><td>" + method + " /api2/json" + data.path + "</td></tr><tr><td>&nbsp</td></tr>";
+               usage += "<tr><td>CLI:</td><td>pmgsh " + clicmdhash[method] + " " + data.path + "</td></tr></table>";
+
+               var sections = [
+                   {
+                       title: 'Description',
+                       html: Ext.htmlEncode(info.description),
+                       bodyPadding: 10
+                   },
+                   {
+                       title: 'Usage',
+                       html: usage,
+                       bodyPadding: 10
+                   }
+               ];
+
+               if (info.parameters && info.parameters.properties) {
+
+                   var pstore = Ext.create('Ext.data.Store', {
+                       model: 'pmg-param-schema',
+                       proxy: {
+                           type: 'memory'
+                       },
+                       groupField: 'optional',
+                       sorters: [
+                           {
+                               property: 'name',
+                               direction: 'ASC'
+                           }
+                       ]
+                   });
+
+                   Ext.Object.each(info.parameters.properties, function(name, pdef) {
+                       pdef.name = name;
+                       pstore.add(pdef);
+                   });
+
+                   pstore.sort();
+
+                   var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
+                       enableGroupingMenu: false,
+                       groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Required</tpl>'
+                   });
+
+                   sections.push({
+                       xtype: 'gridpanel',
+                       title: 'Parameters',
+                       features: [groupingFeature],
+                       store: pstore,
+                       viewConfig: {
+                           trackOver: false,
+                           stripeRows: true
+                       },
+                       columns: [
+                           { 
+                               header: 'Name',
+                               dataIndex: 'name'
+                           },
+                           { 
+                               header: 'Type',
+                               dataIndex: 'type',
+                               renderer: render_type,
+                           },
+                           { 
+                               header: 'Format',
+                               dataIndex: 'type',
+                               renderer: render_format,
+                               flex: 1
+                           },
+                           { 
+                               header: 'Description',
+                               dataIndex: 'description',
+                               renderer: render_description,
+                               flex: 2
+                           }
+                       ]
+                   });
+
+               }
+
+               if (info.returns) {
+
+                   var rtype = info.returns.type;
+                   if (!rtype && info.returns.items)
+                       rtype = 'array';
+                   if (!rtype)
+                       rtype = 'object';
+
+                   sections.push({
+                       title: 'Returns: ' + rtype
+                   });
+               }
+
+               var permhtml = '';
+               if (!info.permissions) {
+                   permhtml = "Root only.";
+               } else {
+                   if (info.permissions.description) {
+                       permhtml += "<div style='white-space:pre-wrap;padding-bottom:10px;'>" +
+                           Ext.htmlEncode(info.permissions.description) + "</div>";
+                   }
+
+                   if (info.permissions.user) {
+                       if (!info.permissions.description) {
+                           if (info.permissions.user === 'world') {
+                               permhtml += "Accessible without any authententification.";
+                           } else if (info.permissions.user === 'all') {
+                               permhtml += "Accessible by all authententicated users.";
+                           } else {
+                               permhtml += 'Onyl accessible by user "' + 
+                                   info.permissions.user + '"';
+                           }
+                       }
+                   } else if (info.permissions.check) {
+                       permhtml += "<pre>Check: " + 
+                           Ext.htmlEncode(Ext.JSON.encode(info.permissions.check))  + "</pre>";
+                   } else {
+                       permhtml += "Unknown systax!";
+                   }
+               }
+
+               sections.push({
+                   title: 'Required permissions',
+                   bodyPadding: 10,
+                   html: permhtml
+               });
+    
+  
+               items.push({
+                   title: method,
+                   autoScroll: true,
+                   defaults: {
+                       border: false
+                   },
+                   items: sections
+               });
+           }
+       });
+
+       var ct = Ext.getCmp('docview');
+       ct.setTitle("Path: " + data.path);
+       ct.removeAll(true);
+       ct.add(items);
+       ct.setActiveTab(0);
+    };
+
+    var tree = Ext.create('Ext.tree.Panel', {
+        title: 'Resource Tree',
+        store: store,
+       width: 200,
+        region: 'west',
+        split: true,
+        margins: '5 0 5 5',
+        rootVisible: false,
+       listeners: {
+           selectionchange: function(v, selections) {
+               if (!selections[0])
+                   return;
+               var rec = selections[0];
+               render_docu(rec.data);
+           }
+       }
+    });
+
+    Ext.create('Ext.container.Viewport', {
+       layout: 'border',
+       renderTo: Ext.getBody(),
+       items: [
+           tree,
+           {
+               xtype: 'tabpanel',
+               title: 'Documentation',
+               id: 'docview',
+               region: 'center',
+               margins: '5 5 5 0',
+               layout: 'fit',
+               items: []
+           }
+       ]
+    });
+
+});
diff --git a/api-viewer/apidata.js b/api-viewer/apidata.js
new file mode 100644 (file)
index 0000000..d92378b
--- /dev/null
@@ -0,0 +1,2803 @@
+var pmgapi = [
+   {
+      "children" : [
+         {
+            "children" : [
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Get list of rules.",
+                        "method" : "GET",
+                        "name" : "list_rules",
+                        "parameters" : {
+                           "additionalProperties" : 0
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ruledb/rules",
+                  "text" : "rules"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Get list of 'action' objects.",
+                        "method" : "GET",
+                        "name" : "list_actions",
+                        "parameters" : {
+                           "additionalProperties" : 0
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ruledb/actions",
+                  "text" : "actions"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Get list of 'what' objects.",
+                        "method" : "GET",
+                        "name" : "list_what_object",
+                        "parameters" : {
+                           "additionalProperties" : 0
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ruledb/what",
+                  "text" : "what"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Get list of 'when' objects.",
+                        "method" : "GET",
+                        "name" : "list_when_object",
+                        "parameters" : {
+                           "additionalProperties" : 0
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ruledb/when",
+                  "text" : "when"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Get list of 'who' objects.",
+                        "method" : "GET",
+                        "name" : "list_who_object",
+                        "parameters" : {
+                           "additionalProperties" : 0
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ruledb/who",
+                  "text" : "who"
+               }
+            ],
+            "info" : {
+               "GET" : {
+                  "description" : "Directory index.",
+                  "method" : "GET",
+                  "name" : "index",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "returns" : {
+                     "items" : {
+                        "properties" : {},
+                        "type" : "object"
+                     },
+                     "links" : [
+                        {
+                           "href" : "{name}",
+                           "rel" : "child"
+                        }
+                     ],
+                     "type" : "array"
+                  }
+               }
+            },
+            "leaf" : 0,
+            "path" : "/config/ruledb",
+            "text" : "ruledb"
+         },
+         {
+            "children" : [
+               {
+                  "info" : {
+                     "DELETE" : {
+                        "description" : "Delete an LDAP server entry.",
+                        "method" : "DELETE",
+                        "name" : "delete",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "section" : {
+                                 "description" : "Secion ID.",
+                                 "format" : "pve-configid",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     },
+                     "GET" : {
+                        "description" : "Get LDAP server configuration.",
+                        "method" : "GET",
+                        "name" : "read",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "section" : {
+                                 "description" : "Secion ID.",
+                                 "format" : "pve-configid",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {}
+                     },
+                     "PUT" : {
+                        "description" : "Update LDAP server settings.",
+                        "method" : "PUT",
+                        "name" : "update",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "accountattr" : {
+                                 "default" : "sAMAccountName",
+                                 "description" : "Account attribute name name.",
+                                 "optional" : 1,
+                                 "pattern" : "[a-zA-Z0-9]+",
+                                 "type" : "string"
+                              },
+                              "basedn" : {
+                                 "description" : "Base domain name.",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "binddn" : {
+                                 "description" : "Bind domain name.",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "bindpw" : {
+                                 "description" : "Bind password.",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "delete" : {
+                                 "description" : "A list of settings you want to delete.",
+                                 "format" : "pve-configid-list",
+                                 "maxLength" : 4096,
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "digest" : {
+                                 "description" : "Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.",
+                                 "maxLength" : 40,
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "filter" : {
+                                 "description" : "LDAP filter.",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "groupbasedn" : {
+                                 "description" : "Base domain name for groups.",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "mailattr" : {
+                                 "default" : "mail, userPrincipalName, proxyAddresses, othermailbox",
+                                 "description" : "List of mail attribute names.",
+                                 "format" : "string-list",
+                                 "optional" : 1,
+                                 "pattern" : "[a-zA-Z0-9]+",
+                                 "type" : "string"
+                              },
+                              "mode" : {
+                                 "default" : "ldap",
+                                 "description" : "LDAP protocol mode ('ldap' or 'ldaps').",
+                                 "enum" : [
+                                    "ldap",
+                                    "ldaps"
+                                 ],
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "port" : {
+                                 "description" : "Specify the port to connect to.",
+                                 "maximum" : 65535,
+                                 "minimum" : 1,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (1 - 65535)"
+                              },
+                              "section" : {
+                                 "description" : "Secion ID.",
+                                 "format" : "pve-configid",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "server1" : {
+                                 "description" : "Server address.",
+                                 "format" : "address",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "server2" : {
+                                 "description" : "Fallback server address. Userd when the first server is not available.",
+                                 "format" : "address",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           },
+                           "type" : "object"
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/ldap/{section}",
+                  "text" : "{section}"
+               }
+            ],
+            "info" : {
+               "GET" : {
+                  "description" : "LDAP server list.",
+                  "method" : "GET",
+                  "name" : "index",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "items" : {
+                        "properties" : {
+                           "mode" : {
+                              "type" : "string"
+                           },
+                           "section" : {
+                              "type" : "string"
+                           },
+                           "server1" : {
+                              "type" : "string"
+                           }
+                        },
+                        "type" : "object"
+                     },
+                     "links" : [
+                        {
+                           "href" : "{section}",
+                           "rel" : "child"
+                        }
+                     ],
+                     "type" : "array"
+                  }
+               },
+               "POST" : {
+                  "description" : "Add LDAP server.",
+                  "method" : "POST",
+                  "name" : "create",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "accountattr" : {
+                           "default" : "sAMAccountName",
+                           "description" : "Account attribute name name.",
+                           "optional" : 1,
+                           "pattern" : "[a-zA-Z0-9]+",
+                           "type" : "string"
+                        },
+                        "basedn" : {
+                           "description" : "Base domain name.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "binddn" : {
+                           "description" : "Bind domain name.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "bindpw" : {
+                           "description" : "Bind password.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "filter" : {
+                           "description" : "LDAP filter.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "groupbasedn" : {
+                           "description" : "Base domain name for groups.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "mailattr" : {
+                           "default" : "mail, userPrincipalName, proxyAddresses, othermailbox",
+                           "description" : "List of mail attribute names.",
+                           "format" : "string-list",
+                           "optional" : 1,
+                           "pattern" : "[a-zA-Z0-9]+",
+                           "type" : "string"
+                        },
+                        "mode" : {
+                           "default" : "ldap",
+                           "description" : "LDAP protocol mode ('ldap' or 'ldaps').",
+                           "enum" : [
+                              "ldap",
+                              "ldaps"
+                           ],
+                           "optional" : 1,
+                           "type" : "string"
+                        },
+                        "port" : {
+                           "description" : "Specify the port to connect to.",
+                           "maximum" : 65535,
+                           "minimum" : 1,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1 - 65535)"
+                        },
+                        "section" : {
+                           "description" : "Secion ID.",
+                           "format" : "pve-configid",
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "server1" : {
+                           "description" : "Server address.",
+                           "format" : "address",
+                           "optional" : 0,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "server2" : {
+                           "description" : "Fallback server address. Userd when the first server is not available.",
+                           "format" : "address",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     },
+                     "type" : "object"
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 0,
+            "path" : "/config/ldap",
+            "text" : "ldap"
+         },
+         {
+            "children" : [
+               {
+                  "info" : {
+                     "DELETE" : {
+                        "description" : "Delete a relay domain",
+                        "method" : "DELETE",
+                        "name" : "delete",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "domain" : {
+                                 "description" : "Domain name.",
+                                 "format" : "dns-name",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "master",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/config/domains/{domain}",
+                  "text" : "{domain}"
+               }
+            ],
+            "info" : {
+               "GET" : {
+                  "description" : "List relay domains.",
+                  "method" : "GET",
+                  "name" : "index",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "proxyto" : "master",
+                  "returns" : {
+                     "items" : {
+                        "properties" : {
+                           "domain" : {
+                              "type" : "string"
+                           }
+                        },
+                        "type" : "object"
+                     },
+                     "links" : [
+                        {
+                           "href" : "{section}",
+                           "rel" : "child"
+                        }
+                     ],
+                     "type" : "array"
+                  }
+               },
+               "POST" : {
+                  "description" : "Add relay domain.",
+                  "method" : "POST",
+                  "name" : "create",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "domain" : {
+                           "description" : "Domain name.",
+                           "format" : "dns-name",
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     }
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 0,
+            "path" : "/config/domains",
+            "text" : "domains"
+         },
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Cluster node index.",
+                  "method" : "GET",
+                  "name" : "index",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "returns" : {
+                     "items" : {
+                        "properties" : {
+                           "cid" : {
+                              "type" : "integer"
+                           }
+                        },
+                        "type" : "object"
+                     },
+                     "links" : [
+                        {
+                           "href" : "{cid}",
+                           "rel" : "child"
+                        }
+                     ],
+                     "type" : "array"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/config/cluster",
+            "text" : "cluster"
+         },
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Read admin configuration properties.",
+                  "method" : "GET",
+                  "name" : "read_admin_section",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "object"
+                  }
+               },
+               "PUT" : {
+                  "description" : "Update admin configuration properties.",
+                  "method" : "PUT",
+                  "name" : "update_admin_section",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "dailyreport" : {
+                           "default" : 1,
+                           "description" : "Send daily reports.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "delete" : {
+                           "description" : "A list of settings you want to delete.",
+                           "format" : "pve-configid-list",
+                           "maxLength" : 4096,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "demo" : {
+                           "default" : 0,
+                           "description" : "Demo mode - do not start SMTP filter.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "digest" : {
+                           "description" : "Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.",
+                           "maxLength" : 40,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "proxypassword" : {
+                           "description" : "HTTP proxy password.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "proxyport" : {
+                           "default" : 8080,
+                           "description" : "HTTP proxy port.",
+                           "minimum" : 1,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1 - N)"
+                        },
+                        "proxyserver" : {
+                           "description" : "HTTP proxy server address.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "proxyuser" : {
+                           "description" : "HTTP proxy user name.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     },
+                     "type" : "object"
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/config/admin",
+            "text" : "admin"
+         },
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Read clamav configuration properties.",
+                  "method" : "GET",
+                  "name" : "read_clamav_section",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "object"
+                  }
+               },
+               "PUT" : {
+                  "description" : "Update clamav configuration properties.",
+                  "method" : "PUT",
+                  "name" : "update_clamav_section",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "archiveblockencrypted" : {
+                           "default" : 0,
+                           "description" : "Wether to block encrypted archives. Mark encrypted archives as viruses.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "archivemaxfiles" : {
+                           "default" : 1000,
+                           "description" : "Number of files to be scanned within an archive, a document, or any other kind of container. Warning: disabling this limit or setting it too high may result in severe damage to the system.",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "archivemaxrec" : {
+                           "default" : 5,
+                           "description" : "Nested archives are scanned recursively, e.g. if a ZIP archive contains a TAR  file,  all files within it will also be scanned. This options specifies how deeply the process should be continued. Warning: setting this limit too high may result in severe damage to the system.",
+                           "minimum" : 1,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1 - N)"
+                        },
+                        "archivemaxsize" : {
+                           "default" : 25000000,
+                           "description" : "Files larger than this limit won't be scanned.",
+                           "minimum" : 1000000,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1000000 - N)"
+                        },
+                        "dbmirror" : {
+                           "default" : "database.clamav.net",
+                           "description" : "ClamAV database mirror server.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "delete" : {
+                           "description" : "A list of settings you want to delete.",
+                           "format" : "pve-configid-list",
+                           "maxLength" : 4096,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "digest" : {
+                           "description" : "Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.",
+                           "maxLength" : 40,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "maxcccount" : {
+                           "default" : 0,
+                           "description" : "This option sets the lowest number of Credit Card or Social Security numbers found in a file to generate a detect.",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "maxscansize" : {
+                           "default" : 100000000,
+                           "description" : "Sets the maximum amount of data to be scanned for each input file.",
+                           "minimum" : 1000000,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1000000 - N)"
+                        }
+                     },
+                     "type" : "object"
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/config/clamav",
+            "text" : "clamav"
+         },
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Read mail configuration properties.",
+                  "method" : "GET",
+                  "name" : "read_mail_section",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "object"
+                  }
+               },
+               "PUT" : {
+                  "description" : "Update mail configuration properties.",
+                  "method" : "PUT",
+                  "name" : "update_mail_section",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "banner" : {
+                           "default" : "ESMTP Proxmox",
+                           "description" : "ESMTP banner.",
+                           "maxLength" : 1024,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "conn_count_limit" : {
+                           "default" : 50,
+                           "description" : "How many simultaneous connections any client is allowed to make to this service. To disable this feature, specify a limit of 0.",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "conn_rate_limit" : {
+                           "default" : 0,
+                           "description" : "The maximal number of connection attempts any client is allowed to make to this service per minute. To disable this feature, specify a limit of 0.",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "delete" : {
+                           "description" : "A list of settings you want to delete.",
+                           "format" : "pve-configid-list",
+                           "maxLength" : 4096,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "digest" : {
+                           "description" : "Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.",
+                           "maxLength" : 40,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "dnsbl_sites" : {
+                           "description" : "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "dwarning" : {
+                           "default" : 4,
+                           "description" : "SMTP delay warning time (in hours).",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "greylist" : {
+                           "default" : 1,
+                           "description" : "Use Greylisting.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "helotests" : {
+                           "default" : 0,
+                           "description" : "Use SMTP HELO tests.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "hide_received" : {
+                           "default" : 0,
+                           "description" : "Hide received header in outgoing mails.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "max_filters" : {
+                           "default" : 15,
+                           "description" : "Maximum number of pmg-smtp-filter processes.",
+                           "maximum" : 40,
+                           "minimum" : 3,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (3 - 40)"
+                        },
+                        "max_policy" : {
+                           "default" : 5,
+                           "description" : "Maximum number of pmgpolicy processes.",
+                           "maximum" : 10,
+                           "minimum" : 2,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (2 - 10)"
+                        },
+                        "max_smtpd_in" : {
+                           "default" : 99,
+                           "description" : "Maximum number of SMTP daemon processes (in).",
+                           "maximum" : 100,
+                           "minimum" : 3,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (3 - 100)"
+                        },
+                        "max_smtpd_out" : {
+                           "default" : 99,
+                           "description" : "Maximum number of SMTP daemon processes (out).",
+                           "maximum" : 100,
+                           "minimum" : 3,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (3 - 100)"
+                        },
+                        "maxsize" : {
+                           "default" : 10485760,
+                           "description" : "Maximum email size. Larger mails are rejected.",
+                           "minimum" : 1024,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1024 - N)"
+                        },
+                        "message_rate_limit" : {
+                           "default" : 0,
+                           "description" : "The maximal number of message delivery requests that any client is allowed to make to this service per minute.To disable this feature, specify a limit of 0.",
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - N)"
+                        },
+                        "rejectunknown" : {
+                           "default" : 0,
+                           "description" : "Reject unknown clients.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "rejectunknownsender" : {
+                           "default" : 0,
+                           "description" : "Reject unknown senders.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "relay" : {
+                           "description" : "The default mail delivery transport (incoming mails).",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "relaynomx" : {
+                           "default" : 0,
+                           "description" : "Disable MX lookups for default relay.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "relayport" : {
+                           "default" : 25,
+                           "description" : "SMTP port number for relay host.",
+                           "maximum" : 65535,
+                           "minimum" : 1,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (1 - 65535)"
+                        },
+                        "spf" : {
+                           "default" : 1,
+                           "description" : "Use Sender Policy Framework.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "tls" : {
+                           "default" : 0,
+                           "description" : "Use TLS.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "use_rbl" : {
+                           "default" : 1,
+                           "description" : "Use Realtime Blacklists.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "verifyreceivers" : {
+                           "default" : 0,
+                           "description" : "Enable receiver verification. The value (if greater than 0) spefifies the numerical reply code when the Postfix SMTP server rejects a recipient address (450 or 550).",
+                           "maximum" : 599,
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - 599)"
+                        }
+                     },
+                     "type" : "object"
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/config/mail",
+            "text" : "mail"
+         },
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Read spam configuration properties.",
+                  "method" : "GET",
+                  "name" : "read_spam_section",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "object"
+                  }
+               },
+               "PUT" : {
+                  "description" : "Update spam configuration properties.",
+                  "method" : "PUT",
+                  "name" : "update_spam_section",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "bounce_score" : {
+                           "default" : 0,
+                           "description" : "Additional score for bounce mails.",
+                           "maximum" : 1000,
+                           "minimum" : 0,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (0 - 1000)"
+                        },
+                        "delete" : {
+                           "description" : "A list of settings you want to delete.",
+                           "format" : "pve-configid-list",
+                           "maxLength" : 4096,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "digest" : {
+                           "description" : "Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.",
+                           "maxLength" : 40,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "languages" : {
+                           "default" : "all",
+                           "description" : "This option is used to specify which languages are considered OK for incoming mail.",
+                           "optional" : 1,
+                           "pattern" : "(all|([a-z][a-z])+( ([a-z][a-z])+)*)",
+                           "type" : "string"
+                        },
+                        "maxspamsize" : {
+                           "default" : 204800,
+                           "description" : "Maximum size of spam messages in bytes.",
+                           "minimum" : 64,
+                           "optional" : 1,
+                           "type" : "integer",
+                           "typetext" : "<integer> (64 - N)"
+                        },
+                        "rbl_checks" : {
+                           "default" : 1,
+                           "description" : "Enable real time blacklists (RBL) checks.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "use_awl" : {
+                           "default" : 1,
+                           "description" : "Use the Auto-Whitelist plugin.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "use_bayes" : {
+                           "default" : 1,
+                           "description" : "Whether to use the naive-Bayesian-style classifier.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "use_ocr" : {
+                           "default" : 0,
+                           "description" : "Enable OCR to scan pictures.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "use_razor" : {
+                           "default" : 1,
+                           "description" : "Whether to use Razor2, if it is available.",
+                           "optional" : 1,
+                           "type" : "boolean",
+                           "typetext" : "<boolean>"
+                        },
+                        "wl_bounce_relays" : {
+                           "description" : "Whitelist legitimate bounce relays.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     },
+                     "type" : "object"
+                  },
+                  "protected" : 1,
+                  "proxyto" : "master",
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/config/spam",
+            "text" : "spam"
+         }
+      ],
+      "info" : {
+         "GET" : {
+            "description" : "Directory index.",
+            "method" : "GET",
+            "name" : "index",
+            "parameters" : {
+               "additionalProperties" : 0
+            },
+            "returns" : {
+               "items" : {
+                  "properties" : {
+                     "section" : {
+                        "type" : "string"
+                     }
+                  },
+                  "type" : "object"
+               },
+               "links" : [
+                  {
+                     "href" : "{section}",
+                     "rel" : "child"
+                  }
+               ],
+               "type" : "array"
+            }
+         }
+      },
+      "leaf" : 0,
+      "path" : "/config",
+      "text" : "config"
+   },
+   {
+      "children" : [
+         {
+            "children" : [
+               {
+                  "children" : [
+                     {
+                        "info" : {
+                           "DELETE" : {
+                              "description" : "Delete network device configuration",
+                              "method" : "DELETE",
+                              "name" : "delete_network",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "iface" : {
+                                       "description" : "Network interface name.",
+                                       "format" : "pve-iface",
+                                       "maxLength" : 20,
+                                       "minLength" : 2,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    }
+                                 }
+                              },
+                              "protected" : 1,
+                              "proxyto" : "node",
+                              "returns" : {
+                                 "type" : "null"
+                              }
+                           },
+                           "GET" : {
+                              "description" : "Read network device configuration",
+                              "method" : "GET",
+                              "name" : "network_config",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "iface" : {
+                                       "description" : "Network interface name.",
+                                       "format" : "pve-iface",
+                                       "maxLength" : 20,
+                                       "minLength" : 2,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    }
+                                 }
+                              },
+                              "proxyto" : "node",
+                              "returns" : {
+                                 "properties" : {
+                                    "method" : {
+                                       "type" : "string"
+                                    },
+                                    "type" : {
+                                       "type" : "string"
+                                    }
+                                 },
+                                 "type" : "object"
+                              }
+                           },
+                           "PUT" : {
+                              "description" : "Update network device configuration",
+                              "method" : "PUT",
+                              "name" : "update_network",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "address" : {
+                                       "description" : "IP address.",
+                                       "format" : "ipv4",
+                                       "optional" : 1,
+                                       "requires" : "netmask",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "address6" : {
+                                       "description" : "IP address.",
+                                       "format" : "ipv6",
+                                       "optional" : 1,
+                                       "requires" : "netmask6",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "autostart" : {
+                                       "description" : "Automatically start interface on boot.",
+                                       "optional" : 1,
+                                       "type" : "boolean",
+                                       "typetext" : "<boolean>"
+                                    },
+                                    "bond_mode" : {
+                                       "description" : "Bonding mode.",
+                                       "enum" : [
+                                          "balance-rr",
+                                          "active-backup",
+                                          "balance-xor",
+                                          "broadcast",
+                                          "802.3ad",
+                                          "balance-tlb",
+                                          "balance-alb",
+                                          "balance-slb",
+                                          "lacp-balance-slb",
+                                          "lacp-balance-tcp"
+                                       ],
+                                       "optional" : 1,
+                                       "type" : "string"
+                                    },
+                                    "bond_xmit_hash_policy" : {
+                                       "description" : "Selects the transmit hash policy to use for slave selection in balance-xor and 802.3ad modes.",
+                                       "enum" : [
+                                          "layer2",
+                                          "layer2+3",
+                                          "layer3+4"
+                                       ],
+                                       "optional" : 1,
+                                       "type" : "string"
+                                    },
+                                    "bridge_ports" : {
+                                       "description" : "Specify the iterfaces you want to add to your bridge.",
+                                       "format" : "pve-iface-list",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "bridge_vlan_aware" : {
+                                       "description" : "Enable bridge vlan support.",
+                                       "optional" : 1,
+                                       "type" : "boolean",
+                                       "typetext" : "<boolean>"
+                                    },
+                                    "comments" : {
+                                       "description" : "Comments",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "comments6" : {
+                                       "description" : "Comments",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "delete" : {
+                                       "description" : "A list of settings you want to delete.",
+                                       "format" : "pve-configid-list",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "gateway" : {
+                                       "description" : "Default gateway address.",
+                                       "format" : "ipv4",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "gateway6" : {
+                                       "description" : "Default ipv6 gateway address.",
+                                       "format" : "ipv6",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "iface" : {
+                                       "description" : "Network interface name.",
+                                       "format" : "pve-iface",
+                                       "maxLength" : 20,
+                                       "minLength" : 2,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "netmask" : {
+                                       "description" : "Network mask.",
+                                       "format" : "ipv4mask",
+                                       "optional" : 1,
+                                       "requires" : "address",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "netmask6" : {
+                                       "description" : "Network mask.",
+                                       "maximum" : 128,
+                                       "minimum" : 0,
+                                       "optional" : 1,
+                                       "requires" : "address6",
+                                       "type" : "integer",
+                                       "typetext" : "<integer> (0 - 128)"
+                                    },
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "ovs_bonds" : {
+                                       "description" : "Specify the interfaces used by the bonding device.",
+                                       "format" : "pve-iface-list",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "ovs_bridge" : {
+                                       "description" : "The OVS bridge associated with a OVS port. This is required when you create an OVS port.",
+                                       "format" : "pve-iface",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "ovs_options" : {
+                                       "description" : "OVS interface options.",
+                                       "maxLength" : 1024,
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "ovs_ports" : {
+                                       "description" : "Specify the iterfaces you want to add to your bridge.",
+                                       "format" : "pve-iface-list",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "ovs_tag" : {
+                                       "description" : "Specify a VLan tag (used by OVSPort, OVSIntPort, OVSBond)",
+                                       "maximum" : 4094,
+                                       "minimum" : 1,
+                                       "optional" : 1,
+                                       "type" : "integer",
+                                       "typetext" : "<integer> (1 - 4094)"
+                                    },
+                                    "slaves" : {
+                                       "description" : "Specify the interfaces used by the bonding device.",
+                                       "format" : "pve-iface-list",
+                                       "optional" : 1,
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "type" : {
+                                       "description" : "Network interface type",
+                                       "enum" : [
+                                          "bridge",
+                                          "bond",
+                                          "eth",
+                                          "alias",
+                                          "vlan",
+                                          "OVSBridge",
+                                          "OVSBond",
+                                          "OVSPort",
+                                          "OVSIntPort",
+                                          "unknown"
+                                       ],
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "protected" : 1,
+                              "proxyto" : "node",
+                              "returns" : {
+                                 "type" : "null"
+                              }
+                           }
+                        },
+                        "leaf" : 1,
+                        "path" : "/nodes/{node}/network/{iface}",
+                        "text" : "{iface}"
+                     }
+                  ],
+                  "info" : {
+                     "DELETE" : {
+                        "description" : "Revert network configuration changes.",
+                        "method" : "DELETE",
+                        "name" : "revert_network_changes",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     },
+                     "GET" : {
+                        "description" : "List available networks",
+                        "method" : "GET",
+                        "name" : "index",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "type" : {
+                                 "description" : "Only list specific interface types.",
+                                 "enum" : [
+                                    "bridge",
+                                    "bond",
+                                    "eth",
+                                    "alias",
+                                    "vlan",
+                                    "OVSBridge",
+                                    "OVSBond",
+                                    "OVSPort",
+                                    "OVSIntPort",
+                                    "any_bridge"
+                                 ],
+                                 "optional" : 1,
+                                 "type" : "string"
+                              }
+                           }
+                        },
+                        "proxyto" : "node",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "links" : [
+                              {
+                                 "href" : "{iface}",
+                                 "rel" : "child"
+                              }
+                           ],
+                           "type" : "array"
+                        }
+                     },
+                     "POST" : {
+                        "description" : "Create network device configuration",
+                        "method" : "POST",
+                        "name" : "create_network",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "address" : {
+                                 "description" : "IP address.",
+                                 "format" : "ipv4",
+                                 "optional" : 1,
+                                 "requires" : "netmask",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "address6" : {
+                                 "description" : "IP address.",
+                                 "format" : "ipv6",
+                                 "optional" : 1,
+                                 "requires" : "netmask6",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "autostart" : {
+                                 "description" : "Automatically start interface on boot.",
+                                 "optional" : 1,
+                                 "type" : "boolean",
+                                 "typetext" : "<boolean>"
+                              },
+                              "bond_mode" : {
+                                 "description" : "Bonding mode.",
+                                 "enum" : [
+                                    "balance-rr",
+                                    "active-backup",
+                                    "balance-xor",
+                                    "broadcast",
+                                    "802.3ad",
+                                    "balance-tlb",
+                                    "balance-alb",
+                                    "balance-slb",
+                                    "lacp-balance-slb",
+                                    "lacp-balance-tcp"
+                                 ],
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "bond_xmit_hash_policy" : {
+                                 "description" : "Selects the transmit hash policy to use for slave selection in balance-xor and 802.3ad modes.",
+                                 "enum" : [
+                                    "layer2",
+                                    "layer2+3",
+                                    "layer3+4"
+                                 ],
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "bridge_ports" : {
+                                 "description" : "Specify the iterfaces you want to add to your bridge.",
+                                 "format" : "pve-iface-list",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "bridge_vlan_aware" : {
+                                 "description" : "Enable bridge vlan support.",
+                                 "optional" : 1,
+                                 "type" : "boolean",
+                                 "typetext" : "<boolean>"
+                              },
+                              "comments" : {
+                                 "description" : "Comments",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "comments6" : {
+                                 "description" : "Comments",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "gateway" : {
+                                 "description" : "Default gateway address.",
+                                 "format" : "ipv4",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "gateway6" : {
+                                 "description" : "Default ipv6 gateway address.",
+                                 "format" : "ipv6",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "iface" : {
+                                 "description" : "Network interface name.",
+                                 "format" : "pve-iface",
+                                 "maxLength" : 20,
+                                 "minLength" : 2,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "netmask" : {
+                                 "description" : "Network mask.",
+                                 "format" : "ipv4mask",
+                                 "optional" : 1,
+                                 "requires" : "address",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "netmask6" : {
+                                 "description" : "Network mask.",
+                                 "maximum" : 128,
+                                 "minimum" : 0,
+                                 "optional" : 1,
+                                 "requires" : "address6",
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (0 - 128)"
+                              },
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "ovs_bonds" : {
+                                 "description" : "Specify the interfaces used by the bonding device.",
+                                 "format" : "pve-iface-list",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "ovs_bridge" : {
+                                 "description" : "The OVS bridge associated with a OVS port. This is required when you create an OVS port.",
+                                 "format" : "pve-iface",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "ovs_options" : {
+                                 "description" : "OVS interface options.",
+                                 "maxLength" : 1024,
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "ovs_ports" : {
+                                 "description" : "Specify the iterfaces you want to add to your bridge.",
+                                 "format" : "pve-iface-list",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "ovs_tag" : {
+                                 "description" : "Specify a VLan tag (used by OVSPort, OVSIntPort, OVSBond)",
+                                 "maximum" : 4094,
+                                 "minimum" : 1,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (1 - 4094)"
+                              },
+                              "slaves" : {
+                                 "description" : "Specify the interfaces used by the bonding device.",
+                                 "format" : "pve-iface-list",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "type" : {
+                                 "description" : "Network interface type",
+                                 "enum" : [
+                                    "bridge",
+                                    "bond",
+                                    "eth",
+                                    "alias",
+                                    "vlan",
+                                    "OVSBridge",
+                                    "OVSBond",
+                                    "OVSPort",
+                                    "OVSIntPort",
+                                    "unknown"
+                                 ],
+                                 "type" : "string"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     }
+                  },
+                  "leaf" : 0,
+                  "path" : "/nodes/{node}/network",
+                  "text" : "network"
+               },
+               {
+                  "children" : [
+                     {
+                        "children" : [
+                           {
+                              "info" : {
+                                 "GET" : {
+                                    "description" : "Read task log.",
+                                    "method" : "GET",
+                                    "name" : "read_task_log",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "limit" : {
+                                             "minimum" : 0,
+                                             "optional" : 1,
+                                             "type" : "integer",
+                                             "typetext" : "<integer> (0 - N)"
+                                          },
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "start" : {
+                                             "minimum" : 0,
+                                             "optional" : 1,
+                                             "type" : "integer",
+                                             "typetext" : "<integer> (0 - N)"
+                                          },
+                                          "upid" : {
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "items" : {
+                                          "properties" : {
+                                             "n" : {
+                                                "description" : "Line number",
+                                                "type" : "integer"
+                                             },
+                                             "t" : {
+                                                "description" : "Line text",
+                                                "type" : "string"
+                                             }
+                                          },
+                                          "type" : "object"
+                                       },
+                                       "type" : "array"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/tasks/{upid}/log",
+                              "text" : "log"
+                           },
+                           {
+                              "info" : {
+                                 "GET" : {
+                                    "description" : "Read task status.",
+                                    "method" : "GET",
+                                    "name" : "read_task_status",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "upid" : {
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "properties" : {
+                                          "pid" : {
+                                             "type" : "integer"
+                                          },
+                                          "status" : {
+                                             "enum" : [
+                                                "running",
+                                                "stopped"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       },
+                                       "type" : "object"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/tasks/{upid}/status",
+                              "text" : "status"
+                           }
+                        ],
+                        "info" : {
+                           "DELETE" : {
+                              "description" : "Stop a task.",
+                              "method" : "DELETE",
+                              "name" : "stop_task",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "upid" : {
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    }
+                                 }
+                              },
+                              "protected" : 1,
+                              "proxyto" : "node",
+                              "returns" : {
+                                 "type" : "null"
+                              }
+                           },
+                           "GET" : {
+                              "description" : "",
+                              "method" : "GET",
+                              "name" : "upid_index",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "upid" : {
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    }
+                                 }
+                              },
+                              "returns" : {
+                                 "items" : {
+                                    "properties" : {},
+                                    "type" : "object"
+                                 },
+                                 "links" : [
+                                    {
+                                       "href" : "{name}",
+                                       "rel" : "child"
+                                    }
+                                 ],
+                                 "type" : "array"
+                              }
+                           }
+                        },
+                        "leaf" : 0,
+                        "path" : "/nodes/{node}/tasks/{upid}",
+                        "text" : "{upid}"
+                     }
+                  ],
+                  "info" : {
+                     "GET" : {
+                        "description" : "Read task list for one node (finished tasks).",
+                        "method" : "GET",
+                        "name" : "node_tasks",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "errors" : {
+                                 "optional" : 1,
+                                 "type" : "boolean",
+                                 "typetext" : "<boolean>"
+                              },
+                              "limit" : {
+                                 "minimum" : 0,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (0 - N)"
+                              },
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "start" : {
+                                 "minimum" : 0,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (0 - N)"
+                              },
+                              "userfilter" : {
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "proxyto" : "node",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {
+                                 "upid" : {
+                                    "type" : "string"
+                                 }
+                              },
+                              "type" : "object"
+                           },
+                           "links" : [
+                              {
+                                 "href" : "{upid}",
+                                 "rel" : "child"
+                              }
+                           ],
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 0,
+                  "path" : "/nodes/{node}/tasks",
+                  "text" : "tasks"
+               },
+               {
+                  "children" : [
+                     {
+                        "children" : [
+                           {
+                              "info" : {
+                                 "GET" : {
+                                    "description" : "Read service properties",
+                                    "method" : "GET",
+                                    "name" : "service_state",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "service" : {
+                                             "description" : "Service ID",
+                                             "enum" : [
+                                                "pmgproxy",
+                                                "pmgdaemon",
+                                                "pmg-smtp-filter",
+                                                "sshd",
+                                                "syslog",
+                                                "cron",
+                                                "postfix",
+                                                "systemd-timesyncd"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "properties" : {},
+                                       "type" : "object"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/services/{service}/state",
+                              "text" : "state"
+                           },
+                           {
+                              "info" : {
+                                 "POST" : {
+                                    "description" : "Start service.",
+                                    "method" : "POST",
+                                    "name" : "service_start",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "service" : {
+                                             "description" : "Service ID",
+                                             "enum" : [
+                                                "pmgproxy",
+                                                "pmgdaemon",
+                                                "pmg-smtp-filter",
+                                                "sshd",
+                                                "syslog",
+                                                "cron",
+                                                "postfix",
+                                                "systemd-timesyncd"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/services/{service}/start",
+                              "text" : "start"
+                           },
+                           {
+                              "info" : {
+                                 "POST" : {
+                                    "description" : "Stop service.",
+                                    "method" : "POST",
+                                    "name" : "service_stop",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "service" : {
+                                             "description" : "Service ID",
+                                             "enum" : [
+                                                "pmgproxy",
+                                                "pmgdaemon",
+                                                "pmg-smtp-filter",
+                                                "sshd",
+                                                "syslog",
+                                                "cron",
+                                                "postfix",
+                                                "systemd-timesyncd"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/services/{service}/stop",
+                              "text" : "stop"
+                           },
+                           {
+                              "info" : {
+                                 "POST" : {
+                                    "description" : "Restart service.",
+                                    "method" : "POST",
+                                    "name" : "service_restart",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "service" : {
+                                             "description" : "Service ID",
+                                             "enum" : [
+                                                "pmgproxy",
+                                                "pmgdaemon",
+                                                "pmg-smtp-filter",
+                                                "sshd",
+                                                "syslog",
+                                                "cron",
+                                                "postfix",
+                                                "systemd-timesyncd"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/services/{service}/restart",
+                              "text" : "restart"
+                           },
+                           {
+                              "info" : {
+                                 "POST" : {
+                                    "description" : "Reload service.",
+                                    "method" : "POST",
+                                    "name" : "service_reload",
+                                    "parameters" : {
+                                       "additionalProperties" : 0,
+                                       "properties" : {
+                                          "node" : {
+                                             "description" : "The cluster node name.",
+                                             "format" : "pve-node",
+                                             "type" : "string",
+                                             "typetext" : "<string>"
+                                          },
+                                          "service" : {
+                                             "description" : "Service ID",
+                                             "enum" : [
+                                                "pmgproxy",
+                                                "pmgdaemon",
+                                                "pmg-smtp-filter",
+                                                "sshd",
+                                                "syslog",
+                                                "cron",
+                                                "postfix",
+                                                "systemd-timesyncd"
+                                             ],
+                                             "type" : "string"
+                                          }
+                                       }
+                                    },
+                                    "protected" : 1,
+                                    "proxyto" : "node",
+                                    "returns" : {
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "leaf" : 1,
+                              "path" : "/nodes/{node}/services/{service}/reload",
+                              "text" : "reload"
+                           }
+                        ],
+                        "info" : {
+                           "GET" : {
+                              "description" : "Directory index",
+                              "method" : "GET",
+                              "name" : "srvcmdidx",
+                              "parameters" : {
+                                 "additionalProperties" : 0,
+                                 "properties" : {
+                                    "node" : {
+                                       "description" : "The cluster node name.",
+                                       "format" : "pve-node",
+                                       "type" : "string",
+                                       "typetext" : "<string>"
+                                    },
+                                    "service" : {
+                                       "description" : "Service ID",
+                                       "enum" : [
+                                          "pmgproxy",
+                                          "pmgdaemon",
+                                          "pmg-smtp-filter",
+                                          "sshd",
+                                          "syslog",
+                                          "cron",
+                                          "postfix",
+                                          "systemd-timesyncd"
+                                       ],
+                                       "type" : "string"
+                                    }
+                                 }
+                              },
+                              "returns" : {
+                                 "items" : {
+                                    "properties" : {
+                                       "subdir" : {
+                                          "type" : "string"
+                                       }
+                                    },
+                                    "type" : "object"
+                                 },
+                                 "links" : [
+                                    {
+                                       "href" : "{subdir}",
+                                       "rel" : "child"
+                                    }
+                                 ],
+                                 "type" : "array"
+                              }
+                           }
+                        },
+                        "leaf" : 0,
+                        "path" : "/nodes/{node}/services/{service}",
+                        "text" : "{service}"
+                     }
+                  ],
+                  "info" : {
+                     "GET" : {
+                        "description" : "Service list.",
+                        "method" : "GET",
+                        "name" : "index",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {},
+                              "type" : "object"
+                           },
+                           "links" : [
+                              {
+                                 "href" : "{service}",
+                                 "rel" : "child"
+                              }
+                           ],
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 0,
+                  "path" : "/nodes/{node}/services",
+                  "text" : "services"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Read system log",
+                        "method" : "GET",
+                        "name" : "syslog",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "limit" : {
+                                 "minimum" : 0,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (0 - N)"
+                              },
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "since" : {
+                                 "description" : "Display all log since this date-time string.",
+                                 "optional" : 1,
+                                 "pattern" : "^\\d{4}-\\d{2}-\\d{2}( \\d{2}:\\d{2}(:\\d{2})?)?$",
+                                 "type" : "string"
+                              },
+                              "start" : {
+                                 "minimum" : 0,
+                                 "optional" : 1,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (0 - N)"
+                              },
+                              "until" : {
+                                 "description" : "Display all log until this date-time string.",
+                                 "optional" : 1,
+                                 "pattern" : "^\\d{4}-\\d{2}-\\d{2}( \\d{2}:\\d{2}(:\\d{2})?)?$",
+                                 "type" : "string"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "items" : {
+                              "properties" : {
+                                 "n" : {
+                                    "description" : "Line number",
+                                    "type" : "integer"
+                                 },
+                                 "t" : {
+                                    "description" : "Line text",
+                                    "type" : "string"
+                                 }
+                              },
+                              "type" : "object"
+                           },
+                           "type" : "array"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/nodes/{node}/syslog",
+                  "text" : "syslog"
+               },
+               {
+                  "info" : {
+                     "POST" : {
+                        "description" : "Creates a VNC Shell proxy.",
+                        "method" : "POST",
+                        "name" : "vncshell",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "websocket" : {
+                                 "default" : 1,
+                                 "description" : "use websocket instead of standard vnc.",
+                                 "optional" : 1,
+                                 "type" : "boolean",
+                                 "typetext" : "<boolean>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "returns" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "port" : {
+                                 "type" : "integer"
+                              },
+                              "ticket" : {
+                                 "type" : "string"
+                              },
+                              "upid" : {
+                                 "type" : "string"
+                              },
+                              "user" : {
+                                 "type" : "string"
+                              }
+                           }
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/nodes/{node}/vncshell",
+                  "text" : "vncshell"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Opens a weksocket for VNC traffic.",
+                        "method" : "GET",
+                        "name" : "vncwebsocket",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "port" : {
+                                 "description" : "Port number returned by previous vncproxy call.",
+                                 "maximum" : 5999,
+                                 "minimum" : 5900,
+                                 "type" : "integer",
+                                 "typetext" : "<integer> (5900 - 5999)"
+                              },
+                              "vncticket" : {
+                                 "description" : "Ticket from previous call to vncproxy.",
+                                 "maxLength" : 512,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "returns" : {
+                           "properties" : {
+                              "port" : {
+                                 "type" : "string"
+                              }
+                           },
+                           "type" : "object"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/nodes/{node}/vncwebsocket",
+                  "text" : "vncwebsocket"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Read DNS settings.",
+                        "method" : "GET",
+                        "name" : "dns",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "proxyto" : "node",
+                        "returns" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "dns1" : {
+                                 "description" : "First name server IP address.",
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "dns2" : {
+                                 "description" : "Second name server IP address.",
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "dns3" : {
+                                 "description" : "Third name server IP address.",
+                                 "optional" : 1,
+                                 "type" : "string"
+                              },
+                              "search" : {
+                                 "description" : "Search domain for host-name lookup.",
+                                 "optional" : 1,
+                                 "type" : "string"
+                              }
+                           },
+                           "type" : "object"
+                        }
+                     },
+                     "PUT" : {
+                        "description" : "Write DNS settings.",
+                        "method" : "PUT",
+                        "name" : "update_dns",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "dns1" : {
+                                 "description" : "First name server IP address.",
+                                 "format" : "ip",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "dns2" : {
+                                 "description" : "Second name server IP address.",
+                                 "format" : "ip",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "dns3" : {
+                                 "description" : "Third name server IP address.",
+                                 "format" : "ip",
+                                 "optional" : 1,
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "search" : {
+                                 "description" : "Search domain for host-name lookup.",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/nodes/{node}/dns",
+                  "text" : "dns"
+               },
+               {
+                  "info" : {
+                     "GET" : {
+                        "description" : "Read server time and time zone settings.",
+                        "method" : "GET",
+                        "name" : "time",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "proxyto" : "node",
+                        "returns" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "localtime" : {
+                                 "description" : "Seconds since 1970-01-01 00:00:00 (local time)",
+                                 "minimum" : 1297163644,
+                                 "type" : "integer"
+                              },
+                              "time" : {
+                                 "description" : "Seconds since 1970-01-01 00:00:00 UTC.",
+                                 "minimum" : 1297163644,
+                                 "type" : "integer"
+                              },
+                              "timezone" : {
+                                 "description" : "Time zone",
+                                 "type" : "string"
+                              }
+                           },
+                           "type" : "object"
+                        }
+                     },
+                     "PUT" : {
+                        "description" : "Set time zone.",
+                        "method" : "PUT",
+                        "name" : "set_timezone",
+                        "parameters" : {
+                           "additionalProperties" : 0,
+                           "properties" : {
+                              "node" : {
+                                 "description" : "The cluster node name.",
+                                 "format" : "pve-node",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              },
+                              "timezone" : {
+                                 "description" : "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
+                                 "type" : "string",
+                                 "typetext" : "<string>"
+                              }
+                           }
+                        },
+                        "protected" : 1,
+                        "proxyto" : "node",
+                        "returns" : {
+                           "type" : "null"
+                        }
+                     }
+                  },
+                  "leaf" : 1,
+                  "path" : "/nodes/{node}/time",
+                  "text" : "time"
+               }
+            ],
+            "info" : {
+               "GET" : {
+                  "description" : "Node index.",
+                  "method" : "GET",
+                  "name" : "index",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "node" : {
+                           "description" : "The cluster node name.",
+                           "format" : "pve-node",
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     }
+                  },
+                  "permissions" : {
+                     "user" : "all"
+                  },
+                  "returns" : {
+                     "items" : {
+                        "properties" : {},
+                        "type" : "object"
+                     },
+                     "links" : [
+                        {
+                           "href" : "{name}",
+                           "rel" : "child"
+                        }
+                     ],
+                     "type" : "array"
+                  }
+               }
+            },
+            "leaf" : 0,
+            "path" : "/nodes/{node}",
+            "text" : "{node}"
+         }
+      ],
+      "info" : {
+         "GET" : {
+            "description" : "Cluster node index.",
+            "method" : "GET",
+            "name" : "index",
+            "parameters" : {
+               "additionalProperties" : 0
+            },
+            "permissions" : {
+               "user" : "all"
+            },
+            "returns" : {
+               "items" : {
+                  "properties" : {},
+                  "type" : "object"
+               },
+               "links" : [
+                  {
+                     "href" : "{node}",
+                     "rel" : "child"
+                  }
+               ],
+               "type" : "array"
+            }
+         }
+      },
+      "leaf" : 0,
+      "path" : "/nodes",
+      "text" : "nodes"
+   },
+   {
+      "children" : [
+         {
+            "info" : {
+               "GET" : {
+                  "description" : "Dummy. Useful for formaters which want to priovde a login page.",
+                  "method" : "GET",
+                  "name" : "get_ticket",
+                  "parameters" : {
+                     "additionalProperties" : 0
+                  },
+                  "permissions" : {
+                     "user" : "world"
+                  },
+                  "returns" : {
+                     "type" : "null"
+                  }
+               },
+               "POST" : {
+                  "description" : "Create or verify authentication ticket.",
+                  "method" : "POST",
+                  "name" : "create_ticket",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "otp" : {
+                           "description" : "One-time password for Two-factor authentication.",
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "password" : {
+                           "description" : "The secret password. This can also be a valid ticket.",
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "realm" : {
+                           "description" : "You can optionally pass the realm using this parameter. Normally the realm is simply added to the username <username>@<relam>.",
+                           "format" : "pmg-realm",
+                           "maxLength" : 32,
+                           "optional" : 1,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "username" : {
+                           "description" : "User name",
+                           "maxLength" : 64,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     }
+                  },
+                  "permissions" : {
+                     "description" : "You need to pass valid credientials.",
+                     "user" : "world"
+                  },
+                  "protected" : 1,
+                  "returns" : {
+                     "properties" : {
+                        "CSRFPreventionToken" : {
+                           "optional" : 1,
+                           "type" : "string"
+                        },
+                        "ticket" : {
+                           "optional" : 1,
+                           "type" : "string"
+                        },
+                        "username" : {
+                           "type" : "string"
+                        }
+                     },
+                     "type" : "object"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/access/ticket",
+            "text" : "ticket"
+         },
+         {
+            "info" : {
+               "PUT" : {
+                  "description" : "Change user password.",
+                  "method" : "PUT",
+                  "name" : "change_passsword",
+                  "parameters" : {
+                     "additionalProperties" : 0,
+                     "properties" : {
+                        "password" : {
+                           "description" : "The new password.",
+                           "maxLength" : 64,
+                           "minLength" : 5,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        },
+                        "userid" : {
+                           "description" : "User ID",
+                           "format" : "pmg-userid",
+                           "maxLength" : 64,
+                           "type" : "string",
+                           "typetext" : "<string>"
+                        }
+                     }
+                  },
+                  "protected" : 1,
+                  "returns" : {
+                     "type" : "null"
+                  }
+               }
+            },
+            "leaf" : 1,
+            "path" : "/access/password",
+            "text" : "password"
+         }
+      ],
+      "info" : {
+         "GET" : {
+            "description" : "Directory index.",
+            "method" : "GET",
+            "name" : "index",
+            "parameters" : {
+               "additionalProperties" : 0
+            },
+            "permissions" : {
+               "user" : "all"
+            },
+            "returns" : {
+               "items" : {
+                  "properties" : {
+                     "subdir" : {
+                        "type" : "string"
+                     }
+                  },
+                  "type" : "object"
+               },
+               "links" : [
+                  {
+                     "href" : "{subdir}",
+                     "rel" : "child"
+                  }
+               ],
+               "type" : "array"
+            }
+         }
+      },
+      "leaf" : 0,
+      "path" : "/access",
+      "text" : "access"
+   },
+   {
+      "info" : {
+         "GET" : {
+            "description" : "API version details.",
+            "method" : "GET",
+            "name" : "version",
+            "parameters" : {
+               "additionalProperties" : 0
+            },
+            "permissions" : {
+               "user" : "all"
+            },
+            "returns" : {
+               "properties" : {
+                  "release" : {
+                     "type" : "string"
+                  },
+                  "repoid" : {
+                     "type" : "string"
+                  },
+                  "version" : {
+                     "type" : "string"
+                  }
+               },
+               "type" : "object"
+            }
+         }
+      },
+      "leaf" : 1,
+      "path" : "/version",
+      "text" : "version"
+   }
+]
+;
+
diff --git a/api-viewer/index.html b/api-viewer/index.html
new file mode 100644 (file)
index 0000000..97ed69e
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <title>Proxmox VE API Documentation</title>
+
+    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/extjs/6.0.1/classic/theme-crisp-touch/resources/theme-crisp-touch-all.css">
+   <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/extjs/6.0.1/ext-all-debug.js"></script>   
+    <script type="text/javascript" src="apidoc.js"></script>
+</head>
+<body></body>
+</html>
diff --git a/asciidoc-pmg.in b/asciidoc-pmg.in
new file mode 100644 (file)
index 0000000..e473d8b
--- /dev/null
@@ -0,0 +1,625 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Getopt::Long;
+use File::Path;
+use File::Basename;
+use IO::File;
+use Cwd;
+
+use JSON;
+
+my $verbose;
+my $keep_artifacts;
+
+my $release = '@RELEASE@';
+
+my $clicmd = shift or
+    die "no command specified\n";
+
+my $data_str = "";
+while (<main::DATA>) { $data_str .= $_; }
+
+my $fileinfo = decode_json($data_str);
+
+my $tmpprefix = '.asciidoc-pmg-tmp'.$$.'_';
+
+my $adoc_source_dir = "/usr/share/pmg-doc-generator";
+
+# inside pmg-docs source dir?
+if (-f "asciidoc-pmg.in" && -f "pmg-admin-guide.adoc") {
+    $adoc_source_dir = getcwd();
+}
+
+my $prepared_files = {};
+
+my $man_target = 'man';
+my $env_stack = [];
+my $env_skip = 0;
+
+my $online_help_links = {
+    'pmg_service_daemons' => {
+       link => '/pmg-docs/index.html#_service_daemons',
+       title => 'Service Daemons',
+    },
+    'pmg_documentation_index' => {
+       link => '/pmg-docs/index.html',
+       title => 'Proxmox VE Documentation Index',
+    },
+    'pmg_admin_guide' => {
+       link => '/pmg-docs/pmg-admin-guide.html',
+       title => 'Proxmox VE Administration Guide',
+    },
+};
+
+sub debug {
+    my $msg = shift;
+
+    return if !$verbose;
+
+    print STDERR "asciidoc-pmg: $msg\n";
+}
+
+sub push_environment {
+    my ($env, $skip) = @_;
+
+    $skip = 1 if $env_skip;
+    $skip = 0 if !defined($skip);
+
+    push @$env_stack, [$env, $skip];
+
+    $env_skip = $skip;
+}
+
+sub pop_environment {
+    my ($env) = @_;
+
+    my $last_stack_entry = pop @$env_stack;
+    die "unable to pop env '$env'" if !defined($last_stack_entry);
+
+    my ($last_env, $skip) = @$last_stack_entry;
+    die "environment missmatch (${last_env} != $env)\n" if $last_env ne $env;
+
+    if (!scalar(@$env_stack)) {
+       $env_skip = 0;
+    } else {
+       my (undef, $skip) = @{$env_stack->[-1]};
+       $env_skip = $skip;
+    }
+}
+
+my $files_for_cleanup = [];
+
+sub cleanup {
+
+    return if $keep_artifacts;
+
+    foreach my $file (@$files_for_cleanup) {
+       unlink $file;
+    }
+}
+
+sub replace_wiki_xref {
+    my ($blockid, $text) = @_;
+
+    my $link = $fileinfo->{blockid_target}->{wiki}->{$blockid};
+    my $reftext = $fileinfo->{reftext}->{wiki}->{$blockid};
+
+    die "unable to resolve wiki link (xref:$blockid)\n"
+       if !defined($link);
+
+    $text = $reftext if !length($text);
+
+    die "xref: no text for wiki link '$blockid'\n" if !$text;
+
+    return "$link\[$text\]";
+}
+
+sub replace_default_xref {
+    my ($blockid, $text) = @_;
+
+    my $link = $fileinfo->{blockid_target}->{default}->{$blockid};
+    my $reftext = $fileinfo->{reftext}->{default}->{$blockid};
+
+    die "unable to resolve chapter link (xref:$blockid)\n"
+       if !defined($link);
+
+    $text = $reftext if !length($text);
+
+    die "xref: no text for chapter link '$blockid'\n" if !$text;
+
+    return "$link\[$text\]";
+}
+
+sub replace_man_xref {
+    my ($blockid, $text) = @_;
+
+    my $link = $fileinfo->{blockid_target}->{manvolnum}->{$blockid};
+    my $reftext = $fileinfo->{reftext}->{manvolnum}->{$blockid};
+
+    die "unable to resolve man page link (xref:$blockid)\n"
+       if !defined($link);
+
+    $text = $reftext if !length($text);
+
+    die "xref: no text for man page link '$blockid'\n" if !$text;
+
+    my $section = $fileinfo->{mansection}->{manvolnum}->{$link};
+    die "link target is not a manual page" if !defined($section);
+
+
+    if ($man_target eq 'html') {
+       my $target = $link;
+       $target =~ s/\.adoc//;
+       $target .= ".$section";
+       return "link:${target}.html#${blockid}\[$text\]";
+    } elsif ($man_target eq 'man') {
+       my $command = $link;
+       $command =~ s/\.adoc//;
+       return "\*${text}\* (man \*${command}\*($section))";
+    } else {
+       die "internal error"
+    }
+}
+
+sub replace_xref {
+    my ($env, $blockid, $text) = @_;
+
+    if ($env eq 'wiki') {
+       return replace_wiki_xref($blockid, $text);
+    } elsif ($env eq 'manvolnum') {
+       if (($man_target eq 'man') || ($man_target eq 'html')) {
+           return replace_man_xref($blockid, $text);
+       } elsif ($man_target eq 'wiki') {
+           return replace_wiki_xref($blockid, $text);
+       } else {
+           die "internal error"
+       }
+    } elsif ($env eq 'default') {
+       return replace_default_xref($blockid, $text);
+    } else {
+       die "internal error";
+    }
+}
+
+sub prepare_adoc_file {
+    my ($target_env, $filename, $attributes) = @_;
+
+    return $prepared_files->{$filename} if defined($prepared_files->{$filename});
+
+    debug("prepare $filename");
+
+    my $dirname = dirname($filename);
+    my $basename = basename($filename);
+
+    my $outfilename = "$dirname/${tmpprefix}$basename";
+
+    $prepared_files->{$filename} = $outfilename;
+
+    my $fh = IO::File->new("$filename", "r") or
+       die "unable to open file '$filename' - $!\n";
+
+    my $outfh = IO::File->new("$outfilename", "w") or
+       die "unable to open temporary file '$outfilename'\n";
+
+    push @$files_for_cleanup, $outfilename;
+
+    while (defined (my $line = <$fh>)) {
+       chomp $line;
+       if ($line =~ m/^if(n?)def::(\S+)\[(.*)\]\s*$/) {
+           my ($not, $env, $text) = ($1, $2, $3);
+           die "unsuported ifdef usage - implement me" if $text;
+
+           my $skip = !exists($attributes->{$env}) ? 1 : 0;
+           $skip = ($skip ? 0 : 1 ) if $not;
+
+           push_environment($env, $skip);
+           next;
+       } elsif ($line =~ m/^endif::(\S+)\[(.*)\]\s*$/) {
+           my ($env, $text) = ($1, $2);
+           die "unsuported ifdef usage - implement me" if $text;
+           pop_environment($env);
+           next;
+       }
+
+       next if $env_skip;
+
+       if ($line =~ m/^include::(\S+)(\[.*\]\s*)$/) {
+           my ($fn, $rest) = ($1, $2);
+           debug("include $fn");
+           my $new_fn = prepare_adoc_file($target_env, $fn, $attributes);
+
+           print $outfh "include::${new_fn}$rest\n";
+           next;
+       }
+
+       if ($line =~ m/xref:\S+?\[[^\]]*$/) {
+           die "possible xref spanning multiple lines in '$filename':\n(line $.): $line\n";
+       }
+       if ($line =~ m/<<((?!\>\>).)*$/) {
+           die "possible xref spanning multiple lines in '$filename':\n(line $.): $line\n";
+       }
+       # fix xrefs
+       $line =~ s/xref:([^\s\[\]]+)\[([^\]]*)\]/replace_xref(${target_env},$1,$2)/ge;
+
+       $line =~ s/<<([^\s,\[\]]+)(?:,(.*?))?>>/replace_xref(${target_env},$1,$2)/ge;
+
+       print $outfh $line . "\n";
+    }
+
+    return $outfilename;
+}
+
+sub compile_asciidoc {
+    my ($env) = @_;
+
+    my $outfile;
+
+    GetOptions ("outfile=s" => \$outfile,
+               "keep-artifacts" => \$keep_artifacts,
+               "verbose"   => \$verbose) or
+                   die("Error in command line arguments\n");
+
+    my $infile = shift(@ARGV) or
+       die "no input file specified\n";
+
+    scalar(@ARGV) == 0 or
+       die "too many arguments...\n";
+
+    my $outfilemap = $fileinfo->{outfile}->{$env}->{$infile} ||
+       die "no output file mapping for '$infile' ($env)";
+
+    if ($man_target eq 'html') {
+       $outfilemap .= '.html';
+    } elsif ($man_target eq 'wiki') {
+       $outfilemap .= '-plain.html';
+    }
+
+    if (defined($outfile)) {
+       die "wrong output file name '$outfile != $outfilemap' ($env)"
+           if $outfile ne $outfilemap;
+    } else {
+       $outfile = $outfilemap;
+    }
+
+    defined($fileinfo->{titles}->{$env}) ||
+       die "unknown environment '$env'";
+
+    my $title = $fileinfo->{titles}->{$env}->{$infile} or
+       die "unable to get title for '$infile'$env\n";
+
+    debug("compile $title");
+
+    my $leveloffset = 0;
+
+    my $doctype = $fileinfo->{doctype}->{$env}->{$infile};
+
+    die "unable to get document type for '$infile'\n"
+       if !defined($doctype);
+
+    $leveloffset = - $doctype;
+
+    my $date = `date`;
+    chomp $date;
+
+    my $attributes = {
+       $env => undef,
+       leveloffset => $leveloffset,
+       revnumber => $release,
+       revdate => $date,
+    };
+
+    my $mansection = $fileinfo->{mansection}->{$env}->{$infile};
+
+    if ($env eq 'wiki') {
+    } elsif ($env eq 'manvolnum') {
+       die "undefined man section" if !defined($mansection);
+       $attributes->{manvolnum} = $mansection;
+    } elsif ($env eq 'default') {
+       die "$infile: wrong doctype\n" if $doctype != 0;
+       $attributes->{toc} = undef;
+    }
+
+    if (!defined($outfile)) {
+       $outfile = $infile;
+       $outfile =~ s/\.adoc$//;
+       if ($env eq 'manvolnum') {
+           if (($man_target eq 'html') || ($man_target eq 'wiki')) {
+               $outfile .= ".$mansection.html";
+           } else {
+               $outfile .= ".$mansection";
+           }
+       } else {
+           $outfile .= ".html";
+       }
+    }
+
+    if (($env eq 'manvolnum') && ($man_target eq 'man')) {
+
+       # asciidoc /etc/asciidoc/docbook-xsl/manpage.xsl skip REFERENCES
+       # section like footnotes, so we cannot use a2x.
+       # We use xmlto instead.
+
+       my $cmd = ['asciidoc', '-dmanpage', '-bdocbook',
+                  '-f', "$adoc_source_dir/asciidoc/asciidoc-pmg.conf",
+                  '-a', 'docinfo1'];
+
+       foreach my $key (keys %$attributes) {
+           my $value = $attributes->{$key};
+           if (defined($value)) {
+               push @$cmd, '-a', "$key=$value";
+           } else {
+               push @$cmd, '-a', $key;
+           }
+       }
+
+       push @$cmd, '--verbose' if $verbose;
+
+       my $tmpxmlfile = "${outfile}.xml.tmp";
+
+       push @$cmd, '--out-file', $tmpxmlfile;
+
+       push @$files_for_cleanup, $tmpxmlfile;
+
+       my $new_infile = prepare_adoc_file($env, $infile, $attributes);
+
+       push @$cmd, $new_infile;
+
+       debug("run " . join(' ', @$cmd));
+
+       system(@$cmd) == 0 or
+           die "aciidoc error";
+
+       $cmd = ['xmlto', 'man', $tmpxmlfile];
+
+       push @$cmd, '-v' if $verbose;
+
+       debug("run " . join(' ', @$cmd));
+
+       system(@$cmd) == 0 or
+           die "xmlto error";
+
+    } else {
+
+       $attributes->{icons} = undef;
+       $attributes->{'data-uri'} = undef;
+
+       my $cmd = ['asciidoc',
+                  '-f', "$adoc_source_dir/asciidoc/asciidoc-pmg.conf",
+           ];
+
+       if (($env eq 'wiki') ||
+           (($env eq 'manvolnum') && ($man_target eq 'wiki'))) {
+
+           push @$cmd, '-b', "$adoc_source_dir/asciidoc/mediawiki";
+       } else {
+           push @$cmd, '-b', "$adoc_source_dir/asciidoc/pmg-html";
+       }
+
+       foreach my $key (keys %$attributes) {
+           my $value = $attributes->{$key};
+           if (defined($value)) {
+               push @$cmd, '-a', "$key=$value";
+           } else {
+               push @$cmd, '-a', $key;
+           }
+       }
+
+       push @$cmd, '--verbose' if $verbose;
+
+       push @$cmd, '--out-file', $outfile;
+
+       my $new_infile = prepare_adoc_file($env, $infile, $attributes);
+
+       push @$cmd, $new_infile;
+
+       debug("run " . join(' ', @$cmd));
+
+       system(@$cmd) == 0 or
+           die "aciidoc error";
+    }
+}
+
+sub get_links {
+
+    my $data = {};
+
+    foreach my $blockid (sort keys %{$fileinfo->{blockid_target}->{default}}) {
+       my $link = $fileinfo->{blockid_target}->{default}->{$blockid};
+       my $reftitle = $fileinfo->{reftitle}->{default}->{$blockid};
+       my $reftext = $fileinfo->{reftext}->{default}->{$blockid};
+       die "internal error" if $link !~ m/^link:/;
+       $link =~ s/^link://;
+
+       my $file = $fileinfo->{blockid}->{default}->{$blockid};
+       die "internal error - no filename" if ! defined($file);
+       my $title =  $fileinfo->{titles}->{default}->{$file} ||
+           die "internal error - no title";
+
+       $data->{$blockid}->{title} = $title;
+       $data->{$blockid}->{link} = $link;
+       my $subtitle = $reftitle || $reftext;
+       $data->{$blockid}->{subtitle} = $subtitle
+           if $subtitle && ($title ne $subtitle);
+    }
+
+    return $data;
+}
+
+sub scan_extjs_file {
+    my ($filename, $res_data) = @_;
+
+    my $fh = IO::File->new($filename, "r") ||
+       die "unable to open '$filename' - $!\n";
+
+    debug("scan-extjs $filename");
+
+    while(defined(my $line = <$fh>)) {
+       if ($line =~ m/\s+onlineHelp:\s*[\'\"](.*?)[\'\"]/) {
+           my $blockid = $1;
+           my $link = $fileinfo->{blockid_target}->{default}->{$blockid};
+           die "undefined blockid '$blockid' ($filename, line $.)\n"
+               if !(defined($link) || defined($online_help_links->{$blockid}));
+
+           $res_data->{$blockid} = 1;
+       }
+    }
+}
+
+if ($clicmd eq 'compile-wiki') {
+
+    eval { compile_asciidoc('wiki'); };
+    my $err = $@;
+
+    cleanup();
+
+    die $err if $err;
+
+} elsif ($clicmd eq 'compile-chapter') {
+
+    eval { compile_asciidoc('default'); };
+    my $err = $@;
+
+    cleanup();
+
+    die $err if $err;
+
+} elsif ($clicmd eq 'compile-man-html') {
+
+    $man_target = 'html';
+
+    eval { compile_asciidoc('manvolnum'); };
+    my $err = $@;
+
+    cleanup();
+
+    die $err if $err;
+
+} elsif ($clicmd eq 'compile-man-wiki') {
+
+    $man_target = 'wiki';
+
+    eval { compile_asciidoc('manvolnum'); };
+    my $err = $@;
+
+    cleanup();
+
+    die $err if $err;
+
+} elsif ($clicmd eq 'compile-man') {
+
+    eval { compile_asciidoc('manvolnum'); };
+    my $err = $@;
+
+    cleanup();
+
+    die $err if $err;
+
+} elsif ($clicmd eq 'print-links') {
+
+    my $outfile;
+
+    GetOptions("outfile=s" => \$outfile,
+              "verbose"   => \$verbose) or
+                  die("Error in command line arguments\n");
+
+    scalar(@ARGV) == 0 or
+       die "too many arguments...\n";
+
+    my $data = get_links();
+
+    my $res = to_json($data, { pretty => 1,  canonical => 1 } );
+
+    if (defined($outfile)) {
+       my $outfh = IO::File->new("$outfile", "w") or
+           die "unable to open temporary file '$outfile'\n";
+
+       print $outfh $res;
+
+    } else {
+
+       print $res;
+    }
+
+} elsif ($clicmd eq 'scan-extjs') {
+
+    GetOptions("verbose" => \$verbose) or
+       die("Error in command line arguments\n");
+
+    my $link_hash = {};
+    my $scanned_files = {};
+    while (my $filename = shift) {
+       die "got strange file name '$filename'\n"
+           if $filename !~ m/\.js$/;
+       next if $scanned_files->{$filename};
+
+       scan_extjs_file($filename, $link_hash);
+       $scanned_files->{$filename} = 1;
+    }
+
+    my $data = get_links();
+
+    my $res_data = {};
+
+    foreach my $blockid (keys %$link_hash) {
+       $res_data->{$blockid} = $data->{$blockid} || $online_help_links->{$blockid} ||
+           die "internal error - no data for '$blockid'";
+    }
+
+    my $data_str =  to_json($res_data, { pretty => 1,  canonical => 1 });
+    chomp $data_str;
+
+    print "var pmgOnlineHelpInfo = ${data_str};\n";
+
+} elsif ($clicmd eq 'chapter-table') {
+    
+    print '[width="100%",options="header"]' . "\n";
+    print "|====\n";
+    print "|Title|Link\n";
+    
+    my $filelist = $fileinfo->{outfile}->{default};
+    foreach my $sourcefile (sort keys %$filelist) {
+       my $target = $filelist->{$sourcefile};
+       next if $target eq 'pmg-admin-guide.html';
+       my $title = $fileinfo->{titles}->{default}->{$sourcefile} ||
+           die "not title for '$sourcefile'";
+       print "|$title|link:$target\[\]\n";
+    }
+    
+    print "|====\n";
+
+} elsif ($clicmd =~ m/^man([158])page-table$/) {
+    
+    my $section = $1;
+    print '[width="100%",cols="5*d",options="header"]' . "\n";
+    print "|====\n";
+    print "|Name 3+|Title|Link\n";
+    
+    my $filelist = $fileinfo->{outfile}->{manvolnum};
+    foreach my $manpage (sort keys %$filelist) {
+       next if $section ne $fileinfo->{mansection}->{manvolnum}->{$manpage};
+       my $mantitle = $fileinfo->{titles}->{manvolnum}->{$manpage} ||
+           die "not manual title for '$manpage'";
+       my $title = $fileinfo->{titles}->{default}->{$manpage} ||
+           die "not title for '$manpage'";
+
+       # hack - remove command name prefix from titles
+       $title =~ s/^[a-z]+\s*-\s*//;
+       
+       my $target = $filelist->{$manpage};
+       print "|$mantitle 3+|$title|link:$target.html\[$target\]\n";
+    }  
+    
+    print "|====\n";
+
+} else {
+
+    die "unknown command '$clicmd'\n";
+
+}
+
+
+exit 0;
+
+__END__
diff --git a/asciidoc/asciidoc-pmg.conf b/asciidoc/asciidoc-pmg.conf
new file mode 100644 (file)
index 0000000..16f7ce1
--- /dev/null
@@ -0,0 +1,15 @@
+
+[attributes]
+proxmoxGmbh=Proxmox Server Solutions Gmbh
+copyright=Proxmox Server Solutions Gmbh
+pmg=Proxmox Mail Gateway
+website=http://www.proxmox.com/
+forum-url=https://forum.proxmox.com/
+forum=https://forum.proxmox.com/[Proxmox VE Community Forum]
+manmanual=Proxmox Mail Gateway Documentation
+max-width=55em
+ifndef::docinfo1[]
+author=Proxmox Server Solutions Gmbh
+email=support@proxmox.com
+endif::docinfo1[]
+
diff --git a/asciidoc/dblatex-custom.sty b/asciidoc/dblatex-custom.sty
new file mode 100644 (file)
index 0000000..ba4a508
--- /dev/null
@@ -0,0 +1,68 @@
+%%
+%% This style is derived from the docbook one.
+%%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{asciidoc-proxmox}[2016/10/30 AsciiDoc DocBook Style]
+
+% this will set letterpaper, because docbook.sty honors page layout
+% made by geometry package
+%\usepackage[letterpaper,total={7.25in,9.25in}, top=1in]{geometry}
+%\usepackage[a4paper]{geometry}
+
+\usepackage[a4paper, left=2cm, right=1cm, top=2.5cm, bottom=2cm ]{geometry}
+
+%% Just use the original package and pass the options.
+\RequirePackageWithOptions{docbook}
+
+% Sidebar is a boxed minipage that can contain verbatim.
+% Changed shadow box to double box.
+\renewenvironment{sidebar}[1][0.95\textwidth]{
+  \hspace{0mm}\newline%
+  \noindent\begin{Sbox}\begin{minipage}{#1}%
+  \setlength\parskip{\medskipamount}%
+}{
+  \end{minipage}\end{Sbox}\doublebox{\TheSbox}%
+}
+
+% use parbox for description labels to allow line breaks
+\renewcommand\descriptionlabel[1]{
+  \parbox[t]{\linewidth}{\raggedright\bfseries #1\smallskip}}
+
+% For DocBook literallayout elements, see `./dblatex/dblatex-readme.txt`.
+\usepackage{alltt}
+
+\definecolor{proxmoxred}{RGB}{229, 112, 0}
+\definecolor{proxmoxgrey1}{RGB}{229, 229, 229}
+
+\def\drawtitlepage{
+  \AddToShipoutPicture*{
+    \put(\LenToUnit{0cm},\LenToUnit{2.5cm}){
+      {\color{proxmoxgrey1}\rule{\paperwidth}{22cm}}}
+    \put(\LenToUnit{\dimexpr(\paperwidth-11cm)},
+         \LenToUnit{\dimexpr(\paperheight-3.5cm)}){
+      \includegraphics[width=10cm]{proxmox-logo}}
+  }
+}
+
+% custom cover page
+\def\DBKcover{
+  \thispagestyle{empty}
+  \vspace*{4cm}
+  \sffamily
+  \begin{center}
+    {\Huge \scshape \color{proxmoxred}  \DBKtitle \\[0.5cm]}
+    {\Large \scshape \DBKsubtitle \\[1cm]}
+    {\includegraphics[width=132mm]{proxmox-ci-header} \\}
+  \end{center}
+  \vfill
+  \begin{flushright}
+    {\Large \sffamily
+      \DBKdate \\
+      Proxmox Server Solutions Gmbh \\
+      \color{proxmoxred} www.proxmox.com \\
+    }
+  \end{flushright}
+  \vspace*{1cm}
+  \drawtitlepage
+  \pagebreak[4]
+}
diff --git a/asciidoc/pmg-dblatex.xsl b/asciidoc/pmg-dblatex.xsl
new file mode 100644 (file)
index 0000000..76edab8
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+dblatex(1) XSL user stylesheet for asciidoc(1).
+See dblatex(1) -p option.
+
+modified for Proxmox VE documenation.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+  <!-- TOC links in the titles, and in blue. -->
+  <xsl:param name="latex.hyperparam">colorlinks,linkcolor=blue,pdfstartview=FitH</xsl:param>
+  <xsl:param name="doc.publisher.show">0</xsl:param>
+  <xsl:param name="doc.lot.show"></xsl:param>
+  <xsl:param name="term.breakline">1</xsl:param>
+  <xsl:param name="doc.collab.show">0</xsl:param>
+  <xsl:param name="doc.publisher.show">0</xsl:param>
+  <xsl:param name="doc.section.depth">2</xsl:param>
+  <xsl:param name="toc.section.depth">2</xsl:param>
+  <xsl:param name="table.in.float">0</xsl:param>
+  <xsl:param name="monoseq.hyphenation">0</xsl:param>
+  <xsl:param name="latex.output.revhistory">0</xsl:param>
+  <xsl:param name="latex.class.options">12pt</xsl:param>
+
+
+  <!-- This doesn't work, don't know why, see:
+  http://dblatex.sourceforge.net/html/manual/apas03.html
+  ./docbook-xsl/common.xsl
+  -->
+  <!--
+  <xsl:param name="doc.toc.show">
+    <xsl:choose>
+      <xsl:when test="/processing-instruction('asciidoc-toc')">
+1
+      </xsl:when>
+      <xsl:otherwise>
+0
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:param>
+  <xsl:param name="doc.lot.show">
+    <xsl:choose>
+      <xsl:when test="/book">
+figure,table,equation,example
+      </xsl:when>
+    </xsl:choose>
+  </xsl:param>
+  -->
+  <xsl:param name="doc.toc.show">1</xsl:param>
+
+  <!--
+    Override default literallayout template.
+    See `./dblatex/dblatex-readme.txt`.
+  -->
+  <xsl:template match="address|literallayout[@class!='monospaced']">
+    <xsl:text>\begin{alltt}</xsl:text>
+    <xsl:text>&#10;\normalfont{}&#10;</xsl:text>
+    <xsl:apply-templates/>
+    <xsl:text>&#10;\end{alltt}</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="processing-instruction('asciidoc-pagebreak')">
+    <!-- force hard pagebreak, varies from 0(low) to 4(high) -->
+    <xsl:text>\pagebreak[4] </xsl:text>
+    <xsl:apply-templates />
+    <xsl:text>&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="processing-instruction('asciidoc-br')">
+    <xsl:text>\newline&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="processing-instruction('asciidoc-hr')">
+    <!-- draw a 444 pt line (centered) -->
+    <xsl:text>\begin{center}&#10; </xsl:text>
+    <xsl:text>\line(1,0){444}&#10; </xsl:text>
+    <xsl:text>\end{center}&#10; </xsl:text>
+  </xsl:template>
+
+  <xsl:template match="formalpara">
+    <xsl:text>&#10;\paragraph*{</xsl:text>
+    <xsl:call-template name="normalize-scape">
+      <xsl:with-param name="string" select="title"/>
+    </xsl:call-template>
+    <xsl:text>} </xsl:text>
+    <xsl:call-template name="label.id"/>
+    <xsl:apply-templates/>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+  </xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/asciidoc/pmg-docbook.conf b/asciidoc/pmg-docbook.conf
new file mode 100644 (file)
index 0000000..044ea84
--- /dev/null
@@ -0,0 +1,810 @@
+#
+# docbook45.conf
+#
+# Asciidoc DocBook 4.5 configuration file.
+#
+# modified for Proxmox VE docs
+# - add thumbnail attribute
+
+[miscellaneous]
+outfilesuffix=.xml
+# Printable page width and units.
+# Used to calculate DocBook CALS tables absolute column and table widths.
+pagewidth=425
+pageunits=*
+
+[attributes]
+basebackend=docbook
+basebackend-docbook=
+basebackend-docbook45=
+# For backward compatibility (docbook backend was renamed to docbook45 at 8.6.2)
+backend-docbook=
+# toc and numbered are set to maintain original default behavior.
+toc=
+numbered=
+
+[replacements2]
+# Line break markup. Custom processing instruction in fo.xsl.
+(?m)^(.*)\s\+$=\1<?asciidoc-br?>
+
+[replacements]
+ifdef::asciidoc7compatible[]
+# Superscripts.
+\^(.+?)\^=<superscript>\1</superscript>
+# Subscripts.
+~(.+?)~=<subscript>\1</subscript>
+endif::asciidoc7compatible[]
+
+[ruler-blockmacro]
+# Uses custom processing instructions in fo.xsl and asciidoc-dblatex.xsl.
+<simpara><?asciidoc-hr?></simpara>
+
+[pagebreak-blockmacro]
+# Uses custom processing instructions in fo.xsl and asciidoc-dblatex.xsl.
+<simpara><?asciidoc-pagebreak?></simpara>
+
+[blockdef-pass]
+latexmath-style=template="latexmathblock",subs=()
+
+[macros]
+# math macros.
+(?su)[\\]?(?P<name>latexmath):(?P<subslist>\S*?)\[(?P<passtext>.*?)(?<!\\)\]=[]
+(?u)^(?P<name>latexmath)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#[]
+
+[latexmath-inlinemacro]
+<inlineequation>
+<alt><![CDATA[{passtext}]]></alt>
+<inlinemediaobject><textobject><phrase></phrase></textobject></inlinemediaobject>
+</inlineequation>
+
+[latexmath-blockmacro]
+<informalequation>
+<alt><![CDATA[{passtext}]]></alt>
+<mediaobject><textobject><phrase></phrase></textobject></mediaobject>
+</informalequation>
+
+[latexmathblock]
+<equation{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}><title>{title}</title>
+{title%}<informalequation{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<alt><![CDATA[|]]></alt>
+<mediaobject><textobject><phrase></phrase></textobject></mediaobject>
+{title#}</equation>
+{title%}</informalequation>
+
+[image-inlinemacro]
+<inlinemediaobject>
+  <imageobject>
+  <imagedata fileref="{imagesdir=}{imagesdir?/}{target}"{width? contentwidth="{width}"}{height? contentdepth="{height}"}{scale? scale="{scale}"}/>
+  </imageobject>
+  <textobject><phrase>{alt={target}}</phrase></textobject>
+</inlinemediaobject>
+
+[image-blockmacro]
+<figure{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}{pgwide-option? pgwide="1"}><title>{title}</title>
+{title%}<informalfigure{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{pgwide-option?<?dbfo pgwide="1"?>}
+# DocBook XSL Stylesheets custom processing instructions.
+<?dbfo keep-together="{breakable-option#auto}"?>
+<?dbfo keep-together="{unbreakable-option#always}"?>
+<mediaobject>
+  <imageobject>
+  <imagedata fileref="{imagesdir=}{imagesdir?/}{target}"{width? contentwidth="{width}"}{height? contentdepth="{height}"}{scale? scale="{scale}"}{scaledwidth? width="{scaledwidth}" scalefit="1"}{align? align="{align}"}/>
+  </imageobject>
+  <textobject><phrase>{alt={target}}</phrase></textobject>
+</mediaobject>
+{title#}</figure>
+{title%}</informalfigure>
+
+[indexterm-inlinemacro]
+# Index term.
+# Generate separate index entries for primary, secondary and tertiary
+# descriptions.
+# Primary only.
+{2%}<indexterm>
+{2%}  <primary>{1}</primary>
+{2%}</indexterm>
+# Primary and secondary.
+{2#}{3%}<indexterm>
+{2#}{3%}  <primary>{1}</primary><secondary>{2}</secondary>
+{2#}{3%}</indexterm>
+{2#}{3%}<indexterm>
+{2#}{3%}  <primary>{2}</primary>
+{2#}{3%}</indexterm>
+# Primary, secondary and tertiary.
+{3#}<indexterm>
+  <primary>{1}</primary><secondary>{2}</secondary><tertiary>{3}</tertiary>
+{3#}</indexterm>
+{3#}<indexterm>
+  <primary>{2}</primary><secondary>{3}</secondary>
+{3#}</indexterm>
+{3#}<indexterm>
+  <primary>{3}</primary>
+{3#}</indexterm>
+
+[indexterm2-inlinemacro]
+# Index term.
+# Single entry index term that is visible in the primary text flow.
+<indexterm><primary>{1}</primary></indexterm>{1}
+
+[footnote-inlinemacro]
+# Footnote.
+<footnote><simpara>{0}</simpara></footnote>
+
+[footnoteref-inlinemacro]
+# Footnote reference.
+{2#}<footnote id="{1}"><simpara>{2}</simpara></footnote>
+{2%}<footnoteref linkend="{1}" />
+
+[callout-inlinemacro]
+# Callout.
+<co id="{coid}"/>
+
+# List tags.
+[listtags-bulleted]
+list=<itemizedlist{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}{compact-option? spacing="compact"}>{unbreakable-option? <?dbfo keep-together="always"?>}{title?<title>{title}</title>}|</itemizedlist>
+item=<listitem>|</listitem>
+text=<simpara>|</simpara>
+
+[listtags-numbered]
+list=<orderedlist{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"} numeration="{style}"{compact-option? spacing="compact"}>{unbreakable-option? <?dbfo keep-together="always"?>}{title?<title>{title}</title>}{start?<?dbfo start="{start}"?><?dbhtml start="{start}"?>}|</orderedlist>
+item=<listitem>|</listitem>
+text=<simpara>|</simpara>
+
+[listtags-labeled]
+list=<variablelist{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{title?<title>{title}</title>}|</variablelist>
+entry=<varlistentry>|</varlistentry>
+label=
+term=<term>|</term>
+item=<listitem>|</listitem>
+text=<simpara>|</simpara>
+
+[listtags-horizontal]
+# Horizontal labeled list (implemented with two column table).
+# Hardwired column widths to 30%,70% because the current crop of PDF
+# generators do not auto calculate column widths.
+ list=<{title?table}{title!informaltable}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}{style? tabstyle="{style}"}{pgwide-option? pgwide="1"} frame="none" colsep="0" rowsep="0">{title?<title>{title}</title>}<tgroup cols="2"><colspec colwidth="{labelwidth=15}*"/><colspec colwidth="{itemwidth=85}*"/><tbody valign="top">|</tbody></tgroup><{title?/table}{title!/informaltable}>
+entry=<row>|</row>
+label=<entry>|</entry>
+term=<simpara>|</simpara>
+item=<entry>|</entry>
+text=<simpara>|</simpara>
+
+[listtags-callout]
+list=<calloutlist{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{title?<title>{title}</title>}|</calloutlist>
+item=<callout arearefs="{coids}">|</callout>
+text=<para>|</para>
+
+[listtags-qanda]
+list=<qandaset{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{title?<title>{title}</title>}|</qandaset>
+entry=<qandaentry>|</qandaentry>
+label=<question>|</question>
+term=<simpara>|</simpara>
+item=<answer>|</answer>
+text=<simpara>|</simpara>
+
+[listtags-bibliography]
+list=<bibliodiv{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{title?<title>{title}</title>}|</bibliodiv>
+item=<bibliomixed>|</bibliomixed>
+text=<bibliomisc>|</bibliomisc>
+
+[listtags-glossary]
+list=
+entry=<glossentry>|</glossentry>
+label=
+term=<glossterm>|</glossterm>
+item=<glossdef>|</glossdef>
+text=<simpara>|</simpara>
+
+[tags]
+# Quoted text
+emphasis=<emphasis>{1?<phrase role="{1}">}|{1?</phrase>}</emphasis>
+strong=<emphasis role="strong">{1?<phrase role="{1}">}|{1?</phrase>}</emphasis>
+monospaced=<literal>{1?<phrase role="{1}">}|{1?</phrase>}</literal>
+singlequoted={lsquo}{1?<phrase role="{1}">}|{1?</phrase>}{rsquo}
+doublequoted={ldquo}{1?<phrase role="{1}">}|{1?</phrase>}{rdquo}
+unquoted={1?<phrase role="{1}">}|{1?</phrase>}
+subscript=<subscript>{1?<phrase role="{1}">}|{1?</phrase>}</subscript>
+superscript=<superscript>{1?<phrase role="{1}">}|{1?</phrase>}</superscript>
+
+ifdef::deprecated-quotes[]
+# Override with deprecated quote attributes.
+emphasis={role?<phrase role="{role}">}<emphasis>|</emphasis>{role?</phrase>}
+strong={role?<phrase role="{role}">}<emphasis role="strong">|</emphasis>{role?</phrase>}
+monospaced={role?<phrase role="{role}">}<literal>|</literal>{role?</phrase>}
+singlequoted={role?<phrase role="{role}">}{amp}#8216;|{amp}#8217;{role?</phrase>}
+doublequoted={role?<phrase role="{role}">}{amp}#8220;|{amp}#8221;{role?</phrase>}
+unquoted={role?<phrase role="{role}">}|{role?</phrase>}
+subscript={role?<phrase role="{role}">}<subscript>|</subscript>{role?</phrase>}
+superscript={role?<phrase role="{role}">}<superscript>|</superscript>{role?</phrase>}
+endif::deprecated-quotes[]
+
+# Inline macros
+[http-inlinemacro]
+<ulink url="{name}:{target}">{0={name}:{target}}</ulink>
+[https-inlinemacro]
+<ulink url="{name}:{target}">{0={name}:{target}}</ulink>
+[ftp-inlinemacro]
+<ulink url="{name}:{target}">{0={name}:{target}}</ulink>
+[file-inlinemacro]
+<ulink url="{name}:{target}">{0={name}:{target}}</ulink>
+[irc-inlinemacro]
+<ulink url="{name}:{target}">{0={name}:{target}}</ulink>
+[mailto-inlinemacro]
+<ulink url="mailto:{target}">{0={target}}</ulink>
+[callto-inlinemacro]
+<ulink url="{name}:{target}">{0={target}}</ulink>
+[link-inlinemacro]
+<ulink url="{target}">{0={target}}</ulink>
+# anchor:id[text]
+[anchor-inlinemacro]
+<anchor id="{target}" xreflabel="{0=[{target}]}"/>
+# [[id,text]]
+[anchor2-inlinemacro]
+<anchor id="{1}" xreflabel="{2=[{1}]}"/>
+# [[[id]]]
+[anchor3-inlinemacro]
+<anchor id="{1}" xreflabel="[{1}]"/>[{1}]
+# xref:id[text]
+[xref-inlinemacro]
+<link linkend="{target}">{0}</link>
+{2%}<xref linkend="{target}"/>
+# <<id,text>>
+[xref2-inlinemacro]
+<link linkend="{1}">{2}</link>
+{2%}<xref linkend="{1}"/>
+# // comment line
+[comment-inlinemacro]
+{showcomments#}<remark>{passtext}</remark>
+
+[comment-blockmacro]
+{showcomments#}<remark>{passtext}</remark>
+
+[literal-inlinemacro]
+# Inline literal.
+<literal>{passtext}</literal>
+
+# Special word macros
+[emphasizedwords]
+<emphasis>{words}</emphasis>
+[monospacedwords]
+<literal>{words}</literal>
+[strongwords]
+<emphasis role="strong">{words}</emphasis>
+
+# Paragraph substitution.
+[paragraph]
+<formalpara{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}><title>{title}</title><para>
+{thumbnail#}<mediaobject>
+{thumbnail#}  <imageobject>
+{thumbnail#}  <imagedata fileref="images/screenshot/{thumbnail}"{width? contentwidth="{width}"}{height? contentdepth="{height}"}{scale? scale="{scale}"}{scaledwidth? width="{scaledwidth}" scalefit="1"}{align? align="{align}"}/>
+{thumbnail#}  </imageobject>
+{thumbnail#}  <textobject><phrase>{alt={thumbnail}}</phrase></textobject>
+{thumbnail#}</mediaobject>
+{title%}<simpara{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+|
+{title%}</simpara>
+{title#}</para></formalpara>
+{empty}
+
+[admonitionparagraph]
+<{name}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}><simpara>|</simpara></{name}>
+
+# Delimited blocks.
+[literalblock]
+<formalpara{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}><title>{title}</title><para>
+{title#}<literallayout class="monospaced">
+{title%}<literallayout{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"} class="monospaced">
+|
+</literallayout>
+{title#}</para></formalpara>
+
+[listingblock]
+<formalpara{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}><title>{title}</title><para>
+{title#}<screen>
+{title%}<screen{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+|
+</screen>
+{title#}</para></formalpara>
+
+[sidebarblock-open]
+<sidebar{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+
+[sidebarblock-close]
+</sidebar>
+
+[sidebarblock]
+template::[sidebarblock-open]
+|
+template::[sidebarblock-close]
+
+[sidebarparagraph]
+template::[sidebarblock-open]
+<simpara>|</simpara>
+template::[sidebarblock-close]
+
+[abstractblock-open]
+<abstract{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+
+[abstractblock-close]
+</abstract>
+
+[abstractblock]
+template::[abstractblock-open]
+|
+template::[abstractblock-close]
+
+[abstractparagraph]
+template::[abstractblock-open]
+<simpara>|</simpara>
+template::[abstractblock-close]
+
+[openblock]
+|
+
+[partintroblock-open]
+<partintro{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+
+[partintroblock-close]
+</partintro>
+
+[partintroblock]
+template::[partintroblock-open]
+|
+template::[partintroblock-close]
+
+[partintroparagraph]
+template::[partintroblock-open]
+<simpara>|</simpara>
+template::[partintroblock-close]
+
+[quote-open]
+# Common quote and verse element template.
+<blockquote{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+# Include attribution only if either {attribution} or {citetitle} is defined.
+{attribution#}<attribution>
+{attribution%}{citetitle#}<attribution>
+{attribution}
+<citetitle>{citetitle}</citetitle>
+{attribution#}</attribution>
+{attribution%}{citetitle#}</attribution>
+
+[quote-close]
+</blockquote>
+
+[quoteblock]
+template::[quote-open]
+|
+template::[quote-close]
+
+[verseblock]
+template::[quote-open]
+<literallayout>|</literallayout>
+template::[quote-close]
+
+[quoteparagraph]
+template::[quote-open]
+<simpara>|</simpara>
+template::[quote-close]
+
+[exampleblock-open]
+<{title?example}{title!informalexample}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+# DocBook XSL Stylesheets custom processing instructions.
+<?dbfo keep-together="{breakable-option#auto}"?>
+<?dbfo keep-together="{unbreakable-option#always}"?>
+<title>{title}</title>
+
+[exampleblock-close]
+</{title?example}{title!informalexample}>
+
+[exampleblock]
+template::[exampleblock-open]
+|
+template::[exampleblock-close]
+
+[exampleparagraph]
+template::[exampleblock-open]
+<simpara>|</simpara>
+template::[exampleblock-close]
+
+[admonitionblock]
+<{name}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</{name}>
+
+# Tables.
+[tabletags-default]
+colspec=<colspec colname="col_{colnumber}" colwidth="{width!{colpcwidth}*}{width?{colabswidth}{pageunits}}"/>
+bodyrow=<row>|</row>
+headdata=<entry align="{halign}" valign="{valign}"{colspan@1:: namest="col_{colstart}" nameend="col_{colend}"}{morerows@0:: morerows="{morerows}"}>|</entry>
+bodydata=<entry align="{halign}" valign="{valign}"{colspan@1:: namest="col_{colstart}" nameend="col_{colend}"}{morerows@0:: morerows="{morerows}"}>|</entry>
+paragraph=<simpara>|</simpara>
+
+[tabletags-emphasis]
+paragraph=<simpara><emphasis>|</emphasis></simpara>
+
+[tabletags-header]
+paragraph=<simpara><emphasis role="strong">|</emphasis></simpara>
+
+[tabletags-strong]
+paragraph=<simpara><emphasis role="strong">|</emphasis></simpara>
+
+[tabletags-monospaced]
+paragraph=<simpara><literal>|</literal></simpara>
+
+[tabletags-verse]
+bodydata=<entry align="{halign}" valign="{valign}"{colspan@1:: namest="col_{colstart}" nameend="col_{colend}"}{morerows@0:: morerows="{morerows}"}><literallayout>|</literallayout></entry>
+paragraph=
+
+[tabletags-literal]
+bodydata=<entry align="{halign}" valign="{valign}"{colspan@1:: namest="col_{colstart}" nameend="col_{colend}"}{morerows@0:: morerows="{morerows}"}><literallayout class="monospaced">|</literallayout></entry>
+paragraph=
+
+[tabletags-asciidoc]
+paragraph=
+
+[table]
+<{title?table}{title!informaltable}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}{pgwide-option? pgwide="1"}
+frame="{frame=all}"
+{grid%rowsep="1" colsep="1"}
+rowsep="{grid@none|cols:0:1}" colsep="{grid@none|rows:0:1}"
+>
+<title>{title}</title>
+# DocBook XSL Stylesheets custom processing instructions.
+<?dbhtml table-width="{width}"?>
+<?dbfo table-width="{width}"?>
+<?dblatex table-width="{width}"?>
+<?dbfo keep-together="{breakable-option#auto}"?>
+<?dbfo keep-together="{unbreakable-option#always}"?>
+<tgroup cols="{colcount}">
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody>
+{bodyrows}
+</tbody>
+</tgroup>
+</{title?table}{title!informaltable}>
+
+#--------------------------------------------------------------------
+# Deprecated old table definitions.
+#
+
+[old_tabledef-default]
+template=old_table
+colspec=<colspec colwidth="{colwidth}{pageunits}" align="{colalign}"/>
+bodyrow=<row>|</row>
+bodydata=<entry>|</entry>
+
+[old_table]
+<{title?table}{title!informaltable}{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"} pgwide="0"
+frame="{frame=topbot}"
+{grid%rowsep="0" colsep="0"}
+rowsep="{grid@none|cols:0:1}" colsep="{grid@none|rows:0:1}"
+>
+<title>{title}</title>
+<tgroup cols="{cols}">
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody>
+{bodyrows}
+</tbody>
+</tgroup>
+</{title?table}{title!informaltable}>
+
+# End of deprecated old table definitions.
+#--------------------------------------------------------------------
+
+# Special sections.
+[preface]
+<preface{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title=}</title>
+|
+</preface>
+
+[index]
+<index{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</index>
+
+[bibliography]
+<bibliography{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</bibliography>
+
+[glossary]
+<glossary{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</glossary>
+
+[appendix]
+<appendix{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</appendix>
+
+[floatingtitle]
+<bridgehead{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"} renderas="sect{level}">{title}</bridgehead>
+
+
+[header-declarations]
+<?xml version="1.0" encoding="{encoding}"?>
+<!DOCTYPE {doctype-article?article}{doctype-book?book}{doctype-manpage?refentry} PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+{toc#}<?asciidoc-toc?>
+{numbered#}<?asciidoc-numbered?>
+
+[+docinfo]
+{notitle%}    <title>{doctitle}</title>
+    <date>{revdate}</date>
+# To ensure valid articleinfo/bookinfo when there is no AsciiDoc header.
+    {doctitle%}{revdate%}<date>{docdate}</date>
+    {authored#}<author>
+        <firstname>{firstname}</firstname>
+        <othername>{middlename}</othername>
+        <surname>{lastname}</surname>
+        <email>{email}</email>
+    {authored#}</author>
+    <authorinitials>{authorinitials}</authorinitials>
+<revhistory><revision>{revnumber?<revnumber>{revnumber}</revnumber>}<date>{revdate}</date>{authorinitials?<authorinitials>{authorinitials}</authorinitials>}{revremark?<revremark>{revremark}</revremark>}</revision></revhistory>
+{docinfo1,docinfo2#}{include:{docdir}/docinfo.xml}
+{docinfo,docinfo2#}{include:{docdir}/{docname}-docinfo.xml}
+# DEPRECATED: Use docinfo.
+{revisionhistory#}{include:{docdir}/{docname}-revhistory.xml}
+# DEPRECATED: Use orgname in preference to companyname.
+<orgname>{companyname}</orgname>
+# DEPRECATED: Use orgname in preference to corpname.
+<orgname>{corpname}</orgname>
+<orgname>{orgname}</orgname>
+
+#-------------------------
+# article document type
+#-------------------------
+ifdef::doctype-article[]
+
+[header]
+template::[header-declarations]
+
+<article lang="{lang=en}">
+<articleinfo>
+template::[docinfo]
+</articleinfo>
+
+[footer]
+</article>
+
+[preamble]
+# Untitled elements between header and first section title.
+|
+
+[abstract]
+<abstract{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+|
+</abstract>
+
+[sect1]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+[sect2]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+[sect3]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+[sect4]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+endif::doctype-article[]
+
+#-------------------------
+# manpage document type
+#-------------------------
+ifdef::doctype-manpage[]
+
+[replacements]
+# The roff format does not substitute special characters so just print them as
+# text.
+\(C\)=(C)
+\(TM\)=(TM)
+
+[header]
+template::[header-declarations]
+<refentry lang="{lang=en}">
+<refentryinfo>
+template::[docinfo]
+</refentryinfo>
+<refmeta>
+<refentrytitle>{mantitle}</refentrytitle>
+<manvolnum>{manvolnum}</manvolnum>
+# Default source and manual to suppress DocBook XSL warnings.
+<refmiscinfo class="source">{mansource=&#160;}</refmiscinfo>
+<refmiscinfo class="manual">{manmanual=&#160;}</refmiscinfo>
+<refmiscinfo class="version">{manversion={revnumber}}</refmiscinfo>
+</refmeta>
+<refnamediv>
+    <refname>{manname1}</refname>
+    <refname>{manname2}</refname>
+    <refname>{manname3}</refname>
+    <refname>{manname4}</refname>
+    <refname>{manname5}</refname>
+    <refname>{manname6}</refname>
+    <refname>{manname7}</refname>
+    <refname>{manname8}</refname>
+    <refname>{manname9}</refname>
+    <refpurpose>{manpurpose}</refpurpose>
+</refnamediv>
+
+[footer]
+</refentry>
+
+# Section macros
+[synopsis]
+<refsynopsisdiv{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+|
+</refsynopsisdiv>
+
+[sect1]
+<refsect1{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</refsect1>
+
+[sect2]
+<refsect2{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</refsect2>
+
+[sect3]
+<refsect3{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</refsect3>
+
+endif::doctype-manpage[]
+
+#-------------------------
+# book document type
+#-------------------------
+ifdef::doctype-book[]
+
+[header]
+template::[header-declarations]
+
+<book lang="{lang=en}">
+<bookinfo>
+template::[docinfo]
+</bookinfo>
+
+[footer]
+</book>
+
+[preamble]
+# Preamble is not allowed in DocBook book so wrap it in a preface.
+<preface{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title=}</title>
+|
+</preface>
+
+[dedication]
+<dedication{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</dedication>
+
+[colophon]
+<colophon{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</colophon>
+
+[sect0]
+<part{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</part>
+
+[sect1]
+<chapter{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</chapter>
+
+[sect2]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+[sect3]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+[sect4]
+<section{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>
+<title>{title}</title>
+|
+</section>
+
+endif::doctype-book[]
+
+ifdef::sgml[]
+#
+# Optional DocBook SGML.
+#
+# Most of the differences between DocBook XML and DocBook SGML boils
+# down to the empty element syntax: SGML does not like the XML empty
+# element <.../> syntax, use <...> instead.
+#
+[miscellaneous]
+outfilesuffix=.sgml
+
+[header-declarations]
+<!DOCTYPE {doctype-article?article}{doctype-book?book}{doctype-manpage?refentry} PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+[tabledef-default]
+colspec=<colspec colwidth="{colabswidth}{pageunits}" align="{colalign}">
+
+[image-inlinemacro]
+<inlinemediaobject>
+  <imageobject>
+  <imagedata fileref="{imagesdir=}{imagesdir?/}{target}"{width? width="{width}"}{height? depth="{height}"}>
+  </imageobject>
+  <textobject><phrase>{alt={target}}</phrase></textobject>
+</inlinemediaobject>
+
+[image-blockmacro]
+<figure><title>{title}</title>
+{title%}<informalfigure>
+<mediaobject>
+  <imageobject>
+  <imagedata fileref="{imagesdir=}{imagesdir?/}{target}"{width? width="{width}"}{height? depth="{height}"}>
+  </imageobject>
+  <textobject><phrase>{alt={target}}</phrase></textobject>
+</mediaobject>
+{title#}</figure>
+{title%}</informalfigure>
+
+# Inline macros
+[xref-inlinemacro]
+<link linkend="{target}">{0}</link>
+{2%}<xref linkend="{target}">
+[xref2-inlinemacro]
+# <<id,text>>
+<link linkend="{1}">{2}</link>
+{2%}<xref linkend="{1}">
+[anchor-inlinemacro]
+<anchor id="{target}" xreflabel="{0=[{target}]}">
+[anchor2-inlinemacro]
+# [[id,text]]
+<anchor id="{1}" xreflabel="{2=[{1}]}">
+
+endif::sgml[]
diff --git a/asciidoc/pmg-html.conf b/asciidoc/pmg-html.conf
new file mode 100644 (file)
index 0000000..74e0d13
--- /dev/null
@@ -0,0 +1,719 @@
+#
+# html5.conf
+#
+# Asciidoc configuration file.
+# html5 backend.
+#
+# modified for Proxmox VE docs
+# - add thumbnail attribute
+# - s!./stylesheets!/etc/asciidoc/stylesheets!g
+# - s!./javascripts!/etc/asciidoc/javascripts!g
+
+[miscellaneous]
+outfilesuffix=.html
+
+[attributes]
+basebackend=html
+basebackend-html=
+basebackend-html5=
+
+[replacements2]
+# Line break.
+(?m)^(.*)\s\+$=\1<br>
+
+[replacements]
+ifdef::asciidoc7compatible[]
+# Superscripts.
+\^(.+?)\^=<sup>\1</sup>
+# Subscripts.
+~(.+?)~=<sub>\1</sub>
+endif::asciidoc7compatible[]
+
+[ruler-blockmacro]
+<hr>
+
+[pagebreak-blockmacro]
+<div style="page-break-after:always"></div>
+
+[blockdef-pass]
+asciimath-style=template="asciimathblock",subs=()
+latexmath-style=template="latexmathblock",subs=()
+
+[macros]
+(?u)^(?P<name>audio|video)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
+# math macros.
+# Special characters are escaped in HTML math markup.
+(?su)[\\]?(?P<name>asciimath|latexmath):(?P<subslist>\S*?)\[(?P<passtext>.*?)(?<!\\)\]=[specialcharacters]
+(?u)^(?P<name>asciimath|latexmath)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#[specialcharacters]
+
+[asciimath-inlinemacro]
+`{passtext}`
+
+[asciimath-blockmacro]
+<div class="mathblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+`{passtext}`
+</div></div>
+
+[asciimathblock]
+<div class="mathblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+`|`
+</div></div>
+
+[latexmath-inlinemacro]
+{passtext}
+
+[latexmath-blockmacro]
+<div class="mathblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+{passtext}
+</div></div>
+
+[latexmathblock]
+<div class="mathblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+|
+</div></div>
+
+[image-inlinemacro]
+<span class="image{role? {role}}">
+<a class="image" href="{link}">
+{data-uri%}<img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}{title? title="{title}"}>
+{data-uri#}<img alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}{title? title="{title}"}
+{data-uri#}{sys:"{python}" -u -c "import mimetypes,base64,sys; print 'src=\"data:'+mimetypes.guess_type(r'{target}')[0]+';base64,'; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{imagesdir=}",r"{target}")}"}">
+{link#}</a>
+</span>
+
+[image-blockmacro]
+<div class="imageblock{style? {style}}{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}{align? style="text-align:{align};"}{float? style="float:{float};"}>
+<div class="content">
+<a class="image" href="{link}">
+{data-uri%}<img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}>
+{data-uri#}<img alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}
+{data-uri#}{sys:"{python}" -u -c "import mimetypes,base64,sys; print 'src=\"data:'+mimetypes.guess_type(r'{target}')[0]+';base64,'; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{imagesdir=}",r"{target}")}"}">
+{link#}</a>
+</div>
+<div class="title">{caption={figure-caption} {counter:figure-number}. }{title}</div>
+</div>
+
+[audio-blockmacro]
+<div class="audioblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+<audio src="{imagesdir=}{imagesdir?/}{target}"{autoplay-option? autoplay}{nocontrols-option! controls}{loop-option? loop}>
+Your browser does not support the audio tag.
+</audio>
+</div></div>
+
+[video-blockmacro]
+<div class="videoblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+<video src="{imagesdir=}{imagesdir?/}{target}"{width? width="{width}"}{height? height="{height}"}{poster? poster="{poster}"}{autoplay-option? autoplay}{nocontrols-option! controls}{loop-option? loop}>
+Your browser does not support the video tag.
+</video>
+</div></div>
+
+[unfloat-blockmacro]
+<div style="clear:both;"></div>
+
+[toc-blockmacro]
+template::[toc]
+
+[indexterm-inlinemacro]
+# Index term.
+{empty}
+
+[indexterm2-inlinemacro]
+# Index term.
+# Single entry index term that is visible in the primary text flow.
+{1}
+
+[footnote-inlinemacro]
+# footnote:[<text>].
+<span class="footnote"><br>[{0}]<br></span>
+
+[footnoteref-inlinemacro]
+# footnoteref:[<id>], create reference to footnote.
+{2%}<span class="footnoteref"><br><a href="#_footnote_{1}">[{1}]</a><br></span>
+# footnoteref:[<id>,<text>], create footnote with ID.
+{2#}<span class="footnote" id="_footnote_{1}"><br>[{2}]<br></span>
+
+[callout-inlinemacro]
+ifndef::icons[]
+<b>&lt;{index}&gt;</b>
+endif::icons[]
+ifdef::icons[]
+ifndef::data-uri[]
+<img src="{icon={iconsdir}/callouts/{index}.png}" alt="{index}">
+endif::data-uri[]
+ifdef::data-uri[]
+<img alt="{index}" src="data:image/png;base64,
+{sys:"{python}" -u -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{icon={iconsdir}/callouts/{index}.png}")}"}">
+endif::data-uri[]
+endif::icons[]
+
+# Comment line macros.
+[comment-inlinemacro]
+{showcomments#}<br><span class="comment">{passtext}</span><br>
+
+[comment-blockmacro]
+{showcomments#}<p><span class="comment">{passtext}</span></p>
+
+[literal-inlinemacro]
+# Inline literal.
+<span class="monospaced">{passtext}</span>
+
+# List tags.
+[listtags-bulleted]
+list=<div class="ulist{style? {style}}{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ul>|</ul></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[listtags-numbered]
+# The start attribute is not valid XHTML 1.1 but all browsers support it.
+list=<div class="olist{style? {style}}{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol class="{style}"{start? start="{start}"}>|</ol></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[listtags-labeled]
+list=<div class="dlist{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<dl>|</dl></div>
+entry=
+label=
+term=<dt class="hdlist1{strong-option? strong}">|</dt>
+item=<dd>|</dd>
+text=<p>|</p>
+
+[listtags-horizontal]
+list=<div class="hdlist{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<table>{labelwidth?<col width="{labelwidth}%">}{itemwidth?<col width="{itemwidth}%">}|</table></div>
+label=<td class="hdlist1{strong-option? strong}">|</td>
+term=|<br>
+entry=<tr>|</tr>
+item=<td class="hdlist2">|</td>
+text=<p style="margin-top: 0;">|</p>
+
+[listtags-qanda]
+list=<div class="qlist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol>|</ol></div>
+entry=<li>|</li>
+label=
+term=<p><em>|</em></p>
+item=
+text=<p>|</p>
+
+[listtags-callout]
+ifndef::icons[]
+list=<div class="colist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol>|</ol></div>
+item=<li>|</li>
+text=<p>|</p>
+endif::icons[]
+ifdef::icons[]
+list=<div class="colist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<table>|</table></div>
+ifndef::data-uri[]
+item=<tr><td><img src="{iconsdir}/callouts/{listindex}.png" alt="{listindex}"></td><td>|</td></tr>
+endif::data-uri[]
+ifdef::data-uri[]
+item=<tr><td><img alt="{listindex}" src="data:image/png;base64, {sys:"{python}" -u -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{icon={iconsdir}/callouts/{listindex}.png}")}"}"></td><td>|</td></tr>
+endif::data-uri[]
+text=|
+endif::icons[]
+
+[listtags-glossary]
+list=<div class="dlist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<dl>|</dl></div>
+label=
+entry=
+term=<dt>|</dt>
+item=<dd>|</dd>
+text=<p>|</p>
+
+[listtags-bibliography]
+list=<div class="ulist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ul>|</ul></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[tags]
+# Quoted text.
+emphasis=<em>{1?<span class="{1}">}|{1?</span>}</em>
+strong=<strong>{1?<span class="{1}">}|{1?</span>}</strong>
+monospaced=<span class="monospaced{1? {1}}">|</span>
+singlequoted={lsquo}{1?<span class="{1}">}|{1?</span>}{rsquo}
+doublequoted={ldquo}{1?<span class="{1}">}|{1?</span>}{rdquo}
+unquoted={1?<span class="{1}">}|{1?</span>}
+superscript=<sup>{1?<span class="{1}">}|{1?</span>}</sup>
+subscript=<sub>{1?<span class="{1}">}|{1?</span>}</sub>
+
+ifdef::deprecated-quotes[]
+# Override with deprecated quote attributes.
+emphasis={role?<span class="{role}">}<em{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</em>{role?</span>}
+strong={role?<span class="{role}">}<strong{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</strong>{role?</span>}
+monospaced=<span class="monospaced{role? {role}}"{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</span>
+singlequoted={role?<span class="{role}">}{1,2,3?<span style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?">}{amp}#8216;|{amp}#8217;{1,2,3?</span>}{role?</span>}
+doublequoted={role?<span class="{role}">}{1,2,3?<span style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?">}{amp}#8220;|{amp}#8221;{1,2,3?</span>}{role?</span>}
+unquoted={role?<span class="{role}">}{1,2,3?<span style="{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}">}|{1,2,3?</span>}{role?</span>}
+superscript={role?<span class="{role}">}<sup{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</sup>{role?</span>}
+subscript={role?<span class="{role}">}<sub{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</sub>{role?</span>}
+endif::deprecated-quotes[]
+
+# Inline macros
+[http-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[https-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[ftp-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[file-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[irc-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[mailto-inlinemacro]
+<a href="mailto:{target}">{0={target}}</a>
+[link-inlinemacro]
+<a href="{target}">{0={target}}</a>
+[callto-inlinemacro]
+<a href="{name}:{target}">{0={target}}</a>
+# anchor:id[text]
+[anchor-inlinemacro]
+<a id="{target}"></a>
+# [[id,text]]
+[anchor2-inlinemacro]
+<a id="{1}"></a>
+# [[[id]]]
+[anchor3-inlinemacro]
+<a id="{1}"></a>[{1}]
+# xref:id[text]
+[xref-inlinemacro]
+<a href="#{target}">{0=[{target}]}</a>
+# <<id,text>>
+[xref2-inlinemacro]
+<a href="#{1}">{2=[{1}]}</a>
+
+# Special word substitution.
+[emphasizedwords]
+<em>{words}</em>
+[monospacedwords]
+<span class="monospaced">{words}</span>
+[strongwords]
+<strong>{words}</strong>
+
+# Paragraph substitution.
+[paragraph]
+<div class="paragraph{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+{thumbnail#}<a class="image" href="images/screenshot/{thumbnail}">
+{thumbnail#}<img src="images/screenshot/{thumbnail}" alt="{alt={thumbnail}}" width=250
+{thumbnail#}{float@left: style="padding\: 0 10px 0 0;float\:left;"}
+{thumbnail#}{float@right: style="padding\: 0 0 0 10px;float\:right;"}
+{thumbnail#}{float%} style="padding: 0 0 0 10px;float:right;"
+{thumbnail#}></a>
+{title?<div class="title">{title}</div>}<p>
+|
+</p></div>
+
+[admonitionparagraph]
+template::[admonitionblock]
+
+# Delimited blocks.
+[listingblock]
+<div class="listingblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content monospaced">
+<pre>
+|
+</pre>
+</div></div>
+
+[literalblock]
+<div class="literalblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content monospaced">
+<pre>
+|
+</pre>
+</div></div>
+
+[sidebarblock]
+<div class="sidebarblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+|
+</div></div>
+
+[openblock]
+<div class="openblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content">
+|
+</div></div>
+
+[partintroblock]
+template::[openblock]
+
+[abstractblock]
+template::[quoteblock]
+
+[quoteblock]
+<div class="quoteblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content">
+|
+</div>
+<div class="attribution">
+<em>{citetitle}</em>{attribution?<br>}
+&#8212; {attribution}
+</div></div>
+
+[verseblock]
+<div class="verseblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<pre class="content">
+|
+</pre>
+<div class="attribution">
+<em>{citetitle}</em>{attribution?<br>}
+&#8212; {attribution}
+</div></div>
+
+[exampleblock]
+<div class="exampleblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<div class="title">{caption={example-caption} {counter:example-number}. }{title}</div>
+<div class="content">
+|
+</div></div>
+
+[admonitionblock]
+<div class="admonitionblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
+<table><tr>
+<td class="icon">
+{data-uri%}{icons#}<img src="{icon={iconsdir}/{name}.png}" alt="{caption}">
+{data-uri#}{icons#}<img alt="{caption}" src="data:image/png;base64,
+{data-uri#}{icons#}{sys:"{python}" -u -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{icon={iconsdir}/{name}.png}")}"}">
+{icons%}<div class="title">{caption}</div>
+</td>
+<td class="content">
+<div class="title">{title}</div>
+|
+</td>
+</tr></table>
+</div>
+
+# Tables.
+[tabletags-default]
+colspec=<col{autowidth-option! style="width:{colpcwidth}%;"}>
+bodyrow=<tr>|</tr>
+headdata=<th class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }>|</th>
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }>|</td>
+paragraph=<p class="tableblock">|</p>
+
+[tabletags-header]
+paragraph=<p class="tableblock header">|</p>
+
+[tabletags-emphasis]
+paragraph=<p class="tableblock"><em>|</em></p>
+
+[tabletags-strong]
+paragraph=<p class="tableblock"><strong>|</strong></p>
+
+[tabletags-monospaced]
+paragraph=<p class="tableblock monospaced">|</p>
+
+[tabletags-verse]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div class="verse">|</div></td>
+paragraph=
+
+[tabletags-literal]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div class="literal monospaced"><pre>|</pre></div></td>
+paragraph=
+
+[tabletags-asciidoc]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div>|</div></td>
+paragraph=
+
+[table]
+<table class="tableblock frame-{frame=all} grid-{grid=all}{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}
+style="
+margin-left:{align@left:0}{align@center|right:auto}; margin-right:{align@left|center:auto}{align@right:0};
+float:{float};
+{autowidth-option%}width:{tablepcwidth}%;
+{autowidth-option#}{width#style=width:{tablepcwidth}%;}
+">
+<caption class="title">{caption={table-caption} {counter:table-number}. }{title}</caption>
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody>
+{bodyrows}
+</tbody>
+</table>
+
+#--------------------------------------------------------------------
+# Deprecated old table definitions.
+#
+
+[miscellaneous]
+# Screen width in pixels.
+pagewidth=800
+pageunits=px
+
+[old_tabledef-default]
+template=old_table
+colspec=<col style="width:{colwidth}{pageunits};" />
+bodyrow=<tr>|</tr>
+headdata=<th class="tableblock halign-{colalign=left}">|</th>
+footdata=<td class="tableblock halign-{colalign=left}">|</td>
+bodydata=<td class="tableblock halign-{colalign=left}">|</td>
+
+[old_table]
+<table class="tableblock frame-{frame=all} grid-{grid=all}"{id? id="{id}"}>
+<caption class="title">{caption={table-caption}}{title}</caption>
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody style="vertical-align:top;">
+{bodyrows}
+</tbody>
+</table>
+
+# End of deprecated old table definitions.
+#--------------------------------------------------------------------
+
+[floatingtitle]
+<h{level@0:1}{level@1:2}{level@2:3}{level@3:4}{level@4:5}{id? id="{id}"} class="float">{title}</h{level@0:1}{level@1:2}{level@2:3}{level@3:4}{level@4:5}>
+
+[preamble]
+# Untitled elements between header and first section title.
+<div id="preamble">
+<div class="sectionbody">
+|
+</div>
+</div>
+
+# Document sections.
+[sect0]
+<h1{id? id="{id}"}>{title}</h1>
+|
+
+[sect1]
+<div class="sect1{style? {style}}{role? {role}}">
+<h2{id? id="{id}"}>{numbered?{sectnum} }{title}</h2>
+<div class="sectionbody">
+|
+</div>
+</div>
+
+[sect2]
+<div class="sect2{style? {style}}{role? {role}}">
+<h3{id? id="{id}"}>{numbered?{sectnum} }{title}</h3>
+|
+</div>
+
+[sect3]
+<div class="sect3{style? {style}}{role? {role}}">
+<h4{id? id="{id}"}>{numbered?{sectnum} }{title}</h4>
+|
+</div>
+
+[sect4]
+<div class="sect4{style? {style}}{role? {role}}">
+<h5{id? id="{id}"}>{title}</h5>
+|
+</div>
+
+[appendix]
+<div class="sect1{style? {style}}{role? {role}}">
+<h2{id? id="{id}"}>{numbered?{sectnum} }{appendix-caption} {counter:appendix-number:A}: {title}</h2>
+<div class="sectionbody">
+|
+</div>
+</div>
+
+[toc]
+<div id="toc">
+  <div id="toctitle">{toc-title}</div>
+  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+
+[header]
+<!DOCTYPE html>
+<html lang="{lang=en}">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={encoding}">
+<meta name="generator" content="AsciiDoc {asciidoc-version}">
+<meta name="description" content="{description}">
+<meta name="keywords" content="{keywords}">
+<title>{title}</title>
+{title%}<title>{doctitle=}</title>
+ifdef::linkcss[]
+<link rel="stylesheet" href="{stylesdir=.}/{theme=asciidoc}.css" type="text/css">
+ifeval::["{source-highlighter}"=="pygments"]
+<link rel="stylesheet" href="{stylesdir=.}/pygments.css" type="text/css">
+endif::[]
+
+# DEPRECATED: 'pygments' attribute.
+ifdef::pygments[<link rel="stylesheet" href="{stylesdir=.}/pygments.css" type="text/css">]
+
+ifdef::toc2[<link rel="stylesheet" href="{stylesdir=.}/toc2.css" type="text/css" />]
+<link rel="stylesheet" href="{stylesdir=.}/{stylesheet}" type="text/css">
+endif::linkcss[]
+ifndef::linkcss[]
+<style type="text/css">
+include1::{theme%}{stylesdir=/etc/asciidoc/stylesheets}/asciidoc.css[]
+include1::{themedir}/{theme}.css[]
+ifeval::["{source-highlighter}"=="pygments"]
+include1::{stylesdir=/etc/asciidoc/stylesheets}/pygments.css[]
+endif::[]
+
+# DEPRECATED: 'pygments' attribute.
+ifdef::pygments[]
+include1::{stylesdir=/etc/asciidoc/stylesheets}/pygments.css[]
+endif::pygments[]
+
+ifdef::toc2[]
+include1::{stylesdir=/etc/asciidoc/stylesheets}/toc2.css[]
+endif::toc2[]
+include1::{stylesheet}[]
+</style>
+endif::linkcss[]
+ifndef::disable-javascript[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/asciidoc.js"></script>
+<script type="text/javascript" src="{scriptsdir=.}/{theme}.js"></script>
+<script type="text/javascript">
+#TODO: Escape not necessary in HTML5?
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+asciidoc.install({toc,toc2?{toclevels}});
+/*]]>*/
+</script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=/etc/asciidoc/javascripts}/asciidoc.js[]
+include1::{themedir}/{theme}.js[warnings=False]
+asciidoc.install({toc,toc2?{toclevels}});
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::disable-javascript[]
+ifdef::asciimath[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/ASCIIMathML.js"></script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=/etc/asciidoc/javascripts}/ASCIIMathML.js[]
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::asciimath[]
+ifdef::latexmath[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/LaTeXMathML.js"></script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=/etc/asciidoc/javascripts}/LaTeXMathML.js[]
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::latexmath[]
+{docinfo1,docinfo2#}{include:{docdir}/docinfo.html}
+{docinfo,docinfo2#}{include:{docdir}/{docname}-docinfo.html}
+template::[docinfo]
+</head>
+<body class="{doctype}"{max-width? style="max-width:{max-width}"}{css-signature? id="{css-signature}"}>
+# Article, book header.
+ifndef::doctype-manpage[]
+<div id="header">
+ifndef::notitle[<h1>{doctitle}</h1>]
+ifdef::doctitle[]
+<span id="author">{author}</span><br>
+<span id="email" class="monospaced">&lt;<a href="mailto:{email}">{email}</a>&gt;</span><br>
+<span id="revnumber">version {revnumber}{revdate?,}</span>
+<span id="revdate">{revdate}</span>
+<br><span id="revremark">{revremark}</span>
+endif::doctitle[]
+{toc,toc2#}{toc-placement$auto:}{template:toc}
+</div>
+endif::doctype-manpage[]
+# Man page header.
+ifdef::doctype-manpage[]
+<div id="header">
+<h1>
+{doctitle} Manual Page
+</h1>
+{toc,toc2#}{toc-placement$auto:}{template:toc}
+<h2>{manname-title}</h2>
+<div class="sectionbody">
+<p>{manname} -
+   {manpurpose}
+</p>
+</div>
+</div>
+endif::doctype-manpage[]
+<div id="content">
+
+[footer]
+</div>
+{disable-javascript%<div id="footnotes"><hr></div>}
+<div id="footer">
+# Removing footer date and version if footer-style set to none
+ifeval::["{footer-style=default}"!="none"]
+<div id="footer-text">
+template::[footer-text]
+</div>
+endif::[]
+ifdef::badges[]
+<div id="footer-badges">
+ifndef::icons[]
+Valid <a href="http://validator.w3.org/check?uri=referer">HTML5</a>
+and <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>.
+endif::icons[]
+ifdef::icons[]
+<a href="http://validator.w3.org/check?uri=referer">
+  <img src="http://www.w3.org/html/logo/badge/html5-badge-h-solo.png"
+       width="30" alt="HTML5 Powered" title="HTML5 Powered">
+</a>
+<a href="http://jigsaw.w3.org/css-validator/check/referer">
+  <img style="border:0;width:88px;height:31px"
+    src="http://www.w3.org/Icons/valid-css"
+    alt="Valid CSS!">
+</a>
+endif::icons[]
+</div>
+endif::badges[]
+</div>
+</body>
+</html>
+
+[footer-date]
+# Default footer date is document modification time
+ifeval::["{footer-style=default}"!="revdate"]
+ {docdate} {doctime}
+endif::[]
+# If set to "revdate", it'll be set to the revision date
+ifeval::["{footer-style=default}"=="revdate"]
+ {revdate}
+endif::[]
+
+ifdef::doctype-manpage[]
+[synopsis]
+template::[sect1]
+endif::doctype-manpage[]
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..614896f
--- /dev/null
@@ -0,0 +1,7 @@
+pmg-docs (5.0-1) unstable; urgency=medium
+
+  * first version using asciidoc
+
+ -- Proxmox Support Team <support@proxmox.com>  Wed, 22 Feb 2017 06:26:49 +0100
+
+
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/debian/control.in b/debian/control.in
new file mode 100644 (file)
index 0000000..9b64bda
--- /dev/null
@@ -0,0 +1,6 @@
+Source: pmg-docs
+Section: perl
+Priority: extra
+Maintainer: Proxmox Support Team <support@proxmox.com>
+Build-Depends: debhelper (>= 7.0.50~), lintian
+Standards-Version: 3.8.4
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..19cd0c8
--- /dev/null
@@ -0,0 +1,34 @@
+Coryright for files in debian/* and all perl files (*.pl): 
+
+    Copyright (C) 2017 Proxmox Server Solutions GmbH
+
+    This software is written by Proxmox Server Solutions GmbH
+    <support@proxmox.com>
+
+    This program is free software: you can redistribute it and/or
+    modify it under the terms of the GNU Affero General Public License
+    as published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    This program 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
+    Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public
+    License along with this program.  If not, see
+    <http://www.gnu.org/licenses/>.
+
+
+All documentation files (*.adoc) are release under:
+
+    Copyright (C) 2017 Proxmox Server Solutions GmbH
+
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.3
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+    You can find a copy of the license in /usr/share/common-licenses/GFDL.
\ No newline at end of file
diff --git a/debian/install b/debian/install
new file mode 100644 (file)
index 0000000..1412e51
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/
diff --git a/debian/pmg-doc-generator.control b/debian/pmg-doc-generator.control
new file mode 100644 (file)
index 0000000..7bd2f20
--- /dev/null
@@ -0,0 +1,8 @@
+Package: pmg-doc-generator
+Section: perl
+Architecture: any
+Depends: ${perl:Depends}, libpve-common-perl, asciidoc, xmlto
+Description: Proxmox Mail Gateway Documentation helpers
+ Tool to auto-generate various Proxmox Mail gateway Documentation files and
+ manual pages. This package is required to build most other Proxmox Mail
+ Gateway packages.
diff --git a/debian/pmg-doc-generator.install b/debian/pmg-doc-generator.install
new file mode 100644 (file)
index 0000000..367d8f0
--- /dev/null
@@ -0,0 +1,2 @@
+/usr/bin/asciidoc-pmg
+/usr/share/pmg-doc-generator
diff --git a/debian/pmg-docs.control b/debian/pmg-docs.control
new file mode 100644 (file)
index 0000000..3608e49
--- /dev/null
@@ -0,0 +1,5 @@
+Package: pmg-docs
+Section: doc
+Architecture: all
+Description: Proxmox Mail Gateway Documentation
+ This package contains the Proxmox Mail Gateway documentation files.
diff --git a/debian/pmg-docs.install b/debian/pmg-docs.install
new file mode 100644 (file)
index 0000000..6d40bb4
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/pmg-docs
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..736b14e
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+       dh $@ 
diff --git a/docinfo.xml b/docinfo.xml
new file mode 100644 (file)
index 0000000..5a71583
--- /dev/null
@@ -0,0 +1,8 @@
+<!-- DocBook document information file for Proxmox VE asciidoc docs -->
+
+<authorgroup>
+  <corpauthor>Proxmox Server Solutions Gmbh
+  <ulink url="http://www.proxmox.com/"><citetitle>www.proxmox.com</citetitle></ulink>
+  </corpauthor>
+</authorgroup>
+
diff --git a/extractapi.pl b/extractapi.pl
new file mode 100755 (executable)
index 0000000..283d8a0
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use JSON;
+
+use PVE::RESTHandler;
+
+use PMG::API2;
+
+sub cleanup_tree {
+    my ($h) = @_;
+
+    my $class = ref($h);
+    return $h if !$class;
+
+    if ($class eq 'ARRAY') {
+       my $res = [];
+       foreach my $el (@$h) {
+           push @$res, cleanup_tree($el);
+       }
+       return $res;
+    } elsif ($class eq 'HASH') {
+       my $res = {};
+       foreach my $k (keys %$h) {
+           if (my $class = ref($h->{$k})) {
+               if ($class eq 'CODE') {
+                   next if $k eq 'completion';
+               }
+               $res->{$k} = cleanup_tree($h->{$k});
+           } else {
+               $res->{$k} = $h->{$k};
+           }
+       }
+       return $res;
+    } elsif ($class eq 'Regexp') {
+       return "$h"; # return string representation
+    } else {
+       die "unknown class '$class'\n";
+    }
+}
+
+my $tree = cleanup_tree(PVE::RESTHandler::api_dump('PMG::API2'));
+
+print "var pmgapi = " . to_json($tree, {pretty => 1, canonical => 1}) . ";\n\n";
+
+exit(0);
diff --git a/images/proxmox-ci-header.svg b/images/proxmox-ci-header.svg
new file mode 100755 (executable)
index 0000000..4efa8a1
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="132.70847mm"
+   height="3.6731544mm"
+   viewBox="0 0 470.22685 13.015114"
+   id="svg4980"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="CI_Header.svg">
+  <defs
+     id="defs4982" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="171.68639"
+     inkscape:cy="-216.28537"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="2560"
+     inkscape:window-height="1327"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata4985">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-173.45801,-111.56894)">
+    <g
+       clip-path="none"
+       id="g12721"
+       transform="matrix(0.66784621,0,0,-0.66784621,-441.83952,585.27956)">
+      <g
+         transform="translate(-10.714286,-13.571429)"
+         id="g12723">
+        <g
+           id="g12733"
+           transform="translate(618.21336,41.416247)">
+          <g
+             id="g12739"
+             transform="translate(216.17265,-373.75644)">
+            <rect
+               style="opacity:1;fill:#ff9100;fill-opacity:1;stroke:none;stroke-width:0.449;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+               id="rect12725"
+               width="177.16536"
+               height="19.48819"
+               x="273.04303"
+               y="1035.7344"
+               ry="0" />
+            <rect
+               ry="0"
+               y="1035.7344"
+               x="97.644478"
+               height="19.48819"
+               width="177.16536"
+               id="rect12727"
+               style="opacity:1;fill:#e57000;fill-opacity:1;stroke:none;stroke-width:0.449;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+            <rect
+               style="opacity:1;fill:#00617f;fill-opacity:1;stroke:none;stroke-width:0.449;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+               id="rect12729"
+               width="177.16536"
+               height="19.48819"
+               x="449.05322"
+               y="1035.7344"
+               ry="0" />
+            <rect
+               style="opacity:1;fill:#abbaba;fill-opacity:1;stroke:none;stroke-width:0.449;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+               id="rect12731"
+               width="177.16536"
+               height="19.48819"
+               x="624.57361"
+               y="1035.7344"
+               ry="0" />
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/images/proxmox-logo.svg b/images/proxmox-logo.svg
new file mode 100644 (file)
index 0000000..bc5d22a
--- /dev/null
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="800"
+   height="129.03929"
+   id="svg3018"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="Proxmox_logo_standard_hex.svg"
+   inkscape:export-filename="S:\Proxmox-Logo-NEW\Standard-Logo\PNG\Proxmox_logo_standard_hex_800px.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="349.01602"
+     inkscape:cy="64.505265"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="2560"
+     inkscape:window-height="1377"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     objecttolerance="4"
+     gridtolerance="2"
+     guidetolerance="1"
+     fit-margin-top="5"
+     fit-margin-left="5"
+     fit-margin-right="5"
+     fit-margin-bottom="5"
+     inkscape:showpageshadow="false" />
+  <defs
+     id="defs3020">
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath3102-1">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect3104-7"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath4746">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect4748"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       id="clipPath2999-2-3-4-1"
+       clipPathUnits="userSpaceOnUse">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3001-8-8-6-0"
+         d="m 0,14400 14400,0 L 14400,0 0,0 0,14400 z" />
+    </clipPath>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath3102-4">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect3104-1"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath3008">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect3010"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath3102">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect3104"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath4814">
+      <rect
+         style="fill:#e57000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         id="rect4816"
+         width="436.40189"
+         height="326.40991"
+         x="-82.999916"
+         y="-347.71387"
+         transform="matrix(0.73449161,0.67861776,-0.78497193,0.61953133,0,0)" />
+    </clipPath>
+    <clipPath
+       id="clipPath2999-2-3-4"
+       clipPathUnits="userSpaceOnUse">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3001-8-8-6"
+         d="m 0,14400 14400,0 L 14400,0 0,0 0,14400 z" />
+    </clipPath>
+  </defs>
+  <metadata
+     id="metadata3023">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(1451.1374,38.932293)"
+     id="layer1"
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1">
+    <g
+       id="g3378"
+       transform="matrix(0.28026719,0,0,0.28026719,-1040.8325,61.254294)"
+       inkscape:export-filename="S:\lucia\New-Logo-Symbol\Standard-Logo\PNG\Proxmox_logo_standard_hex_300px.png"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90">
+      <g
+         id="g3016-9"
+         style="fill:#000000"
+         transform="matrix(0.85286594,0,0,0.85286594,-2204.7964,-970.06495)">
+        <g
+           style="font-size:144px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Helion;-inkscape-font-specification:Helion"
+           id="text3093-5"
+           clip-path="url(#clipPath3102-4)"
+           transform="matrix(-0.99791979,0,0,0.99791979,1452.3586,746.04784)">
+          <path
+             d="M 276.30443,226.6231 466.89227,17.020605 C 459.49903,9.6280871 450.88762,3.8194321 441.05796,-0.40537695 431.22756,-4.6295171 420.6664,-6.7823721 409.37437,-6.8639479 397.38099,-6.7722031 386.39328,-4.3959326 376.41123,0.26487096 366.4286,4.9263417 357.75623,11.32398 350.39413,19.457805 L 276.30327,100.37282 202.69985,19.457805 C 195.07335,11.32397 186.19787,4.9263248 176.07344,0.2648493 165.94881,-4.395959 155.00175,-6.7722224 143.2322,-6.8639479 131.93978,-6.7823616 121.3786,-4.629505 111.5486,-0.40536951 101.71855,3.8194345 93.107122,9.6280871 85.714287,17.020605 L 276.30769,226.61752"
+             id="path3098-5"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="ccccccccccccc"
+             style="fill:#000000;fill-opacity:1" />
+        </g>
+        <g
+           transform="matrix(0.99791979,0,0,-0.99791979,900.89604,1230.3576)"
+           clip-path="url(#clipPath3102-4)"
+           id="g3196-9"
+           style="font-size:144px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Helion;-inkscape-font-specification:Helion">
+          <path
+             style="fill:#000000;fill-opacity:1"
+             sodipodi:nodetypes="ccccccccccccc"
+             inkscape:connector-curvature="0"
+             id="path3198-1"
+             d="M 276.30443,226.6231 466.89227,17.020605 C 459.49903,9.6280871 450.88762,3.8194321 441.05796,-0.40537695 431.22756,-4.6295171 420.6664,-6.7823721 409.37437,-6.8639479 397.38099,-6.7722031 386.39328,-4.3959326 376.41123,0.26487096 366.4286,4.9263417 357.75623,11.32398 350.39413,19.457805 L 276.30327,100.37282 202.69985,19.457805 C 195.07335,11.32397 186.19787,4.9263248 176.07344,0.2648493 165.94881,-4.395959 155.00175,-6.7722224 143.2322,-6.8639479 131.93978,-6.7823616 121.3786,-4.629505 111.5486,-0.40536951 101.71855,3.8194345 93.107122,9.6280871 85.714287,17.020605 L 276.30769,226.61752" />
+        </g>
+        <path
+           style="font-size:1059.61279297px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e57000;fill-opacity:1;stroke:none;font-family:Helion;-inkscape-font-specification:Helion"
+           d="m 1160.6292,988.20538 0,0 -143.2665,-157.11232 c -8.333,-8.88721 -18.03061,-15.87754 -29.09279,-20.97078 -11.06252,-5.09255 -23.02366,-7.68889 -35.88343,-7.78914 -12.33843,0.0892 -23.87792,2.44147 -34.61849,7.05685 -10.74062,4.61613 -20.14972,10.96284 -28.22736,19.04016 L 1034.9383,988.20777 889.54063,1147.9854 c 8.07762,8.3329 17.48674,14.8349 28.22736,19.5062 10.74057,4.6712 22.28006,7.0457 34.61849,7.1234 12.89308,-0.1 24.92073,-2.6962 36.08307,-7.7891 11.16223,-5.0929 20.79325,-12.0833 28.89315,-20.9708 l 143.2662,-157.64917"
+           id="path3278-4"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccccccccscscc" />
+        <path
+           sodipodi:nodetypes="cccccccccscscc"
+           inkscape:connector-curvature="0"
+           id="path3280-5"
+           d="m 1192.6208,988.20538 0,0 143.2665,-157.11232 c 8.333,-8.88721 18.0306,-15.87754 29.0928,-20.97078 11.0625,-5.09255 23.0237,-7.68889 35.8834,-7.78914 12.3385,0.0892 23.878,2.44147 34.6185,7.05685 10.7407,4.61613 20.1498,10.96284 28.2274,19.04016 l -145.3977,159.77762 145.3977,159.77763 c -8.0776,8.3329 -17.4867,14.8349 -28.2274,19.5062 -10.7405,4.6712 -22.28,7.0457 -34.6184,7.1234 -12.8931,-0.1 -24.9208,-2.6962 -36.0831,-7.7891 -11.1623,-5.0929 -20.7933,-12.0833 -28.8932,-20.9708 L 1192.6211,988.20593"
+           style="font-size:1059.61279297px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e57000;fill-opacity:1;stroke:none;font-family:Helion;-inkscape-font-specification:Helion" />
+      </g>
+      <g
+         id="g3368">
+        <g
+           id="text3223"
+           style="font-size:387.52206421px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Helion;-inkscape-font-specification:Helion">
+          <path
+             inkscape:connector-curvature="0"
+             id="path3354"
+             d="m -686.1811,-262.38737 -177.87034,0 c -6.9834,0.19403 -12.87689,2.71288 -17.68048,7.55658 -4.8036,4.84422 -7.30631,10.85073 -7.50813,18.01955 l 0,245.6858223 c 19.0852,-0.4763289 34.97338,-7.080262 47.6646,-19.8118193 12.69112,-12.731517 19.2789,-28.732724 19.76337,-48.003669 l 135.63098,0 c 19.28682,-0.476261 35.35261,-7.080194 48.19742,-19.811819 12.84432,-12.73145 19.51284,-28.732655 20.00558,-48.003665 l 0,-67.42798 c -0.49274,-19.28682 -7.16125,-35.35262 -20.00557,-48.19744 -12.84482,-12.84432 -28.91061,-19.51283 -48.19743,-20.00556 z m -135.63098,144.15635 0,-75.95335 118.96774,0 c 0.69411,-0.34694 3.47131,0.34736 8.33161,2.08291 4.85991,1.73595 7.63712,6.59605 8.33163,14.58033 l 0,42.23936 c 0.34694,0.7106 -0.34736,3.55238 -2.08291,8.52538 -1.73595,4.97326 -6.59606,7.81505 -14.58033,8.52537 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3356"
+             d="m -308.04521,-143.41963 0,-50.76474 c -0.4766,-19.28682 -7.08053,-35.35262 -19.81182,-48.19744 -12.73179,-12.84432 -28.733,-19.51283 -48.00367,-20.00556 l -177.87034,0 c -7.15293,0.19403 -13.09485,2.71288 -17.82578,7.55658 -4.73095,4.84422 -7.18522,10.85073 -7.36283,18.01955 l 0,245.6858223 c 19.10135,-0.4763289 35.05412,-7.080262 47.85836,-19.8118193 12.80414,-12.731517 19.45651,-28.732724 19.95713,-48.003669 l 0,-17.050751 77.1159,0 39.13922,55.802459 c 6.28082,9.009794 14.16033,16.0819732 23.63854,21.2165595 9.47781,5.1346021 20.06993,7.7503397 31.77641,7.8472208 5.64296,-0.00808 11.11663,-0.6700872 16.42102,-1.9860337 5.30388,-1.3159425 10.29316,-3.2373765 14.96786,-5.7643078 l -54.63991,-77.8909318 c 15.83952,-3.431052 28.82133,-11.197535 38.94546,-23.299469 10.12362,-12.10172 15.3551,-26.55286 15.69445,-43.35347 z m -203.05895,8.13786 0,-58.9026 118.19271,0 c 0.71026,-0.34694 3.55205,0.34736 8.52537,2.08291 4.97294,1.73595 7.81473,6.59605 8.52538,14.58033 l 0,25.57613 c 0.35502,0.69445 -0.35543,3.47166 -2.13135,8.33161 -1.77632,4.86025 -6.74945,7.63746 -14.9194,8.33162 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3358"
+             d="m -66.297193,-262.38737 -135.243457,0 c -19.27095,0.49275 -35.27217,7.16126 -48.00368,20.00558 -12.73156,12.84481 -19.33549,28.91061 -19.81181,48.19742 l 0,135.243464 c 0.47632,19.270945 7.08025,35.272154 19.81181,48.003675 12.73152,12.731561 28.73273,19.3354921 48.00368,19.8118133 l 135.243457,0 C -47.026519,8.3982534 -31.02531,1.7943203 -18.293518,-10.937237 -5.5622279,-23.668754 1.0417033,-39.669961 1.5182953,-58.940906 l 0,-135.243464 c -0.4765997,-19.28682 -7.0805328,-35.35262 -19.8118193,-48.19744 -12.731788,-12.84432 -28.732995,-19.51283 -48.003669,-20.00556 z m 0,186.395713 c 0.355023,0.710536 -0.355427,3.552325 -2.13135,8.525376 -1.776324,4.973203 -6.749453,7.814992 -14.919401,8.525375 l -101.141956,0 c -0.71053,0.355294 -3.55232,-0.355156 -8.52538,-2.13135 -4.97321,-1.776054 -7.815,-6.749182 -8.52537,-14.919401 l 0,-101.529473 c -0.3553,-0.69411 0.35515,-3.47132 2.13134,-8.33162 1.77604,-4.85992 6.74918,-7.63712 14.91941,-8.33162 l 101.141956,0 c 0.710265,-0.34694 3.552054,0.34736 8.525376,2.08291 4.972932,1.73595 7.814721,6.59605 8.525375,14.58033 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3360"
+             style="fill:#e57000;fill-opacity:1"
+             d="m 343.24581,-243.01152 c -5.87764,-5.87708 -12.72377,-10.49499 -20.5384,-13.85374 -7.8152,-3.35821 -16.2114,-5.06974 -25.18861,-5.13459 -9.55093,0.0729 -18.35079,1.96208 -26.3996,5.66744 -8.04928,3.70589 -15.00843,8.79205 -20.87749,15.25848 l -58.51508,64.32783 -58.90259,-64.32783 c -6.02275,-6.63598 -12.96576,-11.77058 -20.82905,-15.40381 -7.86343,-3.6327 -16.550262,-5.47341 -26.060517,-5.52211 -8.977519,0.0649 -17.373714,1.77639 -25.18861,5.1346 -7.814936,3.35874 -14.661064,7.97665 -20.538405,13.85373 L 145.99962,-126.75639 40.207458,-10.501271 c 5.877333,6.0630371 12.723461,10.79396706 20.538405,14.1928038 7.814904,3.398847 16.211099,5.1265285 25.18861,5.1830495 9.381091,-0.072659 18.132507,-1.9618037 26.254287,-5.6674401 8.12163,-3.70562508 15.12923,-8.7917806 21.0228,-15.2584822 l 58.51507,-64.327834 58.51508,64.327834 c 5.86906,6.4667016 12.82821,11.55285519 20.87749,15.2584764 8.04881,3.7056326 16.84867,5.5947793 26.3996,5.6674459 8.97721,-0.056513 17.3734,-1.7841929 25.18861,-5.1830438 7.81464,-3.39884052 14.66077,-8.1297724 20.5384,-14.1928095 L 237.45365,-126.75639 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3362"
+             d="m 695.81803,-262.38737 -42.62688,0 c -13.94281,0.19403 -26.35949,3.97232 -37.25008,11.33487 -10.89107,7.36308 -19.14194,17.14787 -24.75266,29.35442 l 0.38752,-0.77503 -39.91426,87.57886 -39.52674,-87.57886 0,0.77503 c -5.44152,-12.20655 -13.64395,-21.99134 -24.60734,-29.35442 -10.96359,-7.36256 -23.42871,-11.14084 -37.39539,-11.33487 l -42.23936,0 c -7.33862,0.19403 -13.39357,2.71288 -18.16487,7.55658 -4.77131,4.84422 -7.24173,10.85073 -7.41126,18.01955 l 0,245.6858223 c 19.10135,-0.4763289 35.05411,-7.080262 47.85835,-19.8118193 12.80415,-12.731517 19.45652,-28.732724 19.95714,-48.003669 l 0,-129.818224 c 0.0241,-1.76784 0.55699,-3.17259 1.59851,-4.21425 1.04138,-1.04125 2.44613,-1.57408 4.21425,-1.5985 1.00908,0.0325 1.99402,0.35542 2.95482,0.96878 0.96064,0.61377 1.65494,1.32422 2.0829,2.13135 l 75.17831,165.857313 c 1.42074,2.962919 3.51979,5.368749 6.29715,7.217496 2.77705,1.848803 5.84489,2.801451 9.20353,2.857948 3.33409,-0.04034 6.35349,-0.928394 9.05821,-2.664177 2.70436,-1.73573 4.85185,-4.076977 6.44248,-7.02375 l 75.17831,-166.24483 c 0.58909,-0.80712 1.34797,-1.51757 2.27666,-2.13135 0.92817,-0.61337 1.97769,-0.9363 3.14858,-0.96878 1.5821,0.0244 2.87382,0.55726 3.87517,1.59851 1.00081,1.04165 1.5175,2.4464 1.55007,4.21424 l 0,129.818224 c 0.50027,19.270945 7.15264,35.272154 19.95712,48.003675 12.8039,12.731561 28.75667,19.3354921 47.85836,19.8118133 l 0,-245.6858223 c -0.17794,-7.16882 -2.63221,-13.17533 -7.36282,-18.01955 -4.73127,-4.8437 -10.67319,-7.36255 -17.82578,-7.55658 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3364"
+             d="m 963.0584,-262.38737 -135.24346,0 c -19.27095,0.49275 -35.27216,7.16126 -48.00368,20.00558 -12.73156,12.84481 -19.33549,28.91061 -19.81181,48.19742 l 0,135.243464 c 0.47632,19.270945 7.08025,35.272154 19.81181,48.003675 12.73153,12.731561 28.73273,19.3354921 48.00368,19.8118133 l 135.24346,0 c 19.27067,-0.4763289 35.27188,-7.080262 48.0037,-19.8118193 12.7313,-12.731517 19.3352,-28.732724 19.8118,-48.003669 l 0,-135.243464 c -0.4766,-19.28682 -7.0805,-35.35262 -19.8118,-48.19744 -12.73182,-12.84432 -28.73303,-19.51283 -48.0037,-20.00556 z m 0,186.395713 c 0.35502,0.710536 -0.35543,3.552325 -2.13135,8.525376 -1.77633,4.973203 -6.74946,7.814992 -14.9194,8.525375 l -101.14196,0 c -0.71053,0.355294 -3.55232,-0.355156 -8.52538,-2.13135 -4.97321,-1.776054 -7.815,-6.749182 -8.52537,-14.919401 l 0,-101.529473 c -0.35529,-0.69411 0.35515,-3.47132 2.13134,-8.33162 1.77604,-4.85992 6.74918,-7.63712 14.91941,-8.33162 l 101.14196,0 c 0.71026,-0.34694 3.55205,0.34736 8.52537,2.08291 4.97293,1.73595 7.81472,6.59605 8.52538,14.58033 z" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3366"
+             style="fill:#e57000;fill-opacity:1"
+             d="m 1372.6013,-243.01152 c -5.8777,-5.87708 -12.7238,-10.49499 -20.5384,-13.85374 -7.8152,-3.35821 -16.2114,-5.06974 -25.1886,-5.13459 -9.551,0.0729 -18.3508,1.96208 -26.3996,5.66744 -8.0493,3.70589 -15.0085,8.79205 -20.8775,15.25848 l -58.5151,64.32783 -58.9026,-64.32783 c -6.0227,-6.63598 -12.9658,-11.77058 -20.829,-15.40381 -7.8635,-3.6327 -16.5503,-5.47341 -26.0606,-5.52211 -8.9775,0.0649 -17.3737,1.77639 -25.1886,5.1346 -7.8149,3.35874 -14.661,7.97665 -20.5384,13.85373 l 105.7922,116.25513 -105.7922,116.255119 c 5.8774,6.0630371 12.7235,10.79396706 20.5384,14.1928038 7.8149,3.398847 16.2111,5.1265285 25.1886,5.1830495 9.3811,-0.072659 18.1326,-1.9618037 26.2543,-5.6674401 8.1217,-3.70562508 15.1293,-8.7917806 21.0228,-15.2584822 l 58.5151,-64.327834 58.5151,64.327834 c 5.869,6.4667016 12.8282,11.55285519 20.8775,15.2584764 8.0488,3.7056326 16.8486,5.5947793 26.3996,5.6674459 8.9772,-0.056513 17.3734,-1.7841929 25.1886,-5.1830438 7.8146,-3.39884052 14.6607,-8.1297724 20.5384,-14.1928095 L 1266.8091,-126.75639 z" />
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/images/screenshot/gui-login-window.png b/images/screenshot/gui-login-window.png
new file mode 100644 (file)
index 0000000..57e1d0f
Binary files /dev/null and b/images/screenshot/gui-login-window.png differ
diff --git a/index.adoc b/index.adoc
new file mode 100644 (file)
index 0000000..700538f
--- /dev/null
@@ -0,0 +1,51 @@
+image:./images/proxmox-logo.svg[] pass:[<br>] {pmg} Documentation Index
+========================================================================
+:data-uri:
+:icons:
+:title: {pmg} Documentation Index
+
+
+{pmg} Administration Guide
+--------------------------
+
+[width="100%",options="header"]
+|===========================================================
+|Format               |Link
+|Printable version    |link:pmg-admin-guide.pdf[]
+|Online HTML version  |link:pmg-admin-guide.html[]
+|E-Book version       |link:pmg-admin-guide.epub[]
+|===========================================================
+
+
+Individual Chapters
+-------------------
+
+include::chapter-index-table.adoc[]
+
+
+{pmg} Manual Pages
+------------------
+
+Command Line Interface
+~~~~~~~~~~~~~~~~~~~~~~
+
+include::man1-index-table.adoc[]
+
+
+Service Daemons
+~~~~~~~~~~~~~~~
+
+include::man8-index-table.adoc[]
+
+
+Configuration Options
+~~~~~~~~~~~~~~~~~~~~~
+
+include::man5-index-table.adoc[]
+
+
+API Viewer
+~~~~~~~~~~
+
+The link:api-viewer/index.html[API viewer] is a tiny web application
+which allows you to inspect all available API calls.
diff --git a/pmg-admin-guide-docinfo.xml.in b/pmg-admin-guide-docinfo.xml.in
new file mode 100644 (file)
index 0000000..31e90c9
--- /dev/null
@@ -0,0 +1,19 @@
+<subtitle>Release @RELEASE@</subtitle>
+
+<copyright>
+  <year>2017</year>
+  <holder>Proxmox Server Solutions Gmbh</holder>
+</copyright>
+
+<legalnotice>
+  <simpara>
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.3
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+  </simpara>
+  <simpara>   
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+  </simpara>
+</legalnotice>
diff --git a/pmg-admin-guide.adoc b/pmg-admin-guide.adoc
new file mode 100644 (file)
index 0000000..44b3d2f
--- /dev/null
@@ -0,0 +1,98 @@
+ifdef::pmglogo[]
+image:./images/proxmox-logo.svg[] pass:[<br>] Proxmox Mail Gateway Administration Guide
+=======================================================================================
+endif::pmglogo[]
+ifndef::pmglogo[]
+Proxmox Mail Gateway Administration Guide
+=========================================
+endif::pmglogo[]
+:doctype:   book
+:title: Proxmox Mail Gateway Administration Guide
+:toc:
+:numbered:
+:data-uri:
+:icons:
+ifndef::wiki[]
+ifndef::manvolnum[]
+:pmg-toplevel:
+
+// Push titles down one level.
+:leveloffset: 1
+
+include::pmg-intro.adoc[]
+
+
+// Return to normal title levels.
+:leveloffset: 0
+
+Important Service Daemons
+-------------------------
+
+TODO
+
+:leveloffset: 2
+//include::pvedaemon.adoc[]
+
+:leveloffset: 0
+
+
+Useful Command Line Tools
+-------------------------
+
+TODO
+
+:leveloffset: 2
+//include::pveceph.adoc[]
+
+:leveloffset: 0
+
+[appendix]
+Command Line Interface
+----------------------
+
+*pmgsh* - {pmg} API Shell
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+TODO
+
+:leveloffset: 1
+//include::pvesm.1-synopsis.adoc[]
+
+:leveloffset: 0
+
+
+[appendix]
+Service Daemons
+---------------
+
+*pmgpolicy* - Policy Daemon
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+TODO
+
+:leveloffset: 1
+//include::pve-firewall.8-synopsis.adoc[]
+
+:leveloffset: 0
+
+
+[appendix]
+Configuration Files
+-------------------
+
+TODO
+
+:leveloffset: 2
+//include::datacenter.cfg.adoc[]
+
+:leveloffset: 0
+
+:leveloffset: 1
+
+[appendix]
+include::GFDL.adoc[]
+
+:leveloffset: 0
+
+endif::manvolnum[]
+endif::wiki[]
diff --git a/pmg-copyright.adoc b/pmg-copyright.adoc
new file mode 100644 (file)
index 0000000..6f13599
--- /dev/null
@@ -0,0 +1,18 @@
+Copyright and Disclaimer
+------------------------
+
+Copyright (C) 2007-2017 Proxmox Server Solutions GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program 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
+Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public
+License along with this program.  If not, see
+http://www.gnu.org/licenses/
diff --git a/pmg-doc-generator.mk.in b/pmg-doc-generator.mk.in
new file mode 100644 (file)
index 0000000..0cd8465
--- /dev/null
@@ -0,0 +1,77 @@
+# also update debian/changelog
+DOCRELEASE=5.0
+
+DGDIR?=/usr/share/pmg-doc-generator
+
+ASCIIDOC_PMG?=/usr/bin/asciidoc-pmg
+
+PERL_DOC_ENV=PMG_GENERATING_DOCS=1
+
+PMG_COMMON_DOC_SOURCES=                 \
+       ${ASCIIDOC_PMG}                 \
+       pmg-copyright.adoc              \
+       docinfo.xml
+
+all:
+
+docinfo.xml:
+       cp ${DGDIR}/$@ $@.tmp
+       mv $@.tmp $@
+
+%-opts.adoc: ${DGDIR}/gen-%-opts.pl
+       $(PERL_DOC_ENV) perl -I. ${DGDIR}/gen-$*-opts.pl >$@.tmp
+       mv $@.tmp $@
+
+%.adoc: ${DGDIR}/gen-%-adoc.pl
+       $(PERL_DOC_ENV) perl -I. ${DGDIR}/gen-$*-adoc.pl >$@.tmp
+       mv $@.tmp $@
+
+%.1-synopsis.adoc:
+       $(PERL_DOC_ENV) perl -I. -e "use PMG::CLI::$(subst -,_,$*);print PMG::CLI::$(subst -,_,$*)->generate_asciidoc_synopsis();" > $@.tmp
+       mv $@.tmp $@
+
+%.8-synopsis.adoc:
+       $(PERL_DOC_ENV) perl -I. -e "use PMG::Service::$(subst -,_,$*);print PMG::Service::$(subst -,_,$*)->generate_asciidoc_synopsis();" > $@.tmp
+       mv $@.tmp $@
+
+ifneq (${DGDIR},.)
+%.adoc: ${DGDIR}/%.adoc
+       cp $< $@.tmp
+       mv $@.tmp $@
+endif
+
+
+%-plain.html: %.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-wiki -o $@ $*.adoc
+
+chapter-%.html: %.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-chapter -o $@ $*.adoc
+
+%.1: %.adoc %.1-synopsis.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man -o $@ $*.adoc
+       test -n "$${NOVIEW}" || man -l $@
+
+%.1.html: %.adoc %.1-synopsis.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man-html -o $@ $*.adoc
+
+%.8: %.adoc %.8-synopsis.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man -o $@ $*.adoc
+       test -n "$${NOVIEW}" || man -l $@
+
+%.8.html: %.adoc %.8-synopsis.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man-html -o $@ $*.adoc
+
+%.5: %.adoc %.5-opts.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man -o $@ $*.adoc
+       test -n "$${NOVIEW}" || man -l $@
+
+%.5.html: %.adoc %.5-opts.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man-html -o $@ $*.adoc
+
+%.5-plain.html: %.adoc %.5-opts.adoc ${PMG_COMMON_DOC_SOURCES}
+       ${ASCIIDOC_PMG} compile-man-wiki -o $@ $*.adoc
+
+
+.PHONY: cleanup-docgen
+cleanup-docgen:
+       rm -f *.xml.tmp *.1 *.5 *.8 *.adoc docinfo.xml
diff --git a/pmg-intro.adoc b/pmg-intro.adoc
new file mode 100644 (file)
index 0000000..a498361
--- /dev/null
@@ -0,0 +1,4 @@
+Introduction
+============
+
+TODO
diff --git a/png-verify.pl b/png-verify.pl
new file mode 100755 (executable)
index 0000000..8eb6611
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $infile = shift ||
+    die "no input file specified\n";
+
+my $dpcm = 58; # expected
+
+my $tmp = `identify -units PixelsPerCentimeter -format '%x x %y' $infile`;
+
+die "got unexpected density '$tmp' (fix with png-cleanup.pl)\n"
+    if $tmp ne "$dpcm x $dpcm";
+
+exit 0;
diff --git a/scan-adoc-refs b/scan-adoc-refs
new file mode 100755 (executable)
index 0000000..e7767dc
--- /dev/null
@@ -0,0 +1,492 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Getopt::Long;
+use IO::File;
+use JSON;
+
+use Data::Dumper;
+
+my $generate_depends;
+
+GetOptions("depends=s" => \$generate_depends) or
+    die("Error in command line arguments\n");
+
+
+my $environments = {
+    default => 1,
+    wiki => 1,
+    manvolnum => 1,
+    pmglogo => 0, # ignore
+};
+
+my $fileinfo = {};
+
+my $start_env = [];
+foreach my $e (keys %$environments) {
+    push @$start_env, $e if $environments->{$e};
+}
+
+my $env_stack = [$start_env];
+my $env_name_stack = [];
+
+sub reset_environment_stack {
+    $env_stack = [$start_env];
+    $env_name_stack = [];
+}
+
+sub push_environment {
+    my ($env, $not) = @_;
+
+    die "undefined environment '$env'\n" if !defined($environments->{$env});
+
+    # FIXME: this seems wrong  (nested env?)?
+    return if !$environments->{$env}; # do not track
+
+    if ($not) {
+       my $new_env = [];
+       foreach my $e (@{$env_stack->[-1]}) {
+           if ($e ne $env) {
+               push @$new_env, $e;
+           }
+       }
+       die "empty environment" if !scalar($new_env);
+       push @$env_stack, $new_env;
+    } else {
+       push @$env_stack, [$env];
+    }
+
+    push @$env_name_stack, $env;
+}
+
+sub pop_environment {
+    my ($env) = @_;
+
+    die "undefined environment '$env'\n" if !defined($environments->{$env});
+
+    return if !$environments->{$env}; # do not track
+
+    pop @$env_stack;
+    my $res = pop @$env_name_stack;
+
+    die "environment missmatch ($res != $env)\n" if $res ne $env;
+}
+
+sub register_include {
+    my ($filename, $include_filename, $env_list) = @_;
+
+    foreach my $e (@$env_list) {
+       $fileinfo->{include}->{$e}->{$filename}->{$include_filename} = 1;
+    }
+}
+
+sub register_blockid {
+    my ($filename, $blockid, $reftext, $env_list) = @_;
+
+    foreach my $e (@$env_list) {
+       my $fn = $fileinfo->{blockid}->{$e}->{$blockid};
+       die "blockid '$blockid' already defined in $fn"
+           if defined($fn);
+       $fileinfo->{blockid}->{$e}->{$blockid} = $filename;
+       $fileinfo->{reftext}->{$e}->{$blockid} = $reftext
+           if defined($reftext);
+    }
+}
+
+sub register_title {
+    my ($filename, $env, $doctype, $title, $blockid) = @_;
+
+    # fixme: what about other macros?
+    $title =~ s/\{pmg\}/Proxmox Mail Gateway/g;
+    $title =~ s!http://\S+\[(.*?)\]!$1!g;
+
+    # register document title (onyl once)
+    if (!defined($fileinfo->{titles}->{$env}->{$filename})) {
+
+       $fileinfo->{titles}->{$env}->{$filename} = $title;
+
+       if (defined($doctype)) {
+           $fileinfo->{doctype}->{$env}->{$filename} = $doctype;
+       } else {
+           die "unable to change title (no doctype)"
+               if !defined($fileinfo->{doctype}->{$env}->{$filename});
+       }
+    } elsif (!defined($doctype)) {
+       # change title via :title: attribute
+       $fileinfo->{titles}->{$env}->{$filename} = $title;
+    }
+
+    if (defined($doctype) && ($env eq 'manvolnum') && ($doctype == 0)) {
+       if ($title =~ m/.*\(([1-8])\)\s*$/) {
+           $fileinfo->{mansection}->{$env}->{$filename} = $1;
+       }
+    }
+
+    if ($blockid) {
+       die "internal error"
+           if !defined($fileinfo->{blockid}->{$env}->{$blockid});
+       $fileinfo->{reftitle}->{$env}->{$blockid} = $title;
+    }
+}
+
+sub scan_adoc_file {
+    my ($filename) = @_;
+
+    reset_environment_stack();
+
+    # print "SCAN $filename\n";
+
+    my $fh = IO::File->new("$filename", "r") or
+       die "unable to open file '$filename' - $!\n";
+
+    my $env_last_line = {};
+    my $env_last_blockid = {};
+
+    while (defined (my $line = <$fh>)) {
+       if ($line =~ m/^if(n?)def::(\S+)\[(.*)\]\s*$/) {
+           my ($not, $env, $text) = ($1, $2, $3);
+           die "unsuported ifdef usage - implement me" if $text;
+           push_environment($env, $not);
+           next;
+       } elsif ($line =~ m/^endif::(\S+)\[(.*)\]\s*$/) {
+           my ($env, $text) = ($1, $2);
+           die "unsuported ifdef usage - implement me" if $text;
+           pop_environment($env);
+           next;
+       } elsif ($line =~ m/^include::(\S+)\[.*\]\s*$/) {
+           register_include($filename, $1, $env_stack->[-1]);
+           next;
+       }
+
+       # try to detect titles
+       foreach my $e (@{$env_stack->[-1]}) {
+           if ($line =~ m/^===+$/) {
+               register_title($filename, $e, 0, $env_last_line->{$e},
+                              $env_last_blockid->{$e});
+           } elsif ($line =~ m/^---+$/) {
+               register_title($filename, $e, 1, $env_last_line->{$e},
+                              $env_last_blockid->{$e});
+           } elsif ($line =~ m/^~~~+$/) {
+               register_title($filename, $e, 2, $env_last_line->{$e},
+                              $env_last_blockid->{$e});
+           } elsif ($line =~ m/^\^\^\^+$/) {
+               register_title($filename, $e, 3, $env_last_line->{$e},
+                              $env_last_blockid->{$e});
+           } elsif ($line =~ m/^= +(\S.*?)( +=)?$/) {
+               register_title($filename, $e, 0, $1, $env_last_blockid->{$e});
+           } elsif ($line =~ m/^== +(\S.*?)( +==)?$/) {
+               register_title($filename, $e, 1, $1, $env_last_blockid->{$e});
+           } elsif ($line =~ m/^=== +(\S.*?)( +===)?$/) {
+               register_title($filename, $e, 2, $1, $env_last_blockid->{$e});
+           } elsif ($line =~ m/^==== +(\S.*?)( +====)?$/) {
+               register_title($filename, $e, 3, $1, $env_last_blockid->{$e});
+           }
+
+           $env_last_line->{$e} = $line;
+           chomp $env_last_line->{$e};
+       }
+
+       if ($line =~ m/^:(\S+?):\s*(.*\S)?\s*$/) {
+           my ($key, $value) = ($1, $2);
+           if ($key eq 'pmg-toplevel') {
+
+               foreach my $e (@{$env_stack->[-1]}) {
+                   my $title = $fileinfo->{titles}->{$e}->{$filename};
+                   die "not title for toplevel file '$filename' (env=$e)\n"
+                       if !defined($title);
+                   $fileinfo->{toplevel}->{$e}->{$filename} = 1;
+               }
+           } elsif ($key eq 'title') {
+               foreach my $e (@{$env_stack->[-1]}) {
+                   register_title($filename, $e, undef, $value);
+               }
+           }
+       }
+
+       if ($line =~ m/^\[\[(.*)\]\]\s*$/) {
+           my $blockid = $1;
+           die "implement me" if $blockid =~m/,/;
+           my $reftext = '';
+           register_blockid($filename, $blockid, $reftext, $env_stack->[-1]);
+           foreach my $e (@{$env_stack->[-1]}) {
+               $env_last_blockid->{$e} = $blockid;
+           }
+       }
+
+       if ($line =~ m/^\s*$/) {
+           foreach my $e (@{$env_stack->[-1]}) {
+               delete $env_last_blockid->{$e};
+           }
+       }
+
+       # fixme: "anchor:"
+       # bibliography anchors
+       if ($line =~ m/\[\[\[([^\]]*)\]\]\]/) {
+           my $blockid = $1;
+           die "implement me" if $blockid =~m/,/;
+           register_blockid($filename, $blockid, "&#91;$blockid&#93;", $env_stack->[-1]);
+       }
+    }
+}
+
+my $scanned_files = {};
+while (my $filename = shift) {
+    next if $filename !~ m/\.adoc$/; # skip attributes.txt
+    next if $filename =~ m/-(opts|synopsis)\.adoc$/;
+    next if $scanned_files->{$filename};
+
+    scan_adoc_file($filename);
+    $scanned_files->{$filename} = 1;
+}
+
+sub resolve_link_target {
+    my ($env, $filename) = @_;
+
+    my $include_hash = $fileinfo->{include}->{$env};
+
+    my $repeat = 1;
+
+    while ($repeat) {
+       $repeat = 0;
+       foreach my $fn (keys %$include_hash) {
+           if ($include_hash->{$fn}->{$filename}) {
+               next if ($fn eq 'pmg-admin-guide.adoc') &&
+                   $fileinfo->{outfile}->{$env}->{$filename};
+               $filename = $fn;
+               $repeat = 1;
+               last;
+           }
+       }
+    }
+
+    return $filename;
+}
+
+
+# try to generate output file mapping
+foreach my $e (@$start_env) {
+    my $toplevel_hash = $fileinfo->{toplevel}->{$e};
+    foreach my $fn (sort keys %$toplevel_hash) {
+       my $mansection = $fileinfo->{mansection}->{manvolnum}->{$fn};
+       if ($e eq 'wiki') {
+           my $realfn = $fn;
+           $realfn =~ s/\.adoc$//;
+           if (defined($mansection) && ($mansection == 5)) {
+               $realfn .= ".$mansection";
+           }
+           $realfn = "$realfn-plain.html";
+           $fileinfo->{outfile}->{$e}->{$fn} = $realfn;
+       } elsif ($e eq 'manvolnum') {
+           my $realfn = $fn;
+           $realfn =~ s/\.adoc$//;
+           die "toplevel file '$fn' is not marked as manual page!" if !$mansection;
+           $realfn .= ".$mansection";
+           $fileinfo->{outfile}->{$e}->{$fn} = $realfn;
+       } elsif ($e eq 'default') {
+           my $realfn = $fn;
+           $realfn =~ s/\.adoc$//;
+           if (defined($mansection) && ($mansection == 5)) {
+               $realfn .= ".$mansection";
+               $realfn = "$realfn.html";
+           } else {
+               if (($fn ne 'pmg-admin-guide.adoc') &&
+                   $fileinfo->{doctype}->{$e}->{$fn} == 0) {
+                   $realfn = "chapter-$realfn.html";
+               } else {
+                   $realfn = "$realfn.html";
+               }
+           }
+           $fileinfo->{outfile}->{$e}->{$fn} = $realfn;
+       }
+    }
+}
+
+# now resolve blockids
+foreach my $e (@$start_env) {
+    my $blockid_hash = $fileinfo->{blockid}->{$e};
+    foreach my $blockid (keys %$blockid_hash) {
+       my $fn = resolve_link_target($e, $blockid_hash->{$blockid});
+       if ($e eq 'wiki') {
+           my $title = $fileinfo->{titles}->{$e}->{$fn};
+           $title =~ s/\s/_/g;
+           die "found not title for '$fn' in env '$e'" if !$title;
+           $fileinfo->{blockid_target}->{$e}->{$blockid} = "link:/wiki/$title#$blockid";
+
+           # we do not produce wiki pages for all content
+           #my $realfn = $fileinfo->{outfile}->{$e}->{$fn};
+           #warn "no output file mapping for '$fn' ($e)\n" if !$realfn;
+
+       } elsif ($e eq 'default') {
+           my $realfn = $fileinfo->{outfile}->{$e}->{$fn} ||
+               die "no output file mapping for '$fn'\n";
+           $fileinfo->{blockid_target}->{$e}->{$blockid} = "link:/pmg-docs/$realfn#$blockid";
+       } elsif ($e eq 'manvolnum') {
+           # we do not produce manpages for all content
+           # my $realfn = $fileinfo->{outfile}->{$e}->{$fn} ||
+           # warn "no output file mapping for '$fn'\n";
+           $fileinfo->{blockid_target}->{$e}->{$blockid} = $fn;
+       }
+    }
+}
+
+my $makevar_hash = {};
+
+sub makevar_define {
+    my ($varname) = @_;
+
+    die "makefile variable '$varname' already defined\n"
+       if exists($makevar_hash->{$varname});
+
+    $makevar_hash->{$varname} = {};
+}
+
+sub makevar_list_add {
+    my ($varname, $value) = @_;
+
+    die "makefile variable '$varname' not defined\n"
+       if !exists($makevar_hash->{$varname});
+
+    $makevar_hash->{$varname}->{$value} = 1;
+}
+
+sub makevar_dump {
+    my $txt = '';
+
+    foreach my $varname (sort keys %$makevar_hash) {
+       $txt .= "$varname =";
+       foreach my $value (sort keys %{$makevar_hash->{$varname}}) {
+           $txt .= " \\\n\t$value";
+       }
+       $txt .= "\n\n";
+    }
+
+    return $txt;
+}
+
+if ($generate_depends) {
+
+    my $tmpfilename = "${generate_depends}.tmp";
+    my $outfh = IO::File->new($tmpfilename, "w") ||
+       die "unable to open temporary file '$tmpfilename'\n";
+
+    my $depends = {};
+    foreach my $e (@$start_env) {
+       my $env_data = $fileinfo->{include}->{$e};
+
+       my $add_depends;
+
+       $add_depends = sub {
+           my ($fn, $dep) = @_;
+
+           $depends->{$fn}->{$dep} = 1;
+           foreach my $nd (keys %{$env_data->{$dep}}) {
+               &$add_depends($fn, $nd);
+           }
+       };
+
+       foreach my $fn (keys %$env_data) {
+           foreach my $dep (keys %{$env_data->{$fn}}) {
+               &$add_depends($fn, $dep);
+           }
+       }
+    }
+
+    my $depend_varname_hash = {};
+
+    foreach my $fn (sort keys %$depends) {
+       my $basename = uc($fn);
+       $basename =~s/\.adoc$//i;
+       $basename =~s/[^A-Za-z0-9]/_/g;
+
+       my $varname1 = "${basename}_ADOCSOURCES";
+       my $varname2 = "${basename}_ADOCDEPENDS";
+
+       makevar_define($varname1);
+       makevar_define($varname2);
+
+       $depend_varname_hash->{$fn} = $varname2;
+
+       makevar_list_add($varname1, $fn);
+       makevar_list_add($varname2, "\$\{$varname1\}");
+
+       foreach my $dep (sort keys %{$depends->{$fn}}) {
+           if ($dep =~ m/-(opts|synopsis).adoc$/) {
+               makevar_list_add($varname2, $dep);
+           } else {
+               makevar_list_add($varname1, $dep);
+           }
+       }
+    }
+
+    my $man_sources_hash = {};
+    foreach my $sourcefile (keys %{$fileinfo->{outfile}->{manvolnum}}) {
+       $man_sources_hash->{$sourcefile} = 1;
+       my $ihash = $fileinfo->{include}->{manvolnum}->{$sourcefile};
+       foreach my $include (keys %$ihash) {
+           if ($include !~ m/-(opts|synopsis).adoc$/) {
+               $man_sources_hash->{$include} = 1;
+           }
+       }
+    }
+
+    my $varname = "MANUAL_SOURCES";
+    makevar_define($varname);
+    foreach my $sourcefile (sort keys %$man_sources_hash) {
+       makevar_list_add($varname, $sourcefile);
+    }
+
+    $varname = "CHAPTER_LIST";
+    makevar_define($varname);
+    my $filelist = $fileinfo->{outfile}->{default};
+    foreach my $sourcefile (sort keys %$filelist) {
+       my $target = $filelist->{$sourcefile};
+       makevar_list_add($varname, $target);
+    }
+
+    $varname = "MANUAL_PAGES";
+    makevar_define($varname);
+    $filelist = $fileinfo->{outfile}->{manvolnum};
+    foreach my $manpage (sort keys %$filelist) {
+       my $target = $filelist->{$manpage};
+       makevar_list_add($varname, $target);
+    }
+
+    $varname = "WIKI_IMPORTS";
+    makevar_define($varname);
+    $filelist = $fileinfo->{outfile}->{wiki};
+    foreach my $sourcefile (sort keys %$filelist) {
+       my $target = $filelist->{$sourcefile};
+       makevar_list_add($varname, $target);
+    }
+
+    my $res = makevar_dump();
+
+    my $make_targets = {};
+    foreach my $e (@$start_env) {
+       my $filelist = $fileinfo->{outfile}->{$e};
+       foreach my $sourcefile (sort keys %$filelist) {
+           my $varname = $depend_varname_hash->{$sourcefile};
+           next if !defined($varname);
+           my $target = $filelist->{$sourcefile};
+           my $dep = "\$\{$varname\}";
+           $make_targets->{$target} = $dep;
+           if ($e eq 'manvolnum') {
+               $make_targets->{"$target.html"} = $dep;
+               $make_targets->{"$target-plain.html"} = $dep;
+           }
+       }
+    }
+    foreach my $target (sort keys%$make_targets) {
+       my $dep = $make_targets->{$target};
+       $res .= "$target: $dep\n\n";
+    }
+
+    print $outfh $res;
+    close($outfh);
+
+    rename($tmpfilename, $generate_depends) ||
+       die "rename failed - $!";
+}
+
+print to_json($fileinfo, { pretty => 1,  canonical => 1 } );