julia (1.0.3+dfsg-4+rpi1) buster-staging; urgency=medium
authorPeter Michael Green <plugwash@raspbian.org>
Sat, 2 Mar 2019 23:41:50 +0000 (23:41 +0000)
committerPeter Michael Green <plugwash@raspbian.org>
Sat, 2 Mar 2019 23:41:50 +0000 (23:41 +0000)
  * Set julia target option for raspbian.
  * Build with -latomic

[dgit import unpatched julia 1.0.3+dfsg-4+rpi1]

215 files changed:
1  2 
debian/NEWS
debian/README.Debian
debian/changelog
debian/clean
debian/compat
debian/control
debian/copyright
debian/embedded/6.0
debian/embedded/6.0.0
debian/embedded/93b6d6de857dc88e665d2c64397852ab9701ba24
debian/embedded/DocStringExtensions
debian/embedded/DocStringExtensions.jl-0.5.0/.codecov.yml
debian/embedded/DocStringExtensions.jl-0.5.0/.travis.yml
debian/embedded/DocStringExtensions.jl-0.5.0/LICENSE.md
debian/embedded/DocStringExtensions.jl-0.5.0/README.md
debian/embedded/DocStringExtensions.jl-0.5.0/REQUIRE
debian/embedded/DocStringExtensions.jl-0.5.0/appveyor.yml
debian/embedded/DocStringExtensions.jl-0.5.0/docs/make.jl
debian/embedded/DocStringExtensions.jl-0.5.0/docs/src/assets/logo.png
debian/embedded/DocStringExtensions.jl-0.5.0/docs/src/index.md
debian/embedded/DocStringExtensions.jl-0.5.0/src/DocStringExtensions.jl
debian/embedded/DocStringExtensions.jl-0.5.0/src/abbreviations.jl
debian/embedded/DocStringExtensions.jl-0.5.0/src/templates.jl
debian/embedded/DocStringExtensions.jl-0.5.0/src/utilities.jl
debian/embedded/DocStringExtensions.jl-0.5.0/test/coverage.jl
debian/embedded/DocStringExtensions.jl-0.5.0/test/runtests.jl
debian/embedded/DocStringExtensions.jl-0.5.0/test/templates.jl
debian/embedded/DocStringExtensions.jl-0.5.0/test/tests.jl
debian/embedded/DocStringExtensions.source
debian/embedded/Documenter
debian/embedded/Documenter.jl-0.20.0/.codecov.yml
debian/embedded/Documenter.jl-0.20.0/.travis.yml
debian/embedded/Documenter.jl-0.20.0/CHANGELOG.md
debian/embedded/Documenter.jl-0.20.0/LICENSE.md
debian/embedded/Documenter.jl-0.20.0/README.md
debian/embedded/Documenter.jl-0.20.0/REQUIRE
debian/embedded/Documenter.jl-0.20.0/appveyor.yml
debian/embedded/Documenter.jl-0.20.0/assets/html/arrow.svg
debian/embedded/Documenter.jl-0.20.0/assets/html/documenter.css
debian/embedded/Documenter.jl-0.20.0/assets/html/documenter.js
debian/embedded/Documenter.jl-0.20.0/assets/html/search.js
debian/embedded/Documenter.jl-0.20.0/assets/html/style.css
debian/embedded/Documenter.jl-0.20.0/assets/latex/documenter.sty
debian/embedded/Documenter.jl-0.20.0/assets/mkdocs/Documenter.css
debian/embedded/Documenter.jl-0.20.0/assets/mkdocs/mathjaxhelper.js
debian/embedded/Documenter.jl-0.20.0/coverage/Project.toml
debian/embedded/Documenter.jl-0.20.0/coverage/coverage.jl
debian/embedded/Documenter.jl-0.20.0/docs/Manifest.toml
debian/embedded/Documenter.jl-0.20.0/docs/Project.toml
debian/embedded/Documenter.jl-0.20.0/docs/make.jl
debian/embedded/Documenter.jl-0.20.0/docs/src/assets/favicon.ico
debian/embedded/Documenter.jl-0.20.0/docs/src/assets/logo.png
debian/embedded/Documenter.jl-0.20.0/docs/src/contributing.md
debian/embedded/Documenter.jl-0.20.0/docs/src/index.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/anchors.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/builder.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/cross-references.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/docchecks.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/docsystem.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/doctests.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/documenter.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/documentertools.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/documents.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/dom.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/expanders.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/formats.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/mdflatten.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/selectors.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/textdiff.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/utilities.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/internals/writers.md
debian/embedded/Documenter.jl-0.20.0/docs/src/lib/public.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/doctests.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/examples.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/guide.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/github-add-deploy-key.png
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen-export-private-key.png
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen-generated.png
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen.png
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/travis-variables.png
debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/walkthrough.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/latex.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/other-formats.md
debian/embedded/Documenter.jl-0.20.0/docs/src/man/syntax.md
debian/embedded/Documenter.jl-0.20.0/src/Anchors.jl
debian/embedded/Documenter.jl-0.20.0/src/Builder.jl
debian/embedded/Documenter.jl-0.20.0/src/CrossReferences.jl
debian/embedded/Documenter.jl-0.20.0/src/Deps.jl
debian/embedded/Documenter.jl-0.20.0/src/DocChecks.jl
debian/embedded/Documenter.jl-0.20.0/src/DocSystem.jl
debian/embedded/Documenter.jl-0.20.0/src/DocTests.jl
debian/embedded/Documenter.jl-0.20.0/src/Documenter.jl
debian/embedded/Documenter.jl-0.20.0/src/Documents.jl
debian/embedded/Documenter.jl-0.20.0/src/Expanders.jl
debian/embedded/Documenter.jl-0.20.0/src/Formats.jl
debian/embedded/Documenter.jl-0.20.0/src/Utilities/DOM.jl
debian/embedded/Documenter.jl-0.20.0/src/Utilities/MDFlatten.jl
debian/embedded/Documenter.jl-0.20.0/src/Utilities/Selectors.jl
debian/embedded/Documenter.jl-0.20.0/src/Utilities/TextDiff.jl
debian/embedded/Documenter.jl-0.20.0/src/Utilities/Utilities.jl
debian/embedded/Documenter.jl-0.20.0/src/Writers/HTMLWriter.jl
debian/embedded/Documenter.jl-0.20.0/src/Writers/LaTeXWriter.jl
debian/embedded/Documenter.jl-0.20.0/src/Writers/MarkdownWriter.jl
debian/embedded/Documenter.jl-0.20.0/src/Writers/Writers.jl
debian/embedded/Documenter.jl-0.20.0/test/docsystem.jl
debian/embedded/Documenter.jl-0.20.0/test/doctests/broken.jl
debian/embedded/Documenter.jl-0.20.0/test/doctests/broken.md
debian/embedded/Documenter.jl-0.20.0/test/doctests/doctests.jl
debian/embedded/Documenter.jl-0.20.0/test/doctests/fixed.jl
debian/embedded/Documenter.jl-0.20.0/test/doctests/fixed.md
debian/embedded/Documenter.jl-0.20.0/test/dom.jl
debian/embedded/Documenter.jl-0.20.0/test/errors/make.jl
debian/embedded/Documenter.jl-0.20.0/test/errors/src/index.md
debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.gif
debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.jpg
debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.png
debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.webp
debian/embedded/Documenter.jl-0.20.0/test/examples/make.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/mkdocs.yml
debian/embedded/Documenter.jl-0.20.0/test/examples/pages/a.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/pages/b.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/pages/c.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/pages/d.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/pages/e.jl
debian/embedded/Documenter.jl-0.20.0/test/examples/src/assets/custom.css
debian/embedded/Documenter.jl-0.20.0/test/examples/src/assets/custom.js
debian/embedded/Documenter.jl-0.20.0/test/examples/src/assets/favicon.ico
debian/embedded/Documenter.jl-0.20.0/test/examples/src/assets/search.js
debian/embedded/Documenter.jl-0.20.0/test/examples/src/hidden.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/hidden/index.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/hidden/x.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/hidden/y.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/hidden/z.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/index.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/lib/autodocs.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/lib/crlf.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/lib/functions.md
debian/embedded/Documenter.jl-0.20.0/test/examples/src/man/data.csv
debian/embedded/Documenter.jl-0.20.0/test/examples/src/man/tutorial.md
debian/embedded/Documenter.jl-0.20.0/test/examples/tests.jl
debian/embedded/Documenter.jl-0.20.0/test/formats/latex.jl
debian/embedded/Documenter.jl-0.20.0/test/formats/markdown.jl
debian/embedded/Documenter.jl-0.20.0/test/htmlwriter.jl
debian/embedded/Documenter.jl-0.20.0/test/mdflatten.jl
debian/embedded/Documenter.jl-0.20.0/test/missingdocs/make.jl
debian/embedded/Documenter.jl-0.20.0/test/missingdocs/src/exports/index.md
debian/embedded/Documenter.jl-0.20.0/test/missingdocs/src/none/index.md
debian/embedded/Documenter.jl-0.20.0/test/navnode.jl
debian/embedded/Documenter.jl-0.20.0/test/nongit/docs/make.jl
debian/embedded/Documenter.jl-0.20.0/test/nongit/docs/src/index.md
debian/embedded/Documenter.jl-0.20.0/test/nongit/tests.jl
debian/embedded/Documenter.jl-0.20.0/test/runtests.jl
debian/embedded/Documenter.jl-0.20.0/test/utilities.jl
debian/embedded/Documenter.source
debian/embedded/Pkg.source
debian/embedded/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e.tar.gz
debian/embedded/libuv.source
debian/embedded/libwhich-81e9723c0273d78493dc8c8ed570f68d9ce7e89e.tar.gz
debian/embedded/libwhich.source
debian/embedded/llvm-6.0.0.src.tar.xz
debian/embedded/llvm-6.0.src.tar.xz
debian/fontface.css
debian/gbp.conf
debian/gitlab-ci.yml
debian/julia-common.install
debian/julia-common.lintian-overrides
debian/julia-doc.doc-base
debian/julia-doc.doc-base.pdf
debian/julia-doc.docs
debian/julia-doc.install
debian/julia.docs
debian/julia.examples
debian/julia.install
debian/julia.manpages
debian/libjulia-dev.install
debian/libjulia1.install
debian/libjulia1.lintian-overrides
debian/libjulia1.symbols
debian/libjulia1.triggers
debian/not-installed
debian/patches/add-libatomic.patch
debian/patches/appstream.patch
debian/patches/default-load-path-distro.patch
debian/patches/do-not-download-libuv.patch
debian/patches/do-not-download-libwhich.patch
debian/patches/do-not-download-llvm.patch
debian/patches/do-not-download-pkgjl.patch
debian/patches/doc-make.patch
debian/patches/doc-silent.patch
debian/patches/doc-unicode-data-path.patch
debian/patches/install-embedded-llvm-hack.patch
debian/patches/install-julia-hack.patch
debian/patches/jldownload-verbose-fakedownload.patch
debian/patches/llvm-armhf-baseline.patch
debian/patches/make-unwind-logic-error.patch
debian/patches/no-debug-version.patch
debian/patches/privacy-breach.patch
debian/patches/require-sse2-on-i386.patch
debian/patches/series
debian/patches/support-noopt.patch
debian/patches/test-skip-dns-ubuntu.patch
debian/patches/test-skip-i386-spec.patch
debian/patches/test-skip-sigint.patch
debian/prompt.example.jl
debian/rules
debian/shlibdeps.c
debian/shlibdeps.mk
debian/source/format
debian/source/include-binaries
debian/tests/control
debian/tests/runtests.sh
debian/upstream/metadata
debian/watch

diff --cc debian/NEWS
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7603a522b8f96afafaea2e740832c9a60d470b70
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++julia (0.3.12-1) unstable; urgency=medium
++
++  Starting with this release, the dynamic library loader only
++  considers files with a .so extension when given a library name
++  without an extension. With previous releases, the loader would
++  fall back to files with a .so.VERSION extension, which could
++  result in undefined behaviour when multiple versions of the
++  same library were installed.
++
++  Before you install an external Julia package using Pkg.add() that
++  depends on a shared library, make sure to install the matching
++  lib*-dev package, which provides a symlink with a .so extension.
++
++ -- Peter Colberg <peter@colberg.org>  Tue, 10 Nov 2015 23:52:57 -0500
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d068bd98ca5d64349f9dfa180a31662810730fb2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,67 @@@
++Starting Julia REPL
++-------------------
++
++  Simply type `julia' in a shell to launch an interactive Julia session.
++
++  Full documentation and examples are available in the julia-doc package.
++  /usr/share/doc/julia/html/en/index.html
++
++  An Emacs mode for editing Julia source files and managing interactive sessions
++  is available in the ess package.
++
++  -- Sébastien Villemot <sebastien@debian.org>, Wed, 16 Oct 2013 16:07:45 +0200
++
++
++Julia and Math Kernel Library (Intel-MKL)
++-----------------------------------------
++
++  There are two ways to switch the BLAS/LAPACK implementation to MKL.
++   1. Switch the libblas.so.3 and liblapack.so.3 candidate with Debian's
++      alternatives system.
++   2. Rebuild Julia against MKL.
++
++  Alternatives System
++  ^^^^^^^^^^^^^^^^^^^
++
++    You can switch e.g. libblas.so.3-x86_64-linux-gnu with galternatives.
++
++      $ sudo apt install galternatives
++
++    When not using OpenBLAS, you might encounter the following warning,
++    but it doesn't harm:
++
++    WARNING: Error during initialization of module LinearAlgebra:
++    ErrorException("could not load symbol "openblas_get_config":
++    /usr/bin/../lib/x86_64-linux-gnu/julia/libblas.so: undefined symbol: openblas_get_config")
++
++  Rebuild against MKL
++  ^^^^^^^^^^^^^^^^^^^
++
++    To rebuild Julia against MKL, set the variable CUSTOM_MKL as 1 in
++    debian/rules, and rebuild the package. Please make sure that you
++    have intel-mkl installed before doing the custom build.
++
++    Brief Instruction for doing custom build against MKL:
++
++      0. Fetch the source package of julia and enter the source tree.
++
++      1. Install the build dependencies and helper scripts
++
++         $ sudo apt install devscripts
++         $ sudo apt build-dep julia
++
++      2. Modify debian/rules, setting CUSTOM_MKL to 1 .
++
++      3. Build, check, and install.
++
++         $ debuild -j4
++         $ debc
++         $ sudo debi
++
++  Known Problems about MKL
++  ^^^^^^^^^^^^^^^^^^^^^^^^
++
++    1. When MKL is installed in the build environment, this test failure
++       may appear: https://github.com/JuliaLang/julia/issues/23264
++
++  -- Mo Zhou <cdluminate@gmail.com>  Thu, 22 Sept 2018 09:00:00 +0000
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c224608d94b3b8a9f3ab350485d57089a7bdb7c8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1081 @@@
++julia (1.0.3+dfsg-4+rpi1) buster-staging; urgency=medium
++
++  * Set julia target option for raspbian.
++  * Build with -latomic
++
++ -- Peter Michael Green <plugwash@raspbian.org>  Sat, 02 Mar 2019 23:41:50 +0000
++
++julia (1.0.3+dfsg-4) unstable; urgency=medium
++
++  [ Mo Zhou ]
++  * Set JULIA_CPU_TARGET="pwr8" for ppc64el architecture
++
++  [ Graham Inggs]
++  * Avoid baseline violation on armhf, thanks Adrian Bunk
++    (Closes: #919183)
++  * Build with GCC 8 on armhf again
++
++ -- Graham Inggs <ginggs@debian.org>  Tue, 22 Jan 2019 20:19:55 +0000
++
++julia (1.0.3+dfsg-3) unstable; urgency=medium
++
++  * Switch to use embedded LLVM-6.0.0 with upstream patches.
++    + Embed llvm-6.0.0.src.tar.xz to debian/embedded.
++    + Register new tarball in source/include-binaries.
++    + Set USE_SYSTEM_LLVM=0 in rules.
++    + Add patch do-not-download-llvm.patch to redirect downloading.
++    + Add symlinks in debian/embedded to avoid "download" errors.
++    + Add cmake, python3 to B-D for the embedded LLVM.
++    + Update copyright for the embedded LLVM.
++    + Patch Makefile and update rules to amend installation.
++    + Install the embedded LLVM to Julia's private library directory.
++    + dh_makeshlibs: Don't track symbols for the private LLVM library.
++    - Drop B-D on Debian's LLVM 6.0
++    - Remove makefile options for system LLVM.
++  * Remove the DESTDIR definition from make flags. This definition
++    screws up installtion of embedded LLVM.
++  * Add hack for embedded LLVM to let it install shlibs correctly.
++  * Refresh patches (quilt push -a --refresh).
++  * Skip more DNS tests for Sockets.jl module.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Thu, 17 Jan 2019 15:27:52 +0000
++
++julia (1.0.3+dfsg-2) unstable; urgency=medium
++
++  [ Graham Inggs ]
++  * Skip DNS tests which fail on Ubuntu autopkgtest infrastructure
++
++  [ Mo Zhou ]
++  * Add d/gitlab-ci.yml for enabling Salsa CI pipeline.
++  * Delete the unused DEBIAN_FORCE_NONET env var from rules and autopkgtest.
++  * Update copyright for embedded .jl packages.
++  * Uscan: add dversionmangle option to append +dfsg postfix.
++  * Add headers for headless patches.
++  * Add patch (disabled by default) to append "@distro" to default LOAD_PATH.
++  * Bump Standards-Version to 4.3.0 (no change).
++  * Rollback embedded Documenter to 0.20.0, DocStringExtensions to 0.5.0 .
++  * Refresh the list of included-binaries.
++  * Bump B-D-I pygmentize to Py3 version.
++    + Append python3-pkg-resources to B-D-I to workaround #918401
++  * Add repacksuffix option to uscan.
++  * Add openssl to B-D (more test coverage) and Recommends.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sun, 13 Jan 2019 10:53:28 +0000
++
++julia (1.0.3+dfsg-1) unstable; urgency=medium
++
++  * Users who want to use MKL as Julia's BLAS/LAPACK backend should
++    rebuild this package after turning on the CUSTOM_MKL flag in d/rules.
++    I temporarily reverted the use of alternatives mechanism because the
++    code of stdlib/LinearAlgebra is not ready for such a feature.
++
++  * DFSG: Exclude contrib/windows/7zS.sfx (Closes: #916957)
++  * Remove the aforementioned incremental patch since the
++    source tarball has been refreshed.
++  * Revert "Link libjulia.so.X against libblas.so.3 to take
++    advantage from alternatives." (Closes: #916991)
++
++ -- Mo Zhou <cdluminate@gmail.com>  Fri, 21 Dec 2018 14:47:47 +0000
++
++julia (1.0.3-2) unstable; urgency=medium
++
++  * Cherry-pick incremental patch from upstream's force-pushed 1.0.3 tag.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Tue, 18 Dec 2018 06:25:16 +0000
++
++julia (1.0.3-1) unstable; urgency=medium
++
++  * New upstream version 1.0.3
++  * Strip shared object libjulia.so.1 , whilst sys.so is still unstripped.
++  * Update embedded tarball for Pkg.jl .
++  * Refresh and update patches, including patches for embedded source.
++    * Refresh doc-silent.patch on new embedded source.
++  * Upgrade embedded DocStringExtensions.jl to v0.6.0
++  * Upgrade embedded Documenter to v0.21.0
++  * Remove embedded Compat.jl, not used by Documenter.jl anymore.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Mon, 17 Dec 2018 10:15:03 +0000
++
++julia (1.0.2-1) unstable; urgency=medium
++
++  * New upstream version 1.0.2
++  * Remove test-precision.patch, merged upstream.
++  * Import Pkg.jl tarball to d/embedded directory.
++    Its sha512sum matches with the one provided by upstream.
++    + Register the Pkg.jl tarball in include-binaries.
++    + Patch makefile to avoid downloading Pkg.jl tarball.
++  * Remove LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING definition from rules.
++  * Refresh Patches.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Thu, 29 Nov 2018 06:50:23 +0000
++
++julia (1.0.1-2) unstable; urgency=medium
++
++  * Extend JULIA_CPU_TARGET to include optimized targets as well,
++    apart from the generic target. (Closes: #910784)
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sat, 13 Oct 2018 06:16:18 +0000
++
++julia (1.0.1-1) unstable; urgency=medium
++
++  * New upstream stable release 1.0.1 (Sept 2018)
++  * Remove hundreds of patches picked from WIP Julia 1.0.1 release.
++  * Elaborate on why debug info should not be stripped from sys.so in rules.
++  * Drop deps:openspecfun which is not used anymore since 0.7 release.
++  * Add CUSTOM_NATIVE variable in rules for custom builds.
++  * Drop test related patches, because they are not needed anymore:
++    - Drop test-add-envvar-for-skipping-network-tests.patch .
++    - Drop test-moredetail.patch, test-skip-ppc64el-spec.patch
++    - Drop test-remove-powermod.patch, test-aggressive-gc.patch .
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sun, 30 Sep 2018 15:22:20 +0000
++
++julia (1.0.0-3) unstable; urgency=medium
++
++  * Handle floating point precision issue during test. (test-precision.patch)
++  * Patch runtests.jl to let it print more detail. (test-moredetail.patch)
++  * Make Documenter.jl quiet. (pre-apply, doc-silent.patch)
++  * Autopkgtest: Skip network related tests for Ubuntu.
++  * Link libjulia.so.X against netlib LAPACK (libblas.so.3/liblapack.so.3)
++    in order to take advantage from alternatives system. (Closes: #905826)
++  * Shared object libjulia.so.X Depends on high performance BLAS/LAPACK
++    implementations when available, i.e. OpenBLAS | Atlas | Intel-MKL.
++  * Add 167 patches from work-in-progress Julia 1.0.1 release.
++  * Autopkgtest: Execute runtests.jl instead of calling Base.runtests()
++  * README.Debian: Julia's BLAS/LAPACK backend is switchable henceforth.
++  * Also remove the "net_on" guard in test/runtests.jl.
++    (update, test-add-envvar-for-skipping-network-tests.patch)
++  * Downgrade GCC version to 7 for armhf in order to circumvent FTBFS.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sun, 23 Sep 2018 03:11:52 +0000
++
++julia (1.0.0-2) unstable; urgency=medium
++
++  * Run test on all architectures instead of only amd64 and i386,
++    but allow non-x86 tests to fail. (Closes: #906754)
++  * Binary package julia Suggests vim-julia. (Closes: #907050)
++  * Enable the build on s390x
++    - Disable libunwind on s390x (unsatisfiable dependency).
++    * shlibdeps.mk: don't link against libunwind on s390x architecture.
++    * Fix logic error in base/Makefile. (+ make-unwind-logic-error.patch)
++  * Skip some tests unconditionally or conditionally according to Sys.ARCH
++    * Skip "powermod" related tests on non-x86 architecture.
++    * Skip several tests specifically on i386. (+ test-skip-i386-spec.patch)
++    * Skip several tests on ppc64el. (+ test-skip-ppc64el-spec.patch)
++    * Add patch test-add-envvar-for-skipping-network-tests.patch.
++      + rules: Export DEBIAN_FORCE_NONET to skip network tests during build.
++  * Add patch test-aggressive-gc.patch: make garbage collection aggressive.
++  * Re-arrange patches and refresh them.
++  * Disable thumb instruction set for armhf by adding -marm to cflags.
++  * Bump Standards-Version to 4.2.1 (no change).
++  * rules: Don't install extra license files.
++  * Override false-positive lintian error: wrong-path-for-interpreter.
++  * Upload to unstable.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Fri, 14 Sep 2018 11:09:12 +0000
++
++julia (1.0.0-1) experimental; urgency=medium
++
++  * New upstream version 1.0.0
++  * Bump SOVERSION from 0.7.0 to 1.0.0, update debian directory accordingly.
++  * Package libjulia1.0 Breaks and Replaces libjulia0.7 .
++  * Refresh symbols list for libjulia.so.1.0 .
++  * Update the embedded Documenter:
++    + Documenter.jl to v0.19.4
++    + Compat.jl to v1.0.1 .
++    + DocStringExtensions.jl to v0.4.6 .
++    * Update debian/source/include-binaries accordingly.
++    * Update patch privacy-breach.patch and pre-apply the patch.
++  * Add patch doc-unicode-data-path.patch and update deb-make-doc.patch
++    to avoid UnicodeData.txt File-Not-Found during documentation build.
++  * Refresh debian/copyright.
++  * Also build the PDF documentation apart from the HTML doc.
++    + Add latex related Build-Depends-Indep packages for building PDF doc.
++    + Override dh_auto_build-indep to build both HTML and PDF document.
++    + Install the generated PDF doc doc/_build/pdf/en/TheJuliaLanguage.pdf
++    + Register the PDF documentation in doc-base.
++  * Remove source/local-options , not useful anymore.
++  * Update appstream.patch from upstream pull request #28020.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Thu, 16 Aug 2018 07:48:17 +0000
++
++julia (0.7.0-2) unstable; urgency=medium
++
++  [ Peter Colberg ]
++  * Drop Build-Depends on libfftw3-dev, Bindings to the FFTW library
++    have been removed from Base. (Closes: #905849)
++
++  [ Mo Zhou ]
++  * Replace Sys.CPU_CORES with Sys.CPU_THREADS in test script.
++  * Add patch test-skip-sigint.patch to temporarily avoid a random
++    test failure in test/stress.jl, which sometimes fail to catch SIGINT.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sun, 12 Aug 2018 01:00:36 +0000
++
++julia (0.7.0-1) unstable; urgency=medium
++
++  * New upstream version 0.7.0
++  * Update embedded libuv tarball to ed3700c849289ed01fe04273a7bf865340b2bd7e.
++  * Refresh all the patches.
++  * Move privacy-breach.patch to quilt directory, and pre-apply the patch.
++  * Require libgit2-dev (>= 0.27.0~) as B-D.
++  * Bump Standards-Version to 4.2.0 (no change).
++  * Three new symbols for libjulia0.7 0.7.0 .
++  * Only traverse within debian directory when fixing shebang. (Avoid FTBFSx2)
++  * README.Debian: Add brief instructions for rebuilding Julia against MKL.
++  * Update file matching expressions in copyright.
++  * Require llvm-6.0-dev (>= 1:6.0.1-3) in the B-D field.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Thu, 09 Aug 2018 16:43:05 +0000
++
++julia (0.7.0~beta2-1) experimental; urgency=medium
++
++  * New upstream BETA version 0.7.0~beta2
++  * Changes related to embedded sources:
++    + Embed newer libuv tarball which is specified by upstream.
++    - Remove the old libuv-d8ab1c6a33e77bf155facb54215dd8798e13825d.tar.gz
++    + Embed libwhich-81e9723c0273d78493dc8c8ed570f68d9ce7e89e.tar.gz
++    - Remove embedded arpack tarball and corresponding b-d.
++    * Update binary file registration in source/include-binaries .
++  * Updates related to patch stack:
++    * Refresh patches for 0.7.0~beta2
++    + Add patch: do-not-download-libwhich.patch
++    + Update patch deb-make-doc.patch to fix document build failure.
++    + Update no-debug-version.patch to adapt to upstream Makefile change.
++    - Remove do-not-download-arpack.patch, not used anymore.
++    - Remove do-not-query-ldconfig.patch, due to upstream's commit:
++      github.com/JuliaLang/julia/commit/28f3c06f2d30dd1ae2c189cf8fb54d625ecc26ad
++    - Remove patch: unversioned-system-load-path.patch (not applied).
++      We don't need it anymore because it may result in confusing behaviour.
++    - Remove unused tests patch: test_libgit2.patch, unicode-test.patch,
++      test_replcompletions.patch. Nolonger needed since the tests don't fail.
++  * Control-related changes:
++    * Bump B-D llvm version to 6 (Closes: #873408)
++    * Bump SOVERSION, and update corresponding file names.
++    * Update .install files: install several new files.
++    * Update symbols control file.
++    * libjuila0.7 breaks and replaces libjulia0.6 .
++    * symbols: Mark jl_cpuidex as {amd64,i386}-only.
++    * Mark usr/share/doc/julia/html/* as not-installed to silent dh_missing.
++  * Build-related changes:
++    + Run dh_missing --list-missing during build.
++    + Suppress compiler warning by explicitly defining the following CXX flag:
++      -DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=0
++    * JULIA_CPU_CORES is deprecated in favor of JULIA_CORE_THREADS.
++    * Fix shebang and mode bits during dh_fixperms:
++      's@#!/usr/bin/env julia@#!/usr/bin/julia@g'
++    * Delete the deprecated make flag USE_SYSTEM_ARPACK.
++  * Policy-related changes:
++    + Update SOVERSION in lintian overrides
++    * julia-common: Override one more lintian Info:
++      package-contains-documentation-outside-usr-share-doc
++  * Miscellaneous changes:
++    - Delete comment from the watch file.
++    + Install an example config which tweaks the default prompt string.
++  * Update copyright for Julia 0.7.X and embedded sources.
++  * autopkgtest: Remove the arpack-sanity test, because arpack was split out
++    from Julia 0.7.X by upstream.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Mon, 23 Jul 2018 08:52:51 +0000
++
++julia (0.6.4-2) unstable; urgency=medium
++
++  * Let julia depend on libjulia0.6 (= ${binary:Version})
++  * libjulia0.6 breaks julia (<< 0.5.0~) due to file overwrite.
++    This fixes stable->sid upgrade. (Closes: #903498)
++  * Remove unused patch version-git.patch since we have NO_GIT=1 in rules.
++  * Fill in patches' header with DEP-3 alike information.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Wed, 11 Jul 2018 09:23:52 +0000
++
++julia (0.6.4-1) unstable; urgency=medium
++
++  [ Mo Zhou ]
++  * New upstream version 0.6.4
++  * Refresh patches after importing 0.6.4 .
++  * Replace the placeholder in watch file, which was left unchanged by mistake.
++  * Import embedded copy of libuv (checksum identical to upstream's).
++    libuv-d8ab1c6a33e77bf155facb54215dd8798e13825d.tar.gz
++    + Register the new embedded tarball in source/include-binary
++    * Refresh copyright for the tarball.
++  * Deprecate the get-orig-tarball target in rules.
++  * Split the autopkgtest test command into individual script.
++  * Replace the old do-not-download-libuv.patch patch with a new one.
++  * Patch: Let jldownload be verbose and download from file:// URI.
++    + debian/patches/jldownload-verbose-fakedownload.patch
++  * rules: Don't install any .gitignore file!
++  * rules: Update the TAGGED_RELEASE_BANNER to avoid confusion.
++  * Update the matching pattern in lintian overrides.
++  * Patch: disable unversioned-system-load-path.patch .
++  * Autopkgtest: One more script to test arpack sanity.
++
++  [ Graham Inggs ]
++  * Disable unaligned access on armhf
++  * Enable ARM NEON extensions, since #842142 is fixed
++
++ -- Mo Zhou <cdluminate@gmail.com>  Tue, 10 Jul 2018 16:08:48 +0000
++
++julia (0.6.3-6) unstable; urgency=medium
++
++  * Bump B-D on libutf8proc-dev to (>= 2.1.1) and enable
++    unicode/utf8proc test, since #902902 is fixed
++  * Drop libjulia0.6's explicit dependency on libgit2-26
++
++ -- Graham Inggs <ginggs@debian.org>  Mon, 09 Jul 2018 20:29:42 +0000
++
++julia (0.6.3-5) unstable; urgency=medium
++
++  * Switch B-D LLVM version from 3.9 -> 4.0 .
++  * Skip more tests in test/libgit2.jl to avoid FTBFS.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Mon, 09 Jul 2018 12:29:34 +0000
++
++julia (0.6.3-4) unstable; urgency=medium
++
++  * Don't strip sys.so and libjulia.so as suggested upstream. This fixes
++    several tests that fail during autopkgtest but didn't fail during build.
++    https://github.com/JuliaLang/julia/issues/23115#issuecomment-320715030
++  * Override lintianE: libjulia0.6: unstripped-binary-or-object.
++  * Enable more tests from libgit2.jl and replcompletions.jl .
++  * Let libjulia0.6 depend on libgit2-27 (>= 0.27.0+dfsg.1-0.2) explicitly.
++  * Add missing symlinks to libmbedcrypto and libmbedx509 .
++  * Drop unneeded B-D libarpack2-dev, libjs-mathjax.
++    Drop libjs-underscore from julia-doc Depends.
++  * Revert "control: Stick to unicode-data version 11 to avoid surprise."
++  * Loosen libgit2 requirement to (>= 0.26.0+dfsg.1-1.1) .
++  * Explicitly Build-Depends on libmbedtls-dev.
++  * Upload to unstable.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Mon, 09 Jul 2018 09:08:35 +0000
++
++julia (0.6.3-3) experimental; urgency=medium
++
++  * rules: Wrap-and-sort the build flags.
++  * Fix a typo in shlibdeps.mk which could causes dh-link failure.
++  * Update shlibdeps.mk for libuv1 .
++  * rules: Comment that we cannot use the libuv1 provided in archive.
++  * Skip test "replcompletions" to avoid FTBFS.
++    See: https://github.com/JuliaLang/julia/issues/27958
++  * Bump Standards-Version to 4.1.5 (no change).
++  * Add the missing B-D libcurl4-gnutls-dev | libcurl-dev .
++
++ -- Mo Zhou <cdluminate@gmail.com>  Sat, 07 Jul 2018 08:39:35 +0000
++
++julia (0.6.3-2) experimental; urgency=medium
++
++  * Deal with symlinks for embedded julia documenter in more graceful way.
++  * Remove unused symlinks shipped in julia-doc .
++  * Install upstream NEWS, HISTORY, DISTRIBUTING, etc to julia.
++  * Merge debian/NOTES into debian/README.Debian
++  * Clean up old/unused parts in rules.
++  * Stick to unicode-data version 11 to avoid surprise.
++  * Update shlibdeps.mk according to upstream Make.inc .
++  * Move all private shared object files to package libjulia0.6 .
++  * Don't generate symbols for the private libarpack.so .
++  * Add a custom option to enable building Julia with MKL.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Fri, 06 Jul 2018 11:18:49 +0000
++
++julia (0.6.3-1) experimental; urgency=medium
++
++  [ Peter Colberg ]
++  * Update Vcs-* fields for move to salsa.debian.org
++  * New upstream version 0.6.0
++  * Refresh patches
++  * Move manpages and examples back to julia package
++  * Add libjulia0.6 with runtime library
++  * Add libjulia-dev with runtime headers
++  * Build-Depends on llvm-3.9-dev
++  * Drop Build-Depends on python3-sphinx (Closes: #896622)
++  * Build-Depends on libgit2-dev (>= 0.23)
++  * Build-Depends on libutf8proc-dev (>= 2.1.0)
++  * Substitute deprecated parameters in autopkgtest command
++  * Update debian/copyright
++  * Drop embedded copy of Rmath from upstream tarball
++  * Drop embedded copy of juliadoc from upstream tarball
++
++  [ Mo Zhou ]
++  * Add myself to Uploaders.
++  * Refresh patch after rebasing Peter's work to master (0.4.7-7).
++  * New upstream version 0.6.3 (Closes: #839668)
++  * Refresh existing patches based on Julia 0.6.3 .
++  * Household changes:
++    * Bump Standards-Version to 4.1.4 .
++    * Change Priority from extra to optional. (4.0.0 -> 4.0.1)
++    * Bump debhelper compat level to 11 .
++    * Remove --parallel option in favor of debhelper compat 11.
++  * Embed several convenient code copies to debian/embedded/ :
++    * These embedded Julia package copies are used to build Julia doc.
++      + Compat.jl-0.69.0
++      + DocStringExtensions.jl-0.4.4
++      + Documenter.jl-0.18.0
++    * The embedded arpack source is used to avoid #902914.
++      + arpack-ng-3.3.0.tar.gz
++    * source: don't complain about binary files from embedded source.
++  * Patch upstream doc to avoid downloading anything.
++    + Build-Depends on unicode-data. (used during doc build)
++    + Prepare symlinks for embedded julia packages during dh_auto_configure.
++    + Patch upstream makefile to prevent it from downloading arpack source.
++  * Add upstream metadata including citation information.
++  * Upgrade watch file to uscan version 4.
++  * Move libjulia0.6 to libs section.
++  * Requires libgit2-dev >= 0.27.0+dfsg.1-0.5 for Build-Depends.
++    The specified version ships working TLS support.
++  * Add symbols control file for libjulia0.6 .
++  * rules: Don't use system Arpack. It causes "eigs(spdiagm(1:25))" failure.
++  * Patch upstream tester to skip utf8proc and libgit2 tests.
++  * Add missing Build-Depends for embedded arpack.
++  * Switch the default downloader dependency from wget to curl.
++    See https://github.com/JuliaLang/julia/issues/22783 . wget doesn't
++    throw the expected error, which would cause test failure.
++  * Patch embedded documenter code to prevent privacy-breach-generic .
++    + Replace google font css URL with customized css to avoid privacy breach.
++    + Use the "Incolsolata" font instead of "Roboto Mono".
++    + Document package depends on inconsolata font.
++  * Move AppStream xml file to new location /usr/share/metainfo .
++  * Patch upstream's outdated appstream xml file to prevent lintian Error.
++  * Update HTML documentation registration path in doc-base.
++  * Don't ship debug files e.g. libccalltest.so.debug .
++  * Don't trigger ldconfig for binary package "julia" because it ships libs
++    in private directory. This is accomplished by appending --no-scripts
++    option to dh_makeshlibs . An ldconfig trigger is manually added for
++    "libjulia0.6" package.
++  * Export HOME environt variable to really fix the mkdir permission issue.
++  * Mark symbol jl_cpuid as (amd64, i386)-only.
++  * Add NOTES to debian/ directory. (MKL is causing test failure)
++  * Note related to LLVM-4.0 : julia-0.6.3, built with llvm-4.0, is able to
++    pass the tests. However, llvm-3.9 is still preferred since upstream
++    sticks to llvm-3.9 .
++  * Update copyright for Julia 0.6.3 and embedded sources.
++  * Upload to experimental.
++
++ -- Mo Zhou <cdluminate@gmail.com>  Thu, 05 Jul 2018 09:26:56 +0000
++
++julia (0.4.7-7) unstable; urgency=medium
++
++  * Add missing documentation option to fix build with Sphinx 1.5
++  * Switch to debhelper 10
++  * Use https in debian/control and debian/copyright
++  * Bump Standards-Version to 4.0.0
++  * Drop override_dh_strip-arch, ddeb migration is complete
++  * Fix more Lintian warnings spelling-error-in-binary
++  * Mark all binary packages Multi-Arch: foreign
++  * Enable all hardening flags
++
++ -- Graham Inggs <ginggs@debian.org>  Wed, 12 Jul 2017 14:50:13 +0200
++
++julia (0.4.7-6) unstable; urgency=medium
++
++  * Use openlibm instead of libm on mips, mips64el and mipsel
++
++ -- Graham Inggs <ginggs@debian.org>  Wed, 25 Jan 2017 07:39:32 +0200
++
++julia (0.4.7-5) unstable; urgency=medium
++
++  * Use openlibm instead of libm on armhf and ppc64
++  * Use openblas instead of blas and lapack on mips64el and ppc64
++  * Update debian/copyright
++  * Do not override ARM options in Make.inc
++  * Do not print warning if unable to determine host CPU name
++  * Add src/*.dwo to debian/clean
++  * Explicitly set USE_SYSTEM_LIBM where needed
++
++ -- Graham Inggs <ginggs@debian.org>  Mon, 23 Jan 2017 08:29:33 +0200
++
++julia (0.4.7-4) unstable; urgency=medium
++
++  * Use DEB_VENDOR inplace of lsb_release -si
++
++ -- Peter Colberg <peter@colberg.org>  Mon, 02 Jan 2017 22:28:51 -0500
++
++julia (0.4.7-3) unstable; urgency=medium
++
++  * Set TAGGED_RELEASE_BANNER to distribution and source package version
++    (Closes: #849815)
++
++ -- Peter Colberg <peter@colberg.org>  Sat, 31 Dec 2016 13:43:20 -0500
++
++julia (0.4.7-2) unstable; urgency=medium
++
++  * Ensure JULIA_CPU_CORES >= 2 to respawn test workers reaching memory limit
++    (Closes: #848506)
++
++ -- Peter Colberg <peter@colberg.org>  Tue, 20 Dec 2016 23:57:28 -0500
++
++julia (0.4.7-1) unstable; urgency=medium
++
++  * New upstream release
++  * Refresh patches
++  * Drop install-sh-exit-status.patch, applied upstream
++  * Drop verbose-build.patch since libuv is already built with V=1
++  * Drop do-not-use-home-directory-in-tests.patch in favour of setting HOME
++  * Drop disable-download-test.patch since wget is not actually invoked
++  * Remove unused lintian override configure-generated-file-in-source
++  * Add debian/gbp.conf for pristine-tar
++
++ -- Peter Colberg <peter@colberg.org>  Sun, 18 Sep 2016 23:55:05 -0400
++
++julia (0.4.6-1) unstable; urgency=medium
++
++  [ Peter Colberg ]
++  * New upstream release
++  * Refresh patches
++  * Drop unneeded build dependency on libdouble-conversion-dev
++  * Bump Standards-Version to 3.9.8, no further changes
++
++  [ Graham Inggs ]
++  * Use libopenlibm instead of libm on arm64
++  * Fix inconsistent use of GNU_SOURCE in embedded libuv (Closes: #748573)
++  * Drop arm-rec_backtrace.patch, no longer needed since ARM ABI backport
++
++ -- Peter Colberg <peter@colberg.org>  Thu, 23 Jun 2016 22:20:54 -0400
++
++julia (0.4.5-3) unstable; urgency=medium
++
++  * Disable ARM NEON extensions. (Closes: #820220)
++
++ -- Graham Inggs <ginggs@debian.org>  Sun, 17 Apr 2016 13:35:42 +0200
++
++julia (0.4.5-2) unstable; urgency=medium
++
++  * Make rec_backtrace() always return 0 on ARM and PPC64,
++    this avoids a FTBFS on armhf with recent GCC.
++
++ -- Graham Inggs <ginggs@debian.org>  Thu, 07 Apr 2016 14:32:28 +0200
++
++julia (0.4.5-1) unstable; urgency=medium
++
++  * New upstream release.
++  * Refresh patches, new fix-spelling-error-in-binary.patch.
++  * Use libopenlibm instead of libm on powerpc and ppc64el.
++
++ -- Graham Inggs <ginggs@debian.org>  Wed, 30 Mar 2016 17:56:56 +0200
++
++julia (0.4.3-4) unstable; urgency=medium
++
++  * Drop versioned build dependency on llvm-3.8-dev and
++    build dependencies on libllvm3.x (no longer needed).
++  * Upload to unstable.
++
++ -- Graham Inggs <ginggs@debian.org>  Sun, 13 Mar 2016 11:06:39 +0200
++
++julia (0.4.3-3) experimental; urgency=medium
++
++  * Build depend on libllvm3.x as well (experimental).
++
++ -- Graham Inggs <ginggs@debian.org>  Mon, 08 Feb 2016 13:06:53 +0200
++
++julia (0.4.3-2) experimental; urgency=medium
++
++  * Optionally build depend on llvm-3.8-dev (>= 1:3.8~+rc1).
++  * Add debian/clean to fix FTBFSx2.
++  * Migrate from julia-dbg to ddebs, bump debhelper build-dependency.
++  * Bump Standards-Version to 3.9.7, no further changes.
++  * Enable tests on i386 again.
++  * Improve generated debug info to fix FTBFS on i386
++    (see upstream issue #13754).
++
++ -- Graham Inggs <ginggs@debian.org>  Mon, 08 Feb 2016 10:02:00 +0200
++
++julia (0.4.3-1) unstable; urgency=medium
++
++  [ Graham Inggs ]
++  * Ensure pcre_h.jl and errno_h.jl are sorted reproducibly.
++
++  [ Peter Colberg ]
++  * Imported Upstream version 0.4.3
++  * Refresh patches.
++  * Drop patch fix-arm64-ftbfs.patch, no longer needed.
++  * Update Vcs-Git and Vcs-Browser fields.
++  * Fix lintian warning dh-exec-useless-usage.
++  * Fix lintian warning spelling-error-in-binary.
++
++ -- Peter Colberg <peter@colberg.org>  Thu, 14 Jan 2016 07:56:18 -0500
++
++julia (0.4.2-3) unstable; urgency=medium
++
++  * Fix FTBFS on arm64 (thanks to Edmund Grimley Evans). (Closes: #807701)
++  * Disable tests on i386 until perfomance issue with LLVM >= 3.4
++    is resolved (see upstream issue #14191).
++
++ -- Graham Inggs <ginggs@debian.org>  Sat, 12 Dec 2015 11:27:26 +0200
++
++julia (0.4.2-2) unstable; urgency=medium
++
++  * Set number of parallel workers for tests.
++    + Restart workers exceeding maximum resident memory size of 500 MiB.
++  * Drop build depends on llvm-3.8-dev to permit migration to testing.
++    (Closes: #803644)
++
++ -- Peter Colberg <peter@colberg.org>  Thu, 10 Dec 2015 06:50:01 -0500
++
++julia (0.4.2-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.4.2
++  * Refresh patches.
++  * Upload to unstable. (Closes: #803644)
++
++ -- Peter Colberg <peter@colberg.org>  Mon, 07 Dec 2015 06:49:01 -0500
++
++julia (0.4.1-2) experimental; urgency=medium
++
++  * Build depend on libpcre2-dev >= 10.20-3~ to fix FTBFS on ppc64el.
++  * Optionally build depend on llvm-3.8-dev to reduce performance regression.
++  * Optionally build depend on llvm-3.6-dev to ease backporting.
++
++ -- Peter Colberg <peter@colberg.org>  Wed, 02 Dec 2015 07:26:24 -0500
++
++julia (0.4.1-1) experimental; urgency=medium
++
++  * Imported Upstream version 0.4.1
++  * Refresh patches.
++  * Update debian/copyright.
++  * Build depend on libsuitesparse-dev >= 1:4.4.5
++  * Build depend on llvm-3.7-dev.
++  * Build depend on libpcre2-dev (thanks to Matthew Vernon).
++  * Disable libgit2 test to avoid dependency on libgit2.
++  * Disable download test to avoid dependency on curl or wget.
++  * Do not use home directory in tests.
++  * Fix backtrace test with MCJIT.
++  * Fix documentation spelling errors.
++  * Install examples to doc directory inplace of symlink.
++
++ -- Peter Colberg <peter@colberg.org>  Wed, 25 Nov 2015 08:00:20 -0500
++
++julia (0.3.12-2) unstable; urgency=medium
++
++  [ Peter Colberg ]
++  * Fix automated package testing with autopkgtest.
++  * Test REPL in dumb mode.
++  * Build depend on libopenlibm-dev (>= 0.4.1+dfsg-4~) to fix FTBFS on i386.
++  * Fix arch-all-only build with dpkg-buildpackage -A.
++
++  [ Sébastien Villemot ]
++  * Remove myself from Uploaders.
++
++ -- Graham Inggs <ginggs@debian.org>  Wed, 25 Nov 2015 10:46:18 +0200
++
++julia (0.3.12-1) unstable; urgency=medium
++
++  [ Peter Colberg ]
++  * Imported Upstream version 0.3.12
++  * Add julia-common package with standard library and test suite.
++  * Remove embedded libraries:
++    + Build depend on libdsfmt-dev.
++    + Build depend on libutf8proc-dev.
++  * Generate version_git.jl from upstream commit.
++  * Build documentation using python3-sphinx.
++  * Fix potential privacy breach in documentation:
++    + Use libjs-modernizr package inplace of external link.
++    + Strip external link to Google Fonts API.
++  * Query SSE2 extension on i386 using x86 CPUID opcode.
++  * Do not query ldconfig for library sonames.
++  * Generate package dependencies for dynamically loaded libraries.
++  * Symlink dynamically loaded libraries to private library path.
++  * Add missing examples test for Base.runtests().
++  * Fix hanging socket test for Base.runtests().
++  * Enable parallel test.
++
++  [ Graham Inggs ]
++  * Build in the multiarch lib directories as well,
++    so that patchelf is no longer required. (Closes: #799099)
++  * Build everywhere. (Closes: #802583)
++    + Use libopenlibm where available, libm elsewhere.
++    + Use libopenblas where available, libblas and liblapack elsewhere.
++    + Cherry-pick patches from upstream 0.4.0 for armhf and ppc64el.
++
++ -- Graham Inggs <ginggs@debian.org>  Fri, 13 Nov 2015 15:56:34 +0200
++
++julia (0.3.11-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.11
++  * d/p/mcjit-llvm-ftbfs.patch: dropped, applied upstream.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 06 Sep 2015 18:51:09 +0200
++
++julia (0.3.10-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.10
++  * d/p/inject-ldflags.patch: drop patch, no longer needed.
++  * d/p/mcjit-llvm-ftbfs.patch: new patch, taken from upstream.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Fri, 17 Jul 2015 23:14:01 +0200
++
++julia (0.3.9-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.9
++  * repl-test.patch: new patch, prevents a test failure.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 21 Jun 2015 14:57:41 +0200
++
++julia (0.3.8-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.8.
++    For the time being, manually embed juliadoc python package.
++    In the longer run, a separate Debian package should be created.
++  * sphinx-build.patch: new patch, needed for building doc without virtualenv.
++  * unicode-test.patch: new patch to workaround a test failure in unicode.jl.
++  * Set a hard dependency on OpenBLAS. (Closes: #778912)
++  * Ship tests in main package, so that they can be run on the compiled binary.
++  * Add autopkgtest (DEP8) support.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Mon, 25 May 2015 15:48:34 +0200
++
++julia (0.3.5-1) experimental; urgency=low
++
++  * Imported Upstream version 0.3.5. (Closes: #776069)
++
++ -- Sébastien Villemot <sebastien@debian.org>  Fri, 13 Feb 2015 23:31:19 +0100
++
++julia (0.3.2-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.2
++  * Ship new desktop file, SVG icon and appdata file.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 22 Oct 2014 18:42:04 +0200
++
++julia (0.3.1-1) unstable; urgency=medium
++
++  * Imported Upstream version 0.3.1
++  * Fix get-orig-source rule with respect to embedded utf8proc.
++  * No longer embed sphinx-rtd-theme.
++    + Add build-dependency on python-sphinx-rtd-theme.
++    + Drop patch embed-sphinx-rtd-theme.patch.
++  * Bump Standards-Version to 3.9.6, no changes needed.
++  * No longer try the "parallel" test at build time.
++    It always fails in chroots.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 24 Sep 2014 11:56:26 +0200
++
++julia (0.3.0-1) unstable; urgency=medium
++
++  * New upstream release.
++    - no longer breaks on PCRE upgrades. (Closes: #755576)
++    - command-line option "-p" works as expected. (Closes: #758783)
++  * Rewrite get-orig-source in d/rules. In particular no longer embed openlibm,
++    since it is now a separate package.
++  * debian/copyright: reflect upstream changes.
++  * New patches:
++    + do-not-download-utf8proc.patch
++    + inject-ldflags.patch
++    + install-sh-exit-status.patch
++  * Dropped patches:
++    + do-not-download-patchelf.patch (instead build depend on patchelf)
++    + fix-cpu-detection.patch
++    + ld-library-path-for-testing.patch
++    + make-4.0.patch
++    + no-git.patch (instead use "make -C base version_git.jl.phony")
++    + readline-6.3.patch (Julia no longer uses readline)
++    + sysconfdir-install.patch (instead use new make variable)
++    + use-sonames-with-dlopen.patch (not really needed, too difficult to
++      maintain)
++  * Ship the cached binary system image (sys.so).
++  * Compile with MARCH=x86-64 on amd64, and with MARCH=pentium4. In particular,
++    this means that SSE2 is now required on i386, because x87 FPU computing is
++    not supported by upstream and is buggy. Abort nicely if the CPU does have
++    SSE2, and by the way activate SSE2 in dSFMT (require-sse2-on-i386.patch).
++    As a consequence, drop the now unneeded testsuite-i386.patch.
++  * Bump to LLVM 3.5. (Closes: #753971)
++  * Add libopenblas-base to Recommends. Having it first in the BLAS
++    dependency alternative is not enough to ensure that it is installed by
++    default.
++  * Use OpenBLAS for both BLAS and LAPACK, since the Debian package now ships
++    both.
++  * Documentation package (julia-doc):
++    + use dh_sphinxdoc
++    + use packaged Mathjax instead of online version (with
++      use_packaged_mathjax.patch, symbolic links in d/julia-doc.links and
++      appropriate logic in d/rules)
++    + use packaged awesome font
++    + embed sphinx-rtd-theme, since the corresponding package has not yet been
++      accepted in sid (embed-sphinx-rtd-theme.patch)
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 20 Aug 2014 10:51:46 +0000
++
++julia (0.2.1+dfsg-3) unstable; urgency=medium
++
++  * make-4.0.patch: fix FTBFS against make 4.0.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 07 May 2014 15:17:37 +0200
++
++julia (0.2.1+dfsg-2) unstable; urgency=medium
++
++  * readline-6.3.patch: new patch, fixes FTBFS against readline 6.3.
++    (Closes: #741824)
++  * Restrict supported archs to amd64 and i386, it never compiled elsewhere.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 16 Mar 2014 16:25:21 +0100
++
++julia (0.2.1+dfsg-1) unstable; urgency=medium
++
++  * New upstream release.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sat, 15 Feb 2014 21:31:41 +0100
++
++julia (0.2.0+dfsg-6) unstable; urgency=medium
++
++  * Transition to libunwind8-dev. (Closes: #730464)
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sat, 01 Feb 2014 10:18:04 +0100
++
++julia (0.2.0+dfsg-5) unstable; urgency=low
++
++  * Transition to suitesparse 4.2.1.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Mon, 02 Dec 2013 18:38:37 +0100
++
++julia (0.2.0+dfsg-4) unstable; urgency=low
++
++  * Make the parallel.jl test non-fatal.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 24 Nov 2013 15:14:50 +0100
++
++julia (0.2.0+dfsg-3) unstable; urgency=low
++
++  * testsuite-i386.patch: loosen the numerical precision for yet another test.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 17 Nov 2013 19:32:52 +0100
++
++julia (0.2.0+dfsg-2) unstable; urgency=low
++
++  * testsuite-i386.patch: new patches, fixes FTBFS on i386.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 17 Nov 2013 17:51:13 +0100
++
++julia (0.2.0+dfsg-1) unstable; urgency=low
++
++  * New upstream release.
++  * debian/copyright: reflect upstream changes
++  * Update patches:
++    + remove patches applied upstream:
++      - suitesparse-3.4.patch
++      - testsuite-i386.patch
++    + remove fhs.patch, and replace it by the SYSCONFDIR build option.
++    + sysconfdir-install.patch: new patch to make the SYSCONFDIR option work
++      for us.
++    + refresh other patches.
++  * Bump Standards-Version to 3.9.5, no changes needed.
++  * Dependency of julia-dbg on julia is now versioned.
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 17 Nov 2013 12:10:10 +0100
++
++julia (0.2.0~rc2+dfsg-2) unstable; urgency=low
++
++  * Use (older) suitesparse 3.4.
++     + d/control: downgrade (build-)dependencies
++     + use-sonames-with-dlopen.patch: update sonames
++     + suitesparse-3.4.patch: new patch
++  * Downgrade build-dependency to libunwind7-dev (was libunwind8-dev).
++    libunwind8-dev is unlikely to merge to testing soon.
++  * unversioned-system-load-path.patch: new patch.
++    Drops version number from system load path. Versioning unnecessary since
++    this path is managed by dpkg/apt. Moreover, it would make transitions to
++    higher versions needlessly complicated.
++  * testsuite-i386.patch: new patch, fixes testsuite crash on i386.
++  * Use canonical URL for Vcs-* fields
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sun, 03 Nov 2013 16:00:08 +0100
++
++julia (0.2.0~rc2+dfsg-1) experimental; urgency=low
++
++  * New upstream release candidate
++  * Link dynamically against LLVM, this seems to now work correctly
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sat, 26 Oct 2013 04:33:44 +0000
++
++julia (0.2.0~rc1+dfsg-1) experimental; urgency=low
++
++  * New upstream release candidate
++  * Removed patches:
++    + do-not-download-jquery.patch
++    + fix-version.patch
++    + no-webrepl.patch
++    + suitesparse-3.4.patch
++    + use-system-double-conversion.patch
++    + zlib-1.2.8.patch
++  * Added patches:
++    + fhs.patch
++    + no-debug-version.patch
++    + verbose-build.patch
++  * Ship upstream manpage
++  * Ship NEWS.md
++  * Build depend on llvm-3.3-dev
++  * Build depend on libsuitesparse-dev >= 1:4.2.1
++  * Stop distributing PDF documentation, it currently does not build
++  * debian/copyright: reflect upstream changes
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 16 Oct 2013 15:54:13 +0200
++
++julia (0.1.2+dfsg-3) unstable; urgency=low
++
++  * Bump the B-D on dpkg-dev.
++    Support for source:Package and source:Version fields was added in dpkg-dev
++    1.16.2 (Closes: #706470)
++  * Add support for DEB_BUILD_OPTIONS=nocheck (Closes: #706472)
++  * Add julia-dbg package
++  * Fix FTBFS with zlib >= 1.2.8 (Closes: #707962)
++    - zlib-1.2.8.patch: new patch, fixes the gzip.jl test
++    - tighten B-D on zlib1g-dev to >= 1:1.2.8
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 15 May 2013 12:44:14 +0200
++
++julia (0.1.2+dfsg-2) unstable; urgency=low
++
++  * Statically link against LLVM.
++    With dynamic linking, strange bugs appear when the runtime library is not
++    the same than the one used for building. At this stage it is not clear
++    whether it is a Julia or LLVM bug. Reported as Julia issue #2494.
++     - use-shared-llvm.patch: remove patch
++     - add Built-Using field for julia binary package
++     - keep a dependency of julia on libllvm3.2, since strpack.jl dlopen's it
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 03 Apr 2013 17:03:39 +0200
++
++julia (0.1.2+dfsg-1) unstable; urgency=low
++
++  * Imported Upstream version 0.1.2+dfsg.
++    Contains hotfix for package manager.
++  * debian/patches/fix-version.patch: new patch
++  * Refresh other patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Thu, 07 Mar 2013 20:50:18 +0100
++
++julia (0.1.1+dfsg-1) unstable; urgency=low
++
++  * Imported Upstream version 0.1.1+dfsg
++  * debian/copyright: reflect upstream changes
++  * Refresh patches
++  * Disable tk-wrapper, since it is no longer built upstream
++  * Update README.debian
++
++ -- Sébastien Villemot <sebastien@debian.org>  Thu, 07 Mar 2013 12:14:59 +0100
++
++julia (0.1+dfsg-1) unstable; urgency=low
++
++  * First upstream release!
++  * debian/copyright: document how to recreate orig tarball
++  * Add a debian/watch file
++  * d/rules, d/p/no-git-patch: adapt for numbered releases.
++    In particular, add a COMMITSHA file in the orig tarball containing the
++    SHA of the release tag.
++  * Promote zlib1g and libarpack2 to Depends
++  * Fix typo in manpage
++
++ -- Sébastien Villemot <sebastien@debian.org>  Thu, 14 Feb 2013 12:00:05 +0100
++
++julia (0.1~20130213.git4bc33bbc-1) unstable; urgency=low
++
++  * New upstream release candidate.
++    Hopefully obviates the need of ugly hacks in libuv in order to build on
++    build daemons.
++  * Remove obsolete patches:
++     + bump-version-0.1.patch
++     + disable-final-uv-loop.patch
++     + revert-stdin-file-iostream.patch
++  * Refresh other patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 13 Feb 2013 10:58:23 +0100
++
++julia (0.1~20130212.gitf375d4bb-1) unstable; urgency=low
++
++  * New upstream snapshot.
++  * no-git.patch: simplify and improve patch
++  * gsvddense_blasint.patch: remove patch, applied upstream
++  * New patches:
++      + bump-version-0.1.patch
++      + disable-final-uv-loop.patch
++      + revert-stdin-file-iostream.patch
++  * Refresh other patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Tue, 12 Feb 2013 12:02:24 +0100
++
++julia (0.1~20130211.git86fbe98d-1) unstable; urgency=low
++
++  * New upstream snapshot.
++  * debian/control:
++     + add git to Recommends (for Julia package manager)
++     + remove dependencies on libglpk-dev (it moved to its own package)
++     + add explicit dependency on libgmp10 (there is no more a wrapper)
++  * fix-clean-rules.patch: remove patch, applied upstream
++  * gsvddense_blasint.patch: new patch
++  * Refresh other patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Mon, 11 Feb 2013 03:51:26 +0100
++
++julia (0.0.0+20130206.git32ff5759-1) unstable; urgency=low
++
++  * New upstream snapshot.
++  * debian/copyright: reflect upstream changes
++  * debian/rules: update get-orig-source to reflect upstream changes
++     + Don't ship nginx
++     + Adapt for new configure-random target in deps/Makefile
++  * Enable build of Tk wrapper.
++     + debian/control: add build dependency on tk-dev
++     + debian/rules: add tk rule to build-arch
++  * debian/julia.install: install VERSION and COMMIT files
++  * no-webrepl.patch: new patch
++  * Refresh other patches
++  * Add source override for config.status file under deps/random/
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 06 Feb 2013 17:54:29 +0100
++
++julia (0.0.0+20130107.gitd9656f41-2) unstable; urgency=low
++
++  * fix-cpu-detection.patch: do not use -momit-leaf-frame-pointer on non-x86
++    archs
++  * Upgrade to LLVM 3.2.
++     + debian/control: bump build-dependency
++     + debian/rules: use llvm-config-3.2
++     + debian/patches/use-shared-llvm.patch
++       debian/patches/use-sonames-with-dlopen.patch: update patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Sat, 19 Jan 2013 15:33:43 +0100
++
++julia (0.0.0+20130107.gitd9656f41-1) unstable; urgency=low
++
++  * New upstream snashot
++  * No longer try to rebuild helpdb.jl.
++     + debian/rules: remove helpdb.jl from build-arch rule
++     + debian/control: move back python-sphinx to Build-Depends-Indep
++  * debian/copyright: reflect upstream changes
++  * Add Build-Conflicts on libatlas3-base (makes linalg tests fail)
++  * debian/rules: replace obsolete USE_DEBIAN makeflag by a list of
++    USE_SYSTEM_* flags
++  * debian/rules: on non-x86 systems, use libm instead of openlibm
++  * dpkg-buildflags.patch: remove patch, applied upstream
++  * Refreshed other patches
++
++ -- Sébastien Villemot <sebastien@debian.org>  Wed, 16 Jan 2013 12:29:42 +0100
++
++julia (0.0.0+20121214.gitdced1f7-1) unstable; urgency=low
++
++  * New upstream snapshot.
++  * debian/copyright: reflect upstream changes
++  * Embedded libuv no longer uses libc-ares and libev.
++     + debian/control: remove them from build-dependencies
++     + debian/rules: no longer strip them from upstream tarball
++     + use-system-{ev,c-ares}.patch: remove patches
++  * Remove other patches merged upstream or no longer necessary
++     + fhs-multiarch.patch
++     + linalg-test-tolerance.patch
++     + remove-rpath.patch
++     + verbose-build.patch
++  * New patches
++     + do-not-download-patchelf.patch
++     + ld-library-path-for-testing.patch
++     + dpkg-multiarch.patch
++     + libjulia-release-drop-soname.patch
++  * Refresh other patches
++  * debian/rules:
++     + compile with MULTIARCH_INSTALL=1
++     + build helpdb.jl as part of the build-arch rule
++     + abort on failures in extra tests
++  * debian/control: move python-sphinx to Build-Depends (now used in build-arch)
++
++ -- Sébastien Villemot <sebastien@debian.org>  Tue, 18 Dec 2012 14:42:23 +0100
++
++julia (0.0.0+20121102.git63e93f2-1) unstable; urgency=low
++
++  * Initial release. (Closes: #691912)
++
++ -- Sébastien Villemot <sebastien@debian.org>  Fri, 02 Nov 2012 16:29:29 +0100
diff --cc debian/clean
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c29dd698911abf0d1fd5ad6f7d6a9320bc5bf044
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++deps/libuv/Makefile
++deps/libuv/config.log
++deps/libuv/config.status
++deps/libuv/libtool
++deps/libuv/libuv.pc
++src/*.dwo
++base/version_git.jl
diff --cc debian/compat
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b4de3947675361a7770d29b8982c407b0ec6b2a0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++11
diff --cc debian/control
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0523cb5addd95b42ba6274b4836d6d62d205608b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,164 @@@
++Source: julia
++Section: science
++Homepage: https://julialang.org
++Priority: optional
++Standards-Version: 4.3.0
++Vcs-Git: https://salsa.debian.org/julia-team/julia.git
++Vcs-Browser: https://salsa.debian.org/julia-team/julia
++Maintainer: Debian Julia Team <pkg-julia-devel@lists.alioth.debian.org>
++Uploaders: Peter Colberg <peter@colberg.org>,
++           Graham Inggs <ginggs@debian.org>,
++           Mo Zhou <cdluminate@gmail.com>,
++Build-Depends:
++ cmake, python3,
++ curl,
++ debhelper (>= 11~),
++ dpkg-dev (>= 1.16.2~),
++ libblas-dev | libblas.so,
++ libcurl4-gnutls-dev | libcurl-dev,
++ libdsfmt-dev (>= 2.2.3),
++ libgit2-dev (>= 0.27.0~),
++ libgmp-dev,
++ liblapack-dev | liblapack.so,
++ libmbedtls-dev,
++ libmpfr-dev,
++ libopenblas-dev [amd64 arm64 armhf i386 kfreebsd-amd64 kfreebsd-i386 mips64el ppc64el s390x],
++ libopenlibm-dev (>= 0.4.1+dfsg-4~) [any-i386 any-amd64 arm64 armhf mips mips64el mipsel powerpc ppc64 ppc64el],
++ libpcre2-dev (>= 10.20-3~),
++ libsuitesparse-dev (>= 1:4.4.5),
++ libunwind8-dev [!s390x],
++ libutf8proc-dev (>= 2.1.1),
++ openssl,
++ unicode-data,
++Build-Depends-Indep:
++ latexmk,
++ texlive,
++ texlive-extra-utils,
++ texlive-fonts-extra,
++ texlive-latex-base,
++ texlive-latex-extra,
++ texlive-latex-recommended,
++ texlive-luatex,
++ texlive-plain-generic,
++ python3-pygments,
++ python3-pkg-resources,
++ fonts-lato,
++
++Package: julia
++Architecture: any
++Multi-Arch: foreign
++Pre-Depends: ${misc:Pre-Depends}
++Depends: julia-common (= ${source:Version}),
++         libjulia1 (= ${binary:Version}),
++         ${misc:Depends},
++         ${shlibs:Depends},
++Replaces: julia-common (<< 0.5.0~)
++Breaks: julia-common (<< 0.5.0~)
++Suggests: ess (>= 12.09-1~), julia-doc, vim-julia,
++Recommends: git, openssl,
++Description: high-performance programming language for technical computing
++ Julia is a high-level, high-performance dynamic programming language for
++ technical computing, with syntax that is familiar to users of other technical
++ computing environments. It provides a sophisticated compiler, distributed
++ parallel execution, numerical accuracy, and an extensive mathematical function
++ library. The library, mostly written in Julia itself, also integrates mature,
++ best-of-breed C and Fortran libraries for linear algebra, random number
++ generation, FFTs, and string processing. Julia programs are organized around
++ defining functions, and overloading them for different combinations of
++ argument types (which can also be user-defined).
++ .
++ This package provides a complete Julia installation (JIT compiler, standard
++ library, text-based user interface).
++
++Package: libjulia1
++Section: libs
++Architecture: any
++Pre-Depends: ${misc:Pre-Depends}
++Replaces: julia (<< 0.5.0~), libjulia0.6, libjulia0.7
++Breaks: julia (<< 0.5.0~), libjulia0.6, libjulia0.7
++Depends: ${misc:Depends}, ${shlibs:Depends},
++ libopenblas-base [amd64 arm64 armhf i386 kfreebsd-amd64 kfreebsd-i386 mips64el ppc64el s390x]
++ | libatlas3-base [amd64 arm64 armel armhf hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x]
++ | libmkl-rt [amd64 i386],
++ libopenblas-dev [amd64 arm64 armhf i386 kfreebsd-amd64 kfreebsd-i386 mips64el ppc64el s390x]
++ | libatlas-base-dev [amd64 arm64 armel armhf hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel ppc64el s390x]
++ | libmkl-dev [amd64 i386],
++Description: high-performance programming language for technical computing (runtime library)
++ Julia is a high-level, high-performance dynamic programming language for
++ technical computing, with syntax that is familiar to users of other technical
++ computing environments. It provides a sophisticated compiler, distributed
++ parallel execution, numerical accuracy, and an extensive mathematical function
++ library. The library, mostly written in Julia itself, also integrates mature,
++ best-of-breed C and Fortran libraries for linear algebra, random number
++ generation, FFTs, and string processing. Julia programs are organized around
++ defining functions, and overloading them for different combinations of
++ argument types (which can also be user-defined).
++ .
++ This package provides the Julia runtime library.
++
++Package: julia-common
++Architecture: all
++Multi-Arch: foreign
++Depends: ${misc:Depends}
++Replaces: julia (<< 0.4.1-1~)
++Breaks: julia (<< 0.4.1-1~)
++Recommends: julia
++Description: high-performance programming language for technical computing (common files)
++ Julia is a high-level, high-performance dynamic programming language for
++ technical computing, with syntax that is familiar to users of other technical
++ computing environments. It provides a sophisticated compiler, distributed
++ parallel execution, numerical accuracy, and an extensive mathematical function
++ library. The library, mostly written in Julia itself, also integrates mature,
++ best-of-breed C and Fortran libraries for linear algebra, random number
++ generation, FFTs, and string processing. Julia programs are organized around
++ defining functions, and overloading them for different combinations of
++ argument types (which can also be user-defined).
++ .
++ This package contains the Julia standard library and test suite.
++
++Package: libjulia-dev
++Section: libdevel
++Architecture: any
++Depends: libjulia1 (= ${binary:Version}), ${misc:Depends}
++Description: high-performance programming language for technical computing (development)
++ Julia is a high-level, high-performance dynamic programming language for
++ technical computing, with syntax that is familiar to users of other technical
++ computing environments. It provides a sophisticated compiler, distributed
++ parallel execution, numerical accuracy, and an extensive mathematical function
++ library. The library, mostly written in Julia itself, also integrates mature,
++ best-of-breed C and Fortran libraries for linear algebra, random number
++ generation, FFTs, and string processing. Julia programs are organized around
++ defining functions, and overloading them for different combinations of
++ argument types (which can also be user-defined).
++ .
++ This package provides the Julia runtime headers.
++
++Package: julia-doc
++Architecture: all
++Multi-Arch: foreign
++Section: doc
++Depends: ${misc:Depends},
++         fonts-font-awesome,
++         fonts-inconsolata,
++         libjs-jquery,
++         libjs-jquery-ui,
++         libjs-mathjax,
++         libjs-highlight.js,
++         libjs-requirejs,
++         libjs-lodash,
++         node-normalize.css,
++         node-highlight.js,
++Suggests: julia
++Description: high-performance programming language for technical computing (documentation)
++ Julia is a high-level, high-performance dynamic programming language for
++ technical computing, with syntax that is familiar to users of other technical
++ computing environments. It provides a sophisticated compiler, distributed
++ parallel execution, numerical accuracy, and an extensive mathematical function
++ library. The library, mostly written in Julia itself, also integrates mature,
++ best-of-breed C and Fortran libraries for linear algebra, random number
++ generation, FFTs, and string processing. Julia programs are organized around
++ defining functions, and overloading them for different combinations of
++ argument types (which can also be user-defined).
++ .
++ This package contains the Julia manual, which describes the language and its
++ standard library. It also contains example Julia programs.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cb4e5d097dc13463e81f0442533f532c4e7852e3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,775 @@@
++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
++Upstream-Name: Julia
++Source: https://julialang.org
++Files-Excluded:
++  contrib/windows/7zS.sfx
++
++Files: *
++Copyright: 2009-2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah
++           and other contributors: https://github.com/JuliaLang/julia/contributors
++License: Expat
++
++Files: base/grisu/bignum.jl
++       base/grisu/bignums.jl
++       base/grisu/fastfixed.jl
++       base/grisu/fastprecision.jl
++       base/grisu/fastshortest.jl
++       base/grisu/float.jl
++Copyright: 2006-2014, the V8 project authors.
++License: BSD-3-clause
++
++Files: base/special/exp.jl
++       base/special/hyperbolic.jl
++       base/special/rem_pio2.jl
++       base/special/trig.jl
++Copyright: 1993, 2004, Sun Microsystems, Inc.
++           2009-2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah
++           and other contributors: https://github.com/JuliaLang/julia/contributors
++License: Expat
++
++Files: stdlib/REPL/src/TerminalMenus/*
++Copyright: 2017 Nick Paul
++License: Expat
++
++Files: stdlib/SHA/*
++Copyright: 2014 Elliot Saba
++License: Expat
++
++Files: contrib/julia.appdata.xml
++Copyright: 2014, Paul Lange <palango@gmx.de>
++License: CC-BY-SA-3.0
++
++Files: src/abi_llvm.cpp
++       src/abi_ppc64le.cpp
++       src/abi_win32.cpp
++       src/abi_win64.cpp
++       src/abi_x86.cpp
++       src/abi_x86_64.cpp
++Copyright: 2007-2012, LDC Team.
++License: BSD-3-clause
++
++Files: src/support/END.h
++       src/support/ENTRY.amd64.h
++       src/support/ENTRY.i387.h
++       src/support/_longjmp.win32.S
++       src/support/_setjmp.win32.S
++Copyright: 1990, The Regents of the University of California. / William Jolitz
++License: BSD-3-clause
++
++Files: src/support/MurmurHash3.c
++       src/support/MurmurHash3.h
++Copyright: none
++License: public-domain-murmurhash
++ MurmurHash3 was written by Austin Appleby, and is placed in the public
++ domain. The author hereby disclaims copyright to this source code.
++
++Files: src/support/asprintf.c
++Copyright: 1997 Todd C. Miller <Todd.Miller AT courtesan.com>
++           2004 Darren Tucker
++License: ISC
++
++Files: src/flisp/flisp.c
++       src/flisp/system.lsp
++Copyright: 2009 Jeff Bezanson
++License: BSD-3-clause
++
++Files: src/support/dirname.c
++Copyright: 2012, 2013 MinGW.org project
++License: Expat
++
++Files: src/getopt.c
++       src/getopt.h
++Copyright: 2005-2014, Rich Felker, et al.
++License: Expat
++
++Files: src/support/strptime.c
++Copyright: 1997-1998, 2005, 2008, The NetBSD Foundation, Inc.
++License: BSD-2-clause
++
++Files: src/disasm.cpp
++Copyright: 2009-2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah
++License: Expat
++Comment: Original code comes from The LLVM Compiler Infrastructure.
++         Modified by Julia developers.
++
++Files: src/support/strtod.c
++Copyright: 2009-2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah
++License: Expat
++Comment: Portions derived from the Python function _PyOS_ascii_strtod
++         Copyright 2001-2014 Python Software Foundation
++
++Files: src/crc32c.c
++Copyright: 2013, Mark Adler <madler@alumni.caltech.edu>
++License: Zlib
++
++Files: src/support/tzfile.h
++Copyright: NONE
++License: public-domain-tzfile
++ This file is in the public domain,
++ so clarified as of 1996-06-05 by Arthur David Olson.   
++
++Files: deps/gfortblas.c
++Copyright: 2013 JuliaLang Project / Jameson Nash
++License: Expat
++
++Files: deps/valgrind/valgrind.h
++Copyright: 2000-2013, Julian Seward.
++License: BSD-3-clause
++
++Files: deps/patches/llvm-D31524-sovers_4.0.patch
++Copyright: 2017 Rebecca N. Palmer <rebecca_palmer@zoho.com>
++           2017 Lisandro Damían Nicanor Pérez Meyer <lisandro@debian.org>
++           2017 Sylvestre Ledru <sylvestre@debian.org>
++License: U-OF-I-BSD-LIKE
++Comment: License copied from Sylvestre Ledru <sylvestre@debian.org>'s
++         copyright file from llvm-toolchain-4.0 source.
++
++Files: debian/*
++Copyright: 2012-2015 Sébastien Villemot <sebastien@debian.org>
++           2015-2017 Graham Inggs <ginggs@debian.org>
++           2015-2017 Peter Colberg <peter@colberg.org>
++           2018      Mo Zhou <cdluminate@gmail.com>
++License: Expat
++
++Files: debian/embedded/Pkg*
++Copyright: 2017 Stefan Karpinski
++           2017 SimonDanisch
++           2016 Art Wild
++License: Expat
++
++Files: debian/embedded/DocStringExtensions.jl*/*
++Copyright: 2016 Michael Hatherly
++License: Expat
++
++Files: debian/embedded/Documenter.jl*/*
++Copyright: 2016 Michael Hatherly
++License: Expat
++Comment:
++ Files: debian/embedded/Documenter.jl*/assets/html/search.js
++ Copyright: Steven Levithan <stevenlevithan.com>
++ License: Expat
++
++# Just a tiny library written for Julia. Maybe no need to package separately.
++Files: debian/embedded/libwhich-81e9723c0273d78493dc8c8ed570f68d9ce7e89e.tar.gz
++Copyright: 2017 Jameson Nash
++License: Expat
++
++Files: debian/embedded/llvm*
++Copyright: 2003-2017 University of Illinois at Urbana-Champaign.
++License: U-OF-I-BSD-LIKE
++
++Files: debian/embedded/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e.tar.gz
++Copyright: Joyent, Inc. and other Node contributors
++           2013 Ben Noordhuis <info@bnoordhuis.nl>
++           StrongLoop, Inc.
++License: Expat
++Comment: Copyright for files contained in this tarball
++ Files: docs/src/sphinx-plugins/manpage.py
++ Copyright: 2013, Dariusz Dwornikowski.
++ License: Apache-2.0
++ .
++ Files: config.guess
++        config.sub
++ Copyright: 1992-2014, Free Software Foundation, Inc.
++ License: GPL-3+
++ .
++ Files: include/pthread-fixes.h
++        src/unix/pthread-fixes.c
++ Copyright: 2012, Google Inc.
++            2013, Sony Mobile Communications AB
++ License: BSD-3-clause
++ .
++ Files: Makefile.am
++        Makefile.mingw
++        autogen.sh
++        checksparse.sh
++        configure.ac
++        src/heap-inl.h
++        src/queue.h
++        src/unix/atomic-ops.h
++        src/unix/spinlock.h
++        test/test-loop-configure.c
++        test/test-pipe-set-non-blocking.c
++ Copyright: 2013-2015, Ben Noordhuis <info@bnoordhuis.nl>
++ License: ISC
++ .
++ Files: samples/socks5-proxy/Makefile
++        samples/socks5-proxy/build.gyp
++        samples/socks5-proxy/client.c
++        samples/socks5-proxy/defs.h
++        samples/socks5-proxy/main.c
++        samples/socks5-proxy/s5.c
++        samples/socks5-proxy/s5.h
++        samples/socks5-proxy/server.c
++        samples/socks5-proxy/util.c
++ Copyright: StrongLoop, Inc.
++ License: Expat
++ .
++ Files: test/test-pipe-connect-multiple.c
++        test/test-pipe-connect-prepare.c
++        test/test-pipe-pending-instances.c
++        test/test-tcp-create-socket-early.c
++        test/test-udp-create-socket-early.c
++ Copyright: 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
++ License: Expat
++ .
++ Files: ar-lib
++        compile
++        depcomp
++        ltmain.sh
++        missing
++ Copyright: 1996-2014, Free Software Foundation, Inc.
++ License: GPL-2+
++ .
++ Files: m4/ltoptions.m4
++        m4/ltsugar.m4
++        m4/lt~obsolete.m4
++ Copyright: 2004-2015, Free Software Foundation, Inc.
++ License: FSFULLR
++ .
++ Files: src/inet.c
++ Copyright: 2004 Internet Systems Consortium, Inc. ("ISC")
++            1996-1999 Internet Software Consortium
++ License: ISC
++ .
++ Files: include/stdint-msvc2008.h
++ Copyright: 2006-2008 Alexander Chemeris
++ License: BSD-3-clause
++ .
++ Files: samples/socks5-proxy/getopt.c
++ Copyright: 1987, 1993, 1994 The Regents of the University of California / NetBSD
++ License: BSD-3-clause
++ .
++ Files: include/tree.h
++ Copyright: 2002 Niels Provos <provos@citi.umich.edu>
++ License: BSD-2-clause
++ .
++ Files: include/android-ifaddrs.h
++        src/unix/android-ifaddrs.c
++ Copyright: 1995, 1999 Berkeley Software Design, Inc.
++            2013 Kenneth MacKay
++            2014 Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016)
++ License: BSD-2-clause
++
++License: Expat
++ Permission is hereby granted, free of charge, to any person obtaining
++ a copy of this software and associated documentation files (the
++ "Software"), to deal in the Software without restriction, including
++ without limitation the rights to use, copy, modify, merge, publish,
++ distribute, sublicense, and/or sell copies of the Software, and to
++ permit persons to whom the Software is furnished to do so, subject to
++ the following conditions:
++ .
++ The above copyright notice and this permission notice shall be
++ included in all copies or substantial portions of the Software.
++ .
++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++
++License: BSD-2-clause
++ Redistribution and use in source and binary forms, with or without
++ modification, are permitted provided that the following conditions are
++ met:
++    * Redistributions of source code must retain the above copyright
++      notice, this list of conditions and the following disclaimer.
++ .
++    * Redistributions in binary form must reproduce the above
++      copyright notice, this list of conditions and the following
++      disclaimer in the documentation and/or other materials provided
++      with the distribution.
++ .
++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++License: BSD-3-clause
++ Redistribution and use in source and binary forms, with or without
++ modification, are permitted provided that the following conditions
++ are met:
++ 1. Redistributions of source code must retain the above copyright
++    notice, this list of conditions and the following disclaimer.
++ 2. Redistributions in binary form must reproduce the above copyright
++    notice, this list of conditions and the following disclaimer in the
++    documentation and/or other materials provided with the distribution.
++ 3. Neither the name of the author nor the names of any contributors
++    may be used to endorse or promote products derived from this software
++    without specific prior written permission.
++ .
++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++License: ISC
++ Permission to use, copy, modify, and distribute this software for any
++ purpose with or without fee is hereby granted, provided that the above
++ copyright notice and this permission notice appear in all copies.
++ .
++ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++License: FSFUL
++ This configure script is free software; the Free Software Foundation
++ gives unlimited permission to copy, distribute and modify it.
++
++License: FSFULLR
++ This file is free software; the Free Software Foundation gives
++ unlimited permission to copy and/or distribute it, with or without
++ modifications, as long as this notice is preserved.
++
++License: CC-BY-SA-3.0
++ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
++ SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT
++ RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS"
++ BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION
++ PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. 
++ .
++ License
++ .
++ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
++ COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
++ COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
++ AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
++ .
++ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO
++ BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE
++ CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
++ HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
++ .
++ 1. Definitions
++    "Adaptation" means a work based upon the Work, or upon the Work and
++    other pre-existing works, such as a translation, adaptation, derivative
++    work, arrangement of music or other alterations of a literary or
++    artistic work, or phonogram or performance and includes cinematographic
++    adaptations or any other form in which the Work may be recast,
++    transformed, or adapted including in any form recognizably derived from
++    the original, except that a work that constitutes a Collection will not
++    be considered an Adaptation for the purpose of this License. For the
++    avoidance of doubt, where the Work is a musical work, performance or
++    phonogram, the synchronization of the Work in timed-relation with a
++    moving image ("synching") will be considered an Adaptation for the
++    purpose of this License.
++    "Collection" means a collection of literary or artistic works, such as
++    encyclopedias and anthologies, or performances, phonograms or
++    broadcasts, or other works or subject matter other than works listed in
++    Section 1(f) below, which, by reason of the selection and arrangement of
++    their contents, constitute intellectual creations, in which the Work is
++    included in its entirety in unmodified form along with one or more other
++    contributions, each constituting separate and independent works in
++    themselves, which together are assembled into a collective whole. A work
++    that constitutes a Collection will not be considered an Adaptation (as
++    defined below) for the purposes of this License.
++    "Creative Commons Compatible License" means a license that is listed at
++    http://creativecommons.org/compatiblelicenses that has been approved by
++    Creative Commons as being essentially equivalent to this License,
++    including, at a minimum, because that license: (i) contains terms that
++    have the same purpose, meaning and effect as the License Elements of
++    this License; and, (ii) explicitly permits the relicensing of
++    adaptations of works made available under that license under this
++    License or a Creative Commons jurisdiction license with the same License
++    Elements as this License.
++    "Distribute" means to make available to the public the original and
++    copies of the Work or Adaptation, as appropriate, through sale or other
++    transfer of ownership.
++    "License Elements" means the following high-level license attributes as
++    selected by Licensor and indicated in the title of this License:
++    Attribution, ShareAlike.
++    "Licensor" means the individual, individuals, entity or entities that
++    offer(s) the Work under the terms of this License.
++    "Original Author" means, in the case of a literary or artistic work, the
++    individual, individuals, entity or entities who created the Work or if
++    no individual or entity can be identified, the publisher; and in
++    addition (i) in the case of a performance the actors, singers,
++    musicians, dancers, and other persons who act, sing, deliver, declaim,
++    play in, interpret or otherwise perform literary or artistic works or
++    expressions of folklore; (ii) in the case of a phonogram the producer
++    being the person or legal entity who first fixes the sounds of a
++    performance or other sounds; and, (iii) in the case of broadcasts, the
++    organization that transmits the broadcast.
++    "Work" means the literary and/or artistic work offered under the terms
++    of this License including without limitation any production in the
++    literary, scientific and artistic domain, whatever may be the mode or
++    form of its expression including digital form, such as a book, pamphlet
++    and other writing; a lecture, address, sermon or other work of the same
++    nature; a dramatic or dramatico-musical work; a choreographic work or
++    entertainment in dumb show; a musical composition with or without words;
++    a cinematographic work to which are assimilated works expressed by a
++    process analogous to cinematography; a work of drawing, painting,
++    architecture, sculpture, engraving or lithography; a photographic work
++    to which are assimilated works expressed by a process analogous to
++    photography; a work of applied art; an illustration, map, plan, sketch
++    or three-dimensional work relative to geography, topography,
++    architecture or science; a performance; a broadcast; a phonogram; a
++    compilation of data to the extent it is protected as a copyrightable
++    work; or a work performed by a variety or circus performer to the extent
++    it is not otherwise considered a literary or artistic work.
++    "You" means an individual or entity exercising rights under this License
++    who has not previously violated the terms of this License with respect
++    to the Work, or who has received express permission from the Licensor to
++    exercise rights under this License despite a previous violation.
++    "Publicly Perform" means to perform public recitations of the Work and
++    to communicate to the public those public recitations, by any means or
++    process, including by wire or wireless means or public digital
++    performances; to make available to the public Works in such a way that
++    members of the public may access these Works from a place and at a place
++    individually chosen by them; to perform the Work to the public by any
++    means or process and the communication to the public of the performances
++    of the Work, including by public digital performance; to broadcast and
++    rebroadcast the Work by any means including signs, sounds or images.
++    "Reproduce" means to make copies of the Work by any means including
++    without limitation by sound or visual recordings and the right of
++    fixation and reproducing fixations of the Work, including storage of a
++    protected performance or phonogram in digital form or other electronic
++    medium.
++ .
++ 2. Fair Dealing Rights. Nothing in this License is intended to reduce,
++ limit, or restrict any uses free from copyright or rights arising from
++ limitations or exceptions that are provided for in connection with the
++ copyright protection under copyright law or other applicable laws.
++ .
++ 3. License Grant. Subject to the terms and conditions of this License,
++ Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
++ perpetual (for the duration of the applicable copyright) license to
++ exercise the rights in the Work as stated below:
++ .
++    to Reproduce the Work, to incorporate the Work into one or more
++    Collections, and to Reproduce the Work as incorporated in the
++    Collections;
++    to create and Reproduce Adaptations provided that any such Adaptation,
++    including any translation in any medium, takes reasonable steps to
++    clearly label, demarcate or otherwise identify that changes were made to
++    the original Work. For example, a translation could be marked "The
++    original work was translated from English to Spanish," or a modification
++    could indicate "The original work has been modified.";
++    to Distribute and Publicly Perform the Work including as incorporated in
++    Collections; and,
++    to Distribute and Publicly Perform Adaptations.
++ .
++    For the avoidance of doubt:
++      Non-waivable Compulsory License Schemes. In those jurisdictions in
++      which the right to collect royalties through any statutory or
++      compulsory licensing scheme cannot be waived, the Licensor reserves
++      the exclusive right to collect such royalties for any exercise by
++      You of the rights granted under this License;
++      Waivable Compulsory License Schemes. In those jurisdictions in which
++      the right to collect royalties through any statutory or compulsory
++      licensing scheme can be waived, the Licensor waives the exclusive
++      right to collect such royalties for any exercise by You of the
++      rights granted under this License; and,
++      Voluntary License Schemes. The Licensor waives the right to collect
++      royalties, whether individually or, in the event that the Licensor
++      is a member of a collecting society that administers voluntary
++      licensing schemes, via that society, from any exercise by You of the
++      rights granted under this License.
++ .
++ The above rights may be exercised in all media and formats whether now
++ known or hereafter devised. The above rights include the right to make such
++ modifications as are technically necessary to exercise the rights in other
++ media and formats. Subject to Section 8(f), all rights not expressly
++ granted by Licensor are hereby reserved.
++ .
++ 4. Restrictions. The license granted in Section 3 above is expressly made
++ subject to and limited by the following restrictions:
++ .
++    You may Distribute or Publicly Perform the Work only under the terms of
++    this License. You must include a copy of, or the Uniform Resource
++    Identifier (URI) for, this License with every copy of the Work You
++    Distribute or Publicly Perform. You may not offer or impose any terms on
++    the Work that restrict the terms of this License or the ability of the
++    recipient of the Work to exercise the rights granted to that recipient
++    under the terms of the License. You may not sublicense the Work. You
++    must keep intact all notices that refer to this License and to the
++    disclaimer of warranties with every copy of the Work You Distribute or
++    Publicly Perform. When You Distribute or Publicly Perform the Work, You
++    may not impose any effective technological measures on the Work that
++    restrict the ability of a recipient of the Work from You to exercise the
++    rights granted to that recipient under the terms of the License. This
++    Section 4(a) applies to the Work as incorporated in a Collection, but
++    this does not require the Collection apart from the Work itself to be
++    made subject to the terms of this License. If You create a Collection,
++    upon notice from any Licensor You must, to the extent practicable,
++    remove from the Collection any credit as required by Section 4(c), as
++    requested. If You create an Adaptation, upon notice from any Licensor
++    You must, to the extent practicable, remove from the Adaptation any
++    credit as required by Section 4(c), as requested.
++    You may Distribute or Publicly Perform an Adaptation only under the
++    terms of: (i) this License; (ii) a later version of this License with
++    the same License Elements as this License; (iii) a Creative Commons
++    jurisdiction license (either this or a later license version) that
++    contains the same License Elements as this License (e.g.,
++    Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
++    License. If you license the Adaptation under one of the licenses
++    mentioned in (iv), you must comply with the terms of that license. If
++    you license the Adaptation under the terms of any of the licenses
++    mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
++    comply with the terms of the Applicable License generally and the
++    following provisions: (I) You must include a copy of, or the URI for,
++    the Applicable License with every copy of each Adaptation You Distribute
++    or Publicly Perform; (II) You may not offer or impose any terms on the
++    Adaptation that restrict the terms of the Applicable License or the
++    ability of the recipient of the Adaptation to exercise the rights
++    granted to that recipient under the terms of the Applicable License;
++    (III) You must keep intact all notices that refer to the Applicable
++    License and to the disclaimer of warranties with every copy of the Work
++    as included in the Adaptation You Distribute or Publicly Perform; (IV)
++    when You Distribute or Publicly Perform the Adaptation, You may not
++    impose any effective technological measures on the Adaptation that
++    restrict the ability of a recipient of the Adaptation from You to
++    exercise the rights granted to that recipient under the terms of the
++    Applicable License. This Section 4(b) applies to the Adaptation as
++    incorporated in a Collection, but this does not require the Collection
++    apart from the Adaptation itself to be made subject to the terms of the
++    Applicable License.
++    If You Distribute, or Publicly Perform the Work or any Adaptations or
++    Collections, You must, unless a request has been made pursuant to
++    Section 4(a), keep intact all copyright notices for the Work and
++    provide, reasonable to the medium or means You are utilizing: (i) the
++    name of the Original Author (or pseudonym, if applicable) if supplied,
++    and/or if the Original Author and/or Licensor designate another party or
++    parties (e.g., a sponsor institute, publishing entity, journal) for
++    attribution ("Attribution Parties") in Licensor's copyright notice,
++    terms of service or by other reasonable means, the name of such party or
++    parties; (ii) the title of the Work if supplied; (iii) to the extent
++    reasonably practicable, the URI, if any, that Licensor specifies to be
++    associated with the Work, unless such URI does not refer to the
++    copyright notice or licensing information for the Work; and (iv) ,
++    consistent with Ssection 3(b), in the case of an Adaptation, a credit
++    identifying the use of the Work in the Adaptation (e.g., "French
++    translation of the Work by Original Author," or "Screenplay based on
++    original Work by Original Author"). The credit required by this Section
++    4(c) may be implemented in any reasonable manner; provided, however,
++    that in the case of a Adaptation or Collection, at a minimum such credit
++    will appear, if a credit for all contributing authors of the Adaptation
++    or Collection appears, then as part of these credits and in a manner at
++    least as prominent as the credits for the other contributing authors.
++    For the avoidance of doubt, You may only use the credit required by this
++    Section for the purpose of attribution in the manner set out above and,
++    by exercising Your rights under this License, You may not implicitly or
++    explicitly assert or imply any connection with, sponsorship or
++    endorsement by the Original Author, Licensor and/or Attribution Parties,
++    as appropriate, of You or Your use of the Work, without the separate,
++    express prior written permission of the Original Author, Licensor and/or
++    Attribution Parties.
++    Except as otherwise agreed in writing by the Licensor or as may be
++    otherwise permitted by applicable law, if You Reproduce, Distribute or
++    Publicly Perform the Work either by itself or as part of any Adaptations
++    or Collections, You must not distort, mutilate, modify or take other
++    derogatory action in relation to the Work which would be prejudicial to
++    the Original Author's honor or reputation. Licensor agrees that in those
++    jurisdictions (e.g. Japan), in which any exercise of the right granted
++    in Section 3(b) of this License (the right to make Adaptations) would be
++    deemed to be a distortion, mutilation, modification or other derogatory
++    action prejudicial to the Original Author's honor and reputation, the
++    Licensor will waive or not assert, as appropriate, this Section, to the
++    fullest extent permitted by the applicable national law, to enable You
++    to reasonably exercise Your right under Section 3(b) of this License
++    (right to make Adaptations) but not otherwise.
++ .
++ 5. Representations, Warranties and Disclaimer
++ .
++ UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
++ OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
++ KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
++ INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
++ FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT
++ OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER
++ OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF
++ IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
++ .
++ 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
++ LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY
++ SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING
++ OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
++ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
++ .
++ 7. Termination
++ .
++    This License and the rights granted hereunder will terminate
++    automatically upon any breach by You of the terms of this License.
++    Individuals or entities who have received Adaptations or Collections
++    from You under this License, however, will not have their licenses
++    terminated provided such individuals or entities remain in full
++    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
++    survive any termination of this License.
++    Subject to the above terms and conditions, the license granted here is
++    perpetual (for the duration of the applicable copyright in the Work).
++    Notwithstanding the above, Licensor reserves the right to release the
++    Work under different license terms or to stop distributing the Work at
++    any time; provided, however that any such election will not serve to
++    withdraw this License (or any other license that has been, or is
++    required to be, granted under the terms of this License), and this
++    License will continue in full force and effect unless terminated as
++    stated above.
++ .
++ 8. Miscellaneous
++ .
++    Each time You Distribute or Publicly Perform the Work or a Collection,
++    the Licensor offers to the recipient a license to the Work on the same
++    terms and conditions as the license granted to You under this License.
++    Each time You Distribute or Publicly Perform an Adaptation, Licensor
++    offers to the recipient a license to the original Work on the same terms
++    and conditions as the license granted to You under this License.
++    If any provision of this License is invalid or unenforceable under
++    applicable law, it shall not affect the validity or enforceability of
++    the remainder of the terms of this License, and without further action
++    by the parties to this agreement, such provision shall be reformed to
++    the minimum extent necessary to make such provision valid and
++    enforceable.
++    No term or provision of this License shall be deemed waived and no
++    breach consented to unless such waiver or consent shall be in writing
++    and signed by the party to be charged with such waiver or consent.
++    This License constitutes the entire agreement between the parties with
++    respect to the Work licensed here. There are no understandings,
++    agreements or representations with respect to the Work not specified
++    here. Licensor shall not be bound by any additional provisions that may
++    appear in any communication from You. This License may not be modified
++    without the mutual written agreement of the Licensor and You.
++    The rights granted under, and the subject matter referenced, in this
++    License were drafted utilizing the terminology of the Berne Convention
++    for the Protection of Literary and Artistic Works (as amended on
++    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
++    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and
++    the Universal Copyright Convention (as revised on July 24, 1971). These
++    rights and subject matter take effect in the relevant jurisdiction in
++    which the License terms are sought to be enforced according to the
++    corresponding provisions of the implementation of those treaty
++    provisions in the applicable national law. If the standard suite of
++    rights granted under applicable copyright law includes additional rights
++    not granted under this License, such additional rights are deemed to be
++    included in the License; this License is not intended to restrict the
++    license of any rights under applicable law.
++
++License: Apache-2.0
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ You may obtain a copy of the License at
++ .
++ http://www.apache.org/licenses/LICENSE-2.0
++ .
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++ .
++ On Debian systems, the complete text of the Apache version 2.0 license
++ can be found in "/usr/share/common-licenses/Apache-2.0".
++
++License: GPL-2+
++ This package is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++ .
++ This package is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU General Public License for more details.
++ .
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>
++ .
++ On Debian systems, the complete text of the GNU General
++ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
++
++License: GPL-3+
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++ .
++ This package is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU General Public License for more details.
++ .
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++ .
++ On Debian systems, the complete text of the GNU General
++ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
++
++License: Zlib
++ This software is provided 'as-is', without any express or implied
++ warranty.  In no event will the authors be held liable for any damages
++ arising from the use of this software.
++ .
++ Permission is granted to anyone to use this software for any purpose,
++ including commercial applications, and to alter it and redistribute it
++ freely, subject to the following restrictions:
++ .
++ 1. The origin of this software must not be misrepresented; you must not
++    claim that you wrote the original software. If you use this software
++    in a product, an acknowledgment in the product documentation would be
++    appreciated but is not required.
++ 2. Altered source versions must be plainly marked as such, and must not be
++    misrepresented as being the original software.
++ 3. This notice may not be removed or altered from any source distribution.
++
++License: U-OF-I-BSD-LIKE
++ ==============================================================================
++ LLVM Release License
++ ==============================================================================
++ University of Illinois/NCSA
++ Open Source License
++ .
++ Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
++ All rights reserved.
++ .
++ Developed by:
++ .
++     LLVM Team
++ .
++     University of Illinois at Urbana-Champaign
++ .
++     http://llvm.org
++ .
++ Permission is hereby granted, free of charge, to any person obtaining a copy of
++ this software and associated documentation files (the "Software"), to deal with
++ the Software without restriction, including without limitation the rights to
++ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
++ of the Software, and to permit persons to whom the Software is furnished to do
++ so, subject to the following conditions:
++ .
++     * Redistributions of source code must retain the above copyright notice,
++       this list of conditions and the following disclaimers.
++ .
++     * Redistributions in binary form must reproduce the above copyright notice,
++       this list of conditions and the following disclaimers in the
++       documentation and/or other materials provided with the distribution.
++ .
++     * Neither the names of the LLVM Team, University of Illinois at
++       Urbana-Champaign, nor the names of its contributors may be used to
++       endorse or promote products derived from this Software without specific
++       prior written permission.
++ .
++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
++ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
++ CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
++ SOFTWARE.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..945c9b46d684f08ec84cb316e1dc0061e361f794
new file mode 120000 (symlink)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..945c9b46d684f08ec84cb316e1dc0061e361f794
new file mode 120000 (symlink)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9a1a272b3d2c5eef26cac0ab28d73de63286c8ae
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e4c57c5c0919485b21392cb8d6ad6bae7edf1bb
new file mode 120000 (symlink)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++DocStringExtensions.jl-0.5.0
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..69cb76019a474330e99666f147ecb85e44de1ce6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++comment: false
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c95f6755d5b0b58c7d050c9fa5f300ff845cc5f1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++language: julia
++
++os:
++  - linux
++  - osx
++
++sudo: false
++
++julia:
++  - 0.7
++  - 1.0
++  - nightly
++
++notifications:
++  email: false
++
++after_success:
++  - julia test/coverage.jl
++
++jobs:
++  include:
++    - stage: "Deploy docs"
++      julia: 1.0
++      os: linux
++      script:
++        - julia -e 'using Pkg; Pkg.add([PackageSpec("Documenter"), PackageSpec(path=pwd())])'
++        - julia docs/make.jl
++      after_success: skip
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..14fb2fa1081e22be38e84c974d1acb3d6245de95
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++The DocStringExtensions.jl package is licensed under the MIT "Expat" License:
++
++> Copyright (c) 2016: Michael Hatherly.
++> 
++> Permission is hereby granted, free of charge, to any person obtaining a copy
++> of this software and associated documentation files (the "Software"), to deal
++> in the Software without restriction, including without limitation the rights
++> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++> copies of the Software, and to permit persons to whom the Software is
++> furnished to do so, subject to the following conditions:
++> 
++> The above copyright notice and this permission notice shall be included in all
++> copies or substantial portions of the Software.
++> 
++> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++> SOFTWARE.
++> 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..658e7aba2424381b6588ee1fc68466fdd36d0dfd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,49 @@@
++# DocStringExtensions
++
++*Extensions for Julia's docsystem.*
++
++| **Documentation**                                                               | **Build Status**                                                                                |
++|:-------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|
++| [![][docs-stable-img]][docs-stable-url] [![][docs-latest-img]][docs-latest-url] | [![][travis-img]][travis-url] [![][appveyor-img]][appveyor-url] [![][codecov-img]][codecov-url] |
++
++## Installation
++
++The package can be added using the Julia package manager. From the Julia REPL, type `]`
++to enter the Pkg REPL mode and run
++
++```
++pkg> add DocStringExtensions
++```
++
++## Documentation
++
++- [**STABLE**][docs-stable-url] &mdash; **most recently tagged version of the documentation.**
++- [**LATEST**][docs-latest-url] &mdash; *in-development version of the documentation.*
++
++## Project Status
++
++The package is tested and developed against Julia `0.7` and `1.0` on Linux, OS X, and Windows,
++but there are versions of the package that works on older versions of Julia.
++
++## Contributing and Questions
++
++Contributions are very welcome, as are feature requests and suggestions. Please open an [issue][issues-url] if you encounter any problems. If you have a question then feel free to ask for help in the [Gitter chat room][gitter-url].
++
++[gitter-url]: https://gitter.im/juliadocs/users
++
++[docs-latest-img]: https://img.shields.io/badge/docs-latest-blue.svg
++[docs-latest-url]: https://juliadocs.github.io/DocStringExtensions.jl/latest
++
++[docs-stable-img]: https://img.shields.io/badge/docs-stable-blue.svg
++[docs-stable-url]: https://juliadocs.github.io/DocStringExtensions.jl/stable
++
++[travis-img]: https://travis-ci.org/JuliaDocs/DocStringExtensions.jl.svg?branch=master
++[travis-url]: https://travis-ci.org/JuliaDocs/DocStringExtensions.jl
++
++[appveyor-img]: https://ci.appveyor.com/api/projects/status/7bixd69chxps91wx/branch/master?svg=true
++[appveyor-url]: https://ci.appveyor.com/project/JuliaDocs/docstringextensions-jl/branch/master
++
++[codecov-img]: https://codecov.io/gh/JuliaDocs/DocStringExtensions.jl/branch/master/graph/badge.svg
++[codecov-url]: https://codecov.io/gh/JuliaDocs/DocStringExtensions.jl
++
++[issues-url]: https://github.com/JuliaDocs/DocStringExtensions.jl/issues
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..859ad4616a2d7e7a241ead96a29a129bc2ce410b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++julia 0.7
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c2588f1d886186a7cce312654d17bb1df4ec4067
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++environment:
++  matrix:
++  - julia_version: 0.7
++  - julia_version: 1
++  - julia_version: nightly
++
++platform:
++  - x86 # 32-bit
++  - x64 # 64-bit
++
++# # Uncomment the following lines to allow failures on nightly julia
++# # (tests will run but not make your overall status red)
++# matrix:
++#   allow_failures:
++#   - julia_version: nightly
++
++branches:
++  only:
++    - master
++    - /release-.*/
++
++notifications:
++  - provider: Email
++    on_build_success: false
++    on_build_failure: false
++    on_build_status_changed: false
++
++install:
++  - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))
++
++build_script:
++  - echo "%JL_BUILD_SCRIPT%"
++  - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"
++
++test_script:
++  - echo "%JL_TEST_SCRIPT%"
++  - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"
++
++# # Uncomment to support code coverage upload. Should only be enabled for packages
++# # which would have coverage gaps without running on Windows
++# on_success:
++#   - echo "%JL_CODECOV_SCRIPT%"
++#   - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..41bc0783b2c815e437804dfd03924b305dd009e0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++using Documenter, DocStringExtensions
++
++makedocs(
++    sitename = "DocStringExtensions.jl",
++    modules = [DocStringExtensions],
++    format = :html,
++    clean = false,
++    pages = Any["Home" => "index.md"],
++)
++
++deploydocs(
++    target = "build",
++    deps = nothing,
++    make = nothing,
++    repo = "github.com/JuliaDocs/DocStringExtensions.jl.git",
++    julia = "1.0",
++)
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c0c8a1be405a1b348389887d404f1cf15e10b81
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b87fdce26bfcbae0eafd789536df21f4a4e1c2b4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++# DocStringExtensions
++
++```@docs
++DocStringExtensions
++```
++
++## Index
++
++```@index
++Modules = [DocStringExtensions]
++```
++
++## Reference
++
++```@autodocs
++Modules = [DocStringExtensions]
++Order = [:constant, :function, :macro, :type]
++```
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9cc96d7a028d2a4c7c24fa9087d581c562f380c8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,110 @@@
++__precompile__(true)
++
++"""
++*Extensions for the Julia docsystem.*
++
++# Introduction
++
++This package provides a collection of useful extensions for Julia's built-in docsystem.
++These are features that are still regarded as "experimental" and not yet mature enough to be
++considered for inclusion in `Base`, or that have sufficiently niche use cases that including
++them with the default Julia installation is not seen as valuable enough at this time.
++
++Currently `DocStringExtensions.jl` exports a collection of so-called "abbreviations", which
++can be used to add useful automatically generated information to docstrings. These include
++information such as:
++
++  * simplified method signatures;
++  * documentation for the individual fields of composite types;
++  * import and export lists for modules;
++  * and source-linked lists of methods applicable to a particular docstring.
++
++Users are most welcome to suggest additional abbreviation ideas, or implement and submit
++them themselves. Julia's strong support for program introspection makes this a reasonably
++straight forward process.
++
++Details of the currently available abbreviations can be viewed in their individual
++docstrings listed below in the "Exports" section.
++
++# Examples
++
++In simple terms an abbreviation can be used by simply interpolating it into a suitable
++docstring. For example:
++
++```julia
++using DocStringExtensions
++
++\"""
++A short summary of `func`...
++
++\$(SIGNATURES)
++
++where `x` and `y` should both be positive.
++
++# Details
++
++Some details about `func`...
++\"""
++func(x, y) = x + y
++```
++
++`\$(SIGNATURES)` will be replaced in the above docstring with
++
++````markdown
++# Signatures
++
++```julia
++func(x, y)
++```
++````
++
++The resulting generated content can be viewed via Julia's `?` mode or, if `Documenter.jl` is
++set up, the generated external documentation.
++
++The advantage of using [`SIGNATURES`](@ref) (and other abbreviations) is that docstrings are
++less likely to become out-of-sync with the surrounding code. Note though that references to
++the argument names `x` and `y` that have been manually embedded within the docstring are, of
++course, not updated automatically.
++
++# Exports
++$(EXPORTS)
++
++# Imports
++$(IMPORTS)
++
++"""
++module DocStringExtensions
++
++# Exports.
++
++export @template, FIELDS, EXPORTS, METHODLIST, IMPORTS, SIGNATURES, TYPEDEF, DOCSTRING, FUNCTIONNAME
++
++# Includes.
++
++include("utilities.jl")
++include("abbreviations.jl")
++include("templates.jl")
++
++#
++# Bootstrap abbreviations.
++#
++# Within the package itself we would like to be able to use the abbreviations that have been
++# implemented. To do this we need to delay evaluation of the interpolated abbreviations
++# until they have all been defined. We use `Symbol`s in place of the actual constants, such
++# as `METHODLIST` which is written as `:METHODLIST` instead.
++#
++# The docstring for the module itself, defined at the start of the file, does not need to
++# use `Symbol`s since with the way `@doc` works the module docstring gets inserted at the
++# end of the module definition and so has all the definitions already defined.
++#
++let λ = s -> isa(s, Symbol) ? getfield(DocStringExtensions, s) : s
++    for (binding, multidoc) in Docs.meta(DocStringExtensions)
++        for (typesig, docstr) in multidoc.docs
++            docstr.text = Core.svec(map(λ, docstr.text)...)
++        end
++    end
++end
++
++__init__() = (hook!(template_hook); nothing)
++
++end # module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b669aa6e6bfd30e0ffc9d2de8770374a3e28e4dc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,467 @@@
++
++#
++# Abstract Interface.
++#
++
++"""
++Abbreviation objects are used to automatically generate context-dependent markdown content
++within documentation strings. Objects of this type interpolated into docstrings will be
++expanded automatically before parsing the text to markdown.
++
++$(:FIELDS)
++"""
++abstract type Abbreviation end
++
++"""
++$(:SIGNATURES)
++
++Expand the [`Abbreviation`](@ref) `abbr` in the context of the `DocStr` `doc` and write
++the resulting markdown-formatted text to the `IOBuffer` `buf`.
++"""
++format(abbr, buf, doc) = error("`format` not implemented for `$typeof(abbr)`.")
++
++# Only extend `formatdoc` once with our abstract type. Within the package use a different
++# `format` function instead to keep things decoupled from `Base` as much as possible.
++Docs.formatdoc(buf::IOBuffer, doc::Docs.DocStr, part::Abbreviation) = format(part, buf, doc)
++
++
++#
++# Implementations.
++#
++
++
++#
++# `TypeFields`
++#
++
++"""
++The singleton type for [`FIELDS`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct TypeFields <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) to include the names of the fields of a type as well as any
++documentation that may be attached to the fields.
++
++# Examples
++
++The generated markdown text should look similar to to following example where a
++type has three fields (`x`, `y`, and `z`) and the last two have documentation
++attached.
++
++```markdown
++
++  - `x`
++
++  - `y`
++
++    Unlike the `x` field this field has been documented.
++
++  - `z`
++
++    Another documented field.
++```
++"""
++const FIELDS = TypeFields()
++
++function format(::TypeFields, buf, doc)
++    local docs = get(doc.data, :fields, Dict())
++    local binding = doc.data[:binding]
++    local object = Docs.resolve(binding)
++    # On 0.7 fieldnames() on an abstract type throws an error. We then explicitly return
++    # an empty vector to be consistent with the behaviour on v0.6.
++    local fields = isabstracttype(object) ? Symbol[] : fieldnames(object)
++    if !isempty(fields)
++        println(buf)
++        for field in fields
++            print(buf, "  - `", field, "`\n")
++            # Print the field docs if they exist and aren't a `doc"..."` docstring.
++            if haskey(docs, field) && isa(docs[field], AbstractString)
++                println(buf)
++                for line in split(docs[field], "\n")
++                    println(buf, isempty(line) ? "" : "    ", rstrip(line))
++                end
++            end
++            println(buf)
++        end
++        println(buf)
++    end
++    return nothing
++end
++
++
++#
++# `ModuleExports`
++#
++
++"""
++The singleton type for [`EXPORTS`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct ModuleExports <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) to include all the exported names of a module is a sorted list of
++`Documenter.jl`-style `@ref` links.
++
++!!! note
++
++    The names are sorted alphabetically and ignore leading `@` characters so that macros are
++    *not* sorted before other names.
++
++# Examples
++
++The markdown text generated by the `EXPORTS` abbreviation looks similar to the following:
++
++```markdown
++
++  - [`bar`](@ref)
++  - [`@baz`](@ref)
++  - [`foo`](@ref)
++
++```
++"""
++const EXPORTS = ModuleExports()
++
++function format(::ModuleExports, buf, doc)
++    local binding = doc.data[:binding]
++    local object = Docs.resolve(binding)
++    local exports = names(object)
++    if !isempty(exports)
++        println(buf)
++        # Sorting ignores the `@` in macro names and sorts them in with others.
++        for sym in sort(exports, by = s -> lstrip(string(s), '@'))
++            # Skip the module itself, since that's always exported.
++            sym === nameof(object) && continue
++            # We print linked names using Documenter.jl cross-reference syntax
++            # for ease of integration with that package.
++            println(buf, "  - [`", sym, "`](@ref)")
++        end
++        println(buf)
++    end
++    return nothing
++end
++
++
++#
++# `ModuleImports`
++#
++
++"""
++The singleton type for [`IMPORTS`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct ModuleImports <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) to include all the imported modules in a sorted list.
++
++# Examples
++
++The markdown text generated by the `IMPORTS` abbreviation looks similar to the following:
++
++```markdown
++
++  - `Foo`
++  - `Bar`
++  - `Baz`
++
++```
++"""
++const IMPORTS = ModuleImports()
++
++function format(::ModuleImports, buf, doc)
++    local binding = doc.data[:binding]
++    local object = Docs.resolve(binding)
++    local imports = unique(ccall(:jl_module_usings, Any, (Any,), object))
++    if !isempty(imports)
++        println(buf)
++        for mod in sort(imports, by = string)
++            println(buf, "  - `", mod, "`")
++        end
++        println(buf)
++    end
++end
++
++
++#
++# `MethodList`
++#
++
++"""
++The singleton type for [`METHODLIST`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct MethodList <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) for including a list of all the methods that match a documented
++`Method`, `Function`, or `DataType` within the current module.
++
++# Examples
++
++The generated markdown text will look similar to the following example where a function
++`f` defines two different methods (one that takes a number, and the other a string):
++
++````markdown
++```julia
++f(num)
++```
++
++defined at [`<path>:<line>`](<github-url>).
++
++```julia
++f(str)
++```
++
++defined at [`<path>:<line>`](<github-url>).
++````
++"""
++const METHODLIST = MethodList()
++
++function format(::MethodList, buf, doc)
++    local binding = doc.data[:binding]
++    local typesig = doc.data[:typesig]
++    local modname = doc.data[:module]
++    local func = Docs.resolve(binding)
++    local groups = methodgroups(func, typesig, modname; exact = false)
++    if !isempty(groups)
++        println(buf)
++        for group in groups
++            println(buf, "```julia")
++            for method in group
++                printmethod(buf, binding, func, method)
++                println(buf)
++            end
++            println(buf, "```\n")
++            if !isempty(group)
++                local method = group[1]
++                local file = string(method.file)
++                local line = method.line
++                local path = cleanpath(file)
++                local URL = url(method)
++                isempty(URL) || println(buf, "defined at [`$path:$line`]($URL).")
++            end
++            println(buf)
++        end
++        println(buf)
++    end
++    return nothing
++end
++
++
++#
++# `MethodSignatures`
++#
++
++"""
++The singleton type for [`SIGNATURES`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct MethodSignatures <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) for including a simplified representation of all the method
++signatures that match the given docstring. See [`printmethod`](@ref) for details on
++the simplifications that are applied.
++
++# Examples
++
++The generated markdown text will look similar to the following example where a function `f`
++defines method taking two positional arguments, `x` and `y`, and two keywords, `a` and the `b`.
++
++````markdown
++```julia
++f(x, y; a, b...)
++```
++````
++"""
++const SIGNATURES = MethodSignatures()
++
++function format(::MethodSignatures, buf, doc)
++    local binding = doc.data[:binding]
++    local typesig = doc.data[:typesig]
++    local modname = doc.data[:module]
++    local func = Docs.resolve(binding)
++    local groups = methodgroups(func, typesig, modname)
++    if !isempty(groups)
++        println(buf)
++        println(buf, "```julia")
++        for group in groups
++            for method in group
++                printmethod(buf, binding, func, method)
++                println(buf)
++            end
++        end
++        println(buf, "\n```\n")
++    end
++end
++
++#
++# `FunctionName`
++#
++
++"""
++The singleton type for [`FUNCTIONNAME`](@ref) abbreviations.
++
++$(:FIELDS)
++"""
++struct FunctionName <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) for including the function name matching the method of
++the docstring.
++
++# Usage
++
++This is mostly useful for not repeating the function name in docstrings where
++the user wants to retain full control of the argument list, or the latter does
++not exist (eg generic functions).
++
++Note that the generated docstring snippet is not quoted, use indentation or
++explicit quoting.
++
++# Example
++
++```julia
++\"""
++    \$(FUNCTIONNAME)(d, θ)
++
++Calculate the logdensity `d` at `θ`.
++
++Users should define their own methods for `$(FUNCTIONNAME)`.
++\"""
++function logdensity end
++```
++"""
++const FUNCTIONNAME = FunctionName()
++
++format(::FunctionName, buf, doc) = print(buf, doc.data[:binding].var)
++
++#
++# `TypeSignature`
++#
++
++"""
++The singleton type for [`TYPEDEF`](@ref) abbreviations.
++"""
++struct TypeDefinition <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) for including a summary of the signature of a type definition.
++Some of the following information may be included in the output:
++
++  * whether the object is an `abstract` type or a `bitstype`;
++  * mutability (either `type` or `struct` is printed);
++  * the unqualified name of the type;
++  * any type parameters;
++  * the supertype of the type if it is not `Any`.
++
++# Examples
++
++The generated output for a type definition such as:
++
++```julia
++\"""
++\$(TYPEDEF)
++\"""
++struct MyType{S, T <: Integer} <: AbstractArray
++    # ...
++end
++```
++
++will look similar to the following:
++
++````markdown
++```julia
++struct MyType{S, T<:Integer} <: AbstractArray
++```
++````
++
++!!! note
++
++    No information about the fields of the type is printed. Use the [`FIELDS`](@ref)
++    abbreviation to include information about the fields of a type.
++"""
++const TYPEDEF = TypeDefinition()
++
++function print_supertype(buf, object)
++    super = supertype(object)
++    super != Any && print(buf, " <: ", super)
++end
++
++function print_params(buf, object)
++    if !isempty(object.parameters)
++        print(buf, "{")
++        join(buf, object.parameters, ", ")
++        print(buf, "}")
++    end
++end
++
++function print_primitive_type(buf, object)
++    print(buf, "primitive type ", object.name.name)
++    print_supertype(buf, object)
++    print(buf, " ", sizeof(object) * 8)
++    println(buf)
++end
++
++function print_abstract_type(buf, object)
++    print(buf, "abstract type ", object.name.name)
++    print_supertype(buf, object)
++    println(buf)
++end
++
++function print_mutable_struct_or_struct(buf, object)
++    object.mutable && print(buf, "mutable ")
++    print(buf, "struct ", object.name.name)
++    print_params(buf, object)
++    print_supertype(buf, object)
++    println(buf)
++end
++
++@static if VERSION < v"0.7.0"
++    isprimitivetype(x) = isbitstype(x)
++end
++
++function format(::TypeDefinition, buf, doc)
++    local binding = doc.data[:binding]
++    local object = gettype(Docs.resolve(binding))
++    if isa(object, DataType)
++        println(buf, "\n```julia")
++        if isprimitivetype(object)
++            print_primitive_type(buf, object)
++        elseif isabstracttype(object)
++            print_abstract_type(buf, object)
++        else
++            print_mutable_struct_or_struct(buf, object)
++        end
++        println(buf, "```\n")
++    end
++end
++
++#
++# `DocStringTemplate`
++#
++
++"""
++The singleton type for [`DOCSTRING`](@ref) abbreviations.
++"""
++struct DocStringTemplate <: Abbreviation end
++
++"""
++An [`Abbreviation`](@ref) used in [`@template`](@ref) definitions to represent the location
++of the docstring body that should be spliced into a template.
++
++!!! warning
++
++    This abbreviation must only ever be used in template strings; never normal docstrings.
++"""
++const DOCSTRING = DocStringTemplate()
++
++# NOTE: no `format` needed for this 'mock' abbreviation.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..77bdc7bf25107be0f2fddf26092951cb2501e50b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,151 @@@
++const expander = Core.atdoc
++const setter! = Core.atdoc!
++
++"""
++$(:SIGNATURES)
++
++Set the docstring expander function to first call `func` before calling the default expander.
++
++To remove a hook that has been applied using this method call [`hook!()`](@ref).
++"""
++hook!(func) = setter!((args...) -> expander(func(args...)...))
++
++"""
++$(:SIGNATURES)
++
++Reset the docstring expander to only call the default expander function. This clears any
++'hook' that has been set using [`hook!(func)`](@ref).
++"""
++hook!() = setter!(expander)
++
++"""
++$(:SIGNATURES)
++
++Defines a docstring template that will be applied to all docstrings in a module that match
++the specified category or tuple of categories.
++
++# Examples
++
++```julia
++@template DEFAULT =
++    \"""
++    \$(SIGNATURES)
++    \$(DOCSTRING)
++    \"""
++```
++
++`DEFAULT` is the default template that is applied to a docstring if no other template
++definitions match the documented expression. The `DOCSTRING` abbreviation is used to mark
++the location in the template where the actual docstring body will be spliced into each
++docstring.
++
++```julia
++@template (FUNCTIONS, METHODS, MACROS) =
++    \"""
++    \$(SIGNATURES)
++    \$(DOCSTRING)
++    \$(METHODLIST)
++    \"""
++```
++
++A tuple of categories can be specified when a docstring template should be used for several
++different categories.
++
++```julia
++@template MODULES = ModName
++```
++
++The template definition above will define a template for module docstrings based on the
++template for modules found in module `ModName`.
++
++!!! note
++
++    Supported categories are `DEFAULT`, `FUNCTIONS`, `METHODS`, `MACROS`, `TYPES`,
++    `MODULES`, and `CONSTANTS`.
++
++"""
++macro template(ex)
++    # JuliaLang/julia#22064 introduced the __module__ variable and deprecated current_module()
++    @static if VERSION >= v"0.7.0-DEV.484"
++        template(__source__, __module__, ex)
++    else
++        template(LineNumberNode(0), current_module(), ex)
++    end
++end
++
++const TEMP_SYM = gensym("templates")
++
++function template(src::LineNumberNode, mod::Module, ex::Expr)
++    Meta.isexpr(ex, :(=), 2) || error("invalid `@template` syntax.")
++    template(src, mod, ex.args[1], ex.args[2])
++end
++
++function template(source::LineNumberNode, mod::Module, tuple::Expr, docstr::Union{Symbol, Expr})
++    Meta.isexpr(tuple, :tuple) || error("invalid `@template` syntax on LHS.")
++    isdefined(mod, TEMP_SYM) || Core.eval(mod, :(const $(TEMP_SYM) = $(Dict{Symbol, Vector}())))
++    local block = Expr(:block)
++    for category in tuple.args
++        local key = Meta.quot(category)
++        local vec = Meta.isexpr(docstr, :string) ?
++            Expr(:vect, docstr.args...) : :($(docstr).$(TEMP_SYM)[$(key)])
++        push!(block.args, :($(TEMP_SYM)[$(key)] = $(vec)))
++    end
++    push!(block.args, nothing)
++    return esc(block)
++end
++
++function template(src::LineNumberNode, mod::Module, sym::Symbol, docstr::Union{Symbol, Expr})
++    template(src, mod, Expr(:tuple, sym), docstr)
++end
++
++# The signature for the atdocs() calls changed in v0.7
++# On v0.6 and below it seems it was assumed to be (docstr::String, expr::Expr), but on v0.7
++# it is (source::LineNumberNode, mod::Module, docstr::String, expr::Expr)
++function template_hook(source::LineNumberNode, mod::Module, docstr, expr::Expr)
++    local docex = interp_string(docstr)
++    if isdefined(mod, TEMP_SYM) && Meta.isexpr(docex, :string)
++        local templates = getfield(mod, TEMP_SYM)
++        local template = get_template(templates, expression_type(expr))
++        local out = Expr(:string)
++        for t in template
++            t == DOCSTRING ? append!(out.args, docex.args) : push!(out.args, t)
++        end
++        return (source, mod, out, expr)
++    else
++        return (source, mod, docstr, expr)
++    end
++end
++
++function template_hook(docstr, expr::Expr)
++    source, mod, docstr, expr::Expr = template_hook(LineNumberNode(0), current_module(), docstr, expr)
++    docstr, expr
++end
++
++template_hook(args...) = args
++
++interp_string(str::AbstractString) = Expr(:string, str)
++interp_string(other) = other
++
++get_template(t::Dict, k::Symbol) = haskey(t, k) ? t[k] : get(t, :DEFAULT, Any[DOCSTRING])
++
++function expression_type(ex::Expr)
++    # Expression heads changed in JuliaLang/julia/pull/23157 to match the new keyword syntax.
++    if VERSION < v"0.7.0-DEV.1263" && Meta.isexpr(ex, [:type, :bitstype])
++        :TYPES
++    elseif Meta.isexpr(ex, :module)
++        :MODULES
++    elseif Meta.isexpr(ex, [:struct, :abstract, :typealias, :primitive])
++        :TYPES
++    elseif Meta.isexpr(ex, :macro)
++        :MACROS
++    elseif Meta.isexpr(ex, [:function, :(=)]) && Meta.isexpr(ex.args[1], :call) || (Meta.isexpr(ex.args[1], :where) && Meta.isexpr(ex.args[1].args[1], :call))
++        :METHODS
++    elseif Meta.isexpr(ex, :function)
++        :FUNCTIONS
++    elseif Meta.isexpr(ex, [:const, :(=)])
++        :CONSTANTS
++    else
++        :DEFAULT
++    end
++end
++expression_type(other) = :DEFAULT
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..947e2a817b319da4f228de1d17894f462fe6aa2d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,342 @@@
++
++#
++# Utilities.
++#
++
++#
++# Method grouping.
++#
++
++"""
++$(:SIGNATURES)
++
++Group all methods of function `func` with type signatures `typesig` in module `modname`.
++Keyword argument `exact = true` matches signatures "exactly" with `==` rather than `<:`.
++
++# Examples
++
++```julia
++groups = methodgroups(f, Union{Tuple{Any}, Tuple{Any, Integer}}, Main; exact = false)
++```
++"""
++function methodgroups(func, typesig, modname; exact = true)
++    # Group methods by file and line number.
++    local methods = getmethods(func, typesig)
++    local groups = groupby(Tuple{Symbol, Int}, Vector{Method}, methods) do m
++        (m.file, m.line), m
++    end
++
++    # Filter out methods from other modules and with non-matching signatures.
++    local typesigs = alltypesigs(typesig)
++    local results = Vector{Method}[]
++    for (key, group) in groups
++        filter!(group) do m
++            local ismod = m.module == modname
++            exact ? (ismod && Base.rewrap_unionall(Base.tuple_type_tail(m.sig), m.sig) in typesigs) : ismod
++        end
++        isempty(group) || push!(results, group)
++    end
++
++    # Sort the groups by file and line.
++    sort!(results, lt = comparemethods, by = first)
++
++    return results
++end
++
++"""
++$(:SIGNATURES)
++
++Compare methods `a` and `b` by file and line number.
++"""
++function comparemethods(a::Method, b::Method)
++    comp = a.file < b.file ? -1 : a.file > b.file ? 1 : 0
++    comp == 0 ? a.line < b.line : comp < 0
++end
++
++if isdefined(Base, :UnionAll)
++    uniontypes(T) = uniontypes!(Any[], T)
++    function uniontypes!(out, T)
++        if isa(T, Union)
++            push!(out, T.a)
++            uniontypes!(out, T.b)
++        else
++            push!(out, T)
++        end
++        return out
++    end
++    gettype(T::UnionAll) = gettype(T.body)
++else
++    uniontypes(T) = collect(T.types)
++end
++gettype(other) = other
++
++"""
++$(:SIGNATURES)
++
++A helper method for [`getmethods`](@ref) that collects methods in `results`.
++"""
++function getmethods!(results, f, sig)
++    if sig == Union{}
++        append!(results, methods(f))
++    elseif isa(sig, Union)
++        for each in uniontypes(sig)
++            getmethods!(results, f, each)
++        end
++    elseif isa(sig, UnionAll)
++        getmethods!(results, f, Base.unwrap_unionall(sig))
++    else
++        append!(results, methods(f, sig))
++    end
++    return results
++end
++"""
++$(:SIGNATURES)
++
++Collect and return all methods of function `f` matching signature `sig`.
++
++This is similar to `methods(f, sig)`, but handles type signatures found in `DocStr` objects
++more consistently that `methods`.
++"""
++getmethods(f, sig) = unique(getmethods!(Method[], f, sig))
++
++
++"""
++$(:SIGNATURES)
++
++Is the type `t` a `bitstype`?
++"""
++isbitstype(@nospecialize(t)) = isconcretetype(t) && sizeof(t) > 0 && isbits(t)
++
++"""
++$(:SIGNATURES)
++
++Is the type `t` an `abstract` type?
++"""
++isabstracttype(@nospecialize(t)) = isa(t, DataType) && getfield(t, :abstract)
++
++
++"""
++$(:SIGNATURES)
++
++Returns a `Vector` of the `Tuple` types contained in `sig`.
++"""
++function alltypesigs(sig)::Vector{Any}
++    if sig == Union{}
++        Any[]
++    elseif isa(sig, Union)
++        uniontypes(sig)
++    elseif isa(sig, UnionAll)
++        Base.rewrap_unionall.(uniontypes(Base.unwrap_unionall(sig)), sig)
++    else
++        Any[sig]
++    end
++end
++
++"""
++$(:SIGNATURES)
++
++A helper method for [`groupby`](@ref) that uses a pre-allocated `groups` `Dict`.
++"""
++function groupby!(f, groups, data)
++    for each in data
++        key, value = f(each)
++        push!(get!(groups, key, []), value)
++    end
++    return sort!(collect(groups), by = first)
++end
++
++"""
++$(:SIGNATURES)
++
++Group `data` using function `f` where key type is specified by `K` and group type by `V`.
++
++The function `f` takes a single argument, an element of `data`, and should return a 2-tuple
++of `(computed_key, element)`. See the example below for details.
++
++# Examples
++
++```julia
++groupby(Int, Vector{Int}, collect(1:10)) do num
++    mod(num, 3), num
++end
++```
++"""
++groupby(f, K, V, data) = groupby!(f, Dict{K, V}(), data)
++
++"""
++$(:SIGNATURES)
++
++Remove the `Pkg.dir` part of a file `path` if it exists.
++"""
++function cleanpath(path::AbstractString)
++    for depot in DEPOT_PATH
++        pkgdir = joinpath(depot, "")
++        startswith(path, pkgdir) && return first(split(path, pkgdir, keepempty=false))
++    end
++    return path
++end
++
++"""
++$(:SIGNATURES)
++
++Parse all docstrings defined within a module `mod`.
++"""
++function parsedocs(mod::Module)
++    for (binding, multidoc) in Docs.meta(mod)
++        for (typesig, docstr) in multidoc.docs
++            Docs.parsedoc(docstr)
++        end
++    end
++end
++
++
++"""
++$(:SIGNATURES)
++
++Print a simplified representation of a method signature to `buffer`. Some of these
++simplifications include:
++
++  * no `TypeVar`s;
++  * no types;
++  * no keyword default values;
++  * `?` printed where `#unused#` arguments are found.
++
++# Examples
++
++```julia
++f(x; a = 1, b...) = x
++sig = printmethod(Docs.Binding(Main, :f), f, first(methods(f)))
++```
++"""
++function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Method)
++    # TODO: print qualified?
++    print(buffer, binding.var)
++    print(buffer, "(")
++    join(buffer, arguments(method), ", ")
++    local kws = keywords(func, method)
++    if !isempty(kws)
++        print(buffer, "; ")
++        join(buffer, kws, ", ")
++    end
++    print(buffer, ")")
++    return buffer
++end
++
++printmethod(b, f, m) = String(take!(printmethod(IOBuffer(), b, f, m)))
++
++get_method_source(m::Method) = Base.uncompressed_ast(m)
++nargs(m::Method) = m.nargs
++
++
++"""
++$(:SIGNATURES)
++
++Returns the list of keywords for a particular method `m` of a function `func`.
++
++# Examples
++
++```julia
++f(x; a = 1, b...) = x
++kws = keywords(f, first(methods(f)))
++```
++"""
++function keywords(func, m::Method)
++    local table = methods(func).mt
++    # table is a MethodTable object. For some reason, the :kwsorter field is not always
++    # defined. An undefined kwsorter seems to imply that there are no methods in the
++    # MethodTable with keyword arguments.
++    if isdefined(table, :kwsorter)
++        # Fetching method keywords stolen from base/replutil.jl:572-576 (commit 3b45cdc9aab0):
++        local kwargs = Base.kwarg_decl(m, typeof(table.kwsorter))
++        if isa(kwargs, Vector) && length(kwargs) > 0
++            filter!(arg -> !occursin("#", string(arg)), kwargs)
++            # Keywords *may* not be sorted correctly. We move the vararg one to the end.
++            local index = findfirst(arg -> endswith(string(arg), "..."), kwargs)
++            if index != nothing
++                kwargs[index], kwargs[end] = kwargs[end], kwargs[index]
++            end
++            return kwargs
++        end
++    end
++    return Symbol[]
++end
++
++
++"""
++$(:SIGNATURES)
++
++Returns the list of arguments for a particular method `m`.
++
++# Examples
++
++```julia
++f(x; a = 1, b...) = x
++args = arguments(first(methods(f)))
++```
++"""
++function arguments(m::Method)
++    local template = get_method_source(m)
++    if isdefined(template, :slotnames)
++        local args = map(template.slotnames[1:nargs(m)]) do arg
++            arg === Symbol("#unused#") ? "?" : arg
++        end
++        return filter(arg -> arg !== Symbol("#self#"), args)
++    end
++    return Symbol[]
++end
++
++#
++# Source URLs.
++#
++# Based on code from https://github.com/JuliaLang/julia/blob/master/base/methodshow.jl.
++#
++# Customised to handle URLs on travis since the directory is not a Git repo and we must
++# instead rely on `TRAVIS_REPO_SLUG` to get the remote repo.
++#
++
++"""
++$(:SIGNATURES)
++
++Get the URL (file and line number) where a method `m` is defined.
++
++Note that this is based on the implementation of `Base.url`, but handles URLs correctly
++on TravisCI as well.
++"""
++url(m::Method) = url(m.module, string(m.file), m.line)
++
++import LibGit2
++
++function url(mod::Module, file::AbstractString, line::Integer)
++    file = Sys.iswindows() ? replace(file, '\\' => '/') : file
++    if Base.inbase(mod) && !isabspath(file)
++        local base = "https://github.com/JuliaLang/julia/tree"
++        if isempty(Base.GIT_VERSION_INFO.commit)
++            return "$base/v$VERSION/base/$file#L$line"
++        else
++            local commit = Base.GIT_VERSION_INFO.commit
++            return "$base/$commit/base/$file#L$line"
++        end
++    else
++        if isfile(file)
++            local d = dirname(file)
++            return LibGit2.with(LibGit2.GitRepoExt(d)) do repo
++                LibGit2.with(LibGit2.GitConfig(repo)) do cfg
++                    local u = LibGit2.get(cfg, "remote.origin.url", "")
++                    local m = match(LibGit2.GITHUB_REGEX, u)
++                    u = m === nothing ? get(ENV, "TRAVIS_REPO_SLUG", "") : m.captures[1]
++                    local commit = string(LibGit2.head_oid(repo))
++                    local root = LibGit2.path(repo)
++                    if startswith(file, root) || startswith(realpath(file), root)
++                        local base = "https://github.com/$u/tree"
++                        local filename = file[(length(root) + 1):end]
++                        return "$base/$commit/$filename#L$line"
++                    else
++                        return ""
++                    end
++                end
++            end
++        else
++            return ""
++        end
++    end
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..818ef3ad08eb0cc4cad65525bb89a53076ebe432
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++# Only run coverage from linux nightly build on travis.
++get(ENV, "TRAVIS_OS_NAME", "")       == "linux"   || exit()
++get(ENV, "TRAVIS_JULIA_VERSION", "") == "nightly" || exit()
++using Pkg
++Pkg.add("Coverage")
++using Coverage
++
++cd(joinpath(dirname(@__FILE__), "..")) do
++    Codecov.submit(Codecov.process_folder())
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..047a880255bfc631a133567ed5e58cd9a298f71a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++using DocStringExtensions
++using Test
++import Markdown
++
++include("tests.jl")
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1e9de96009e634fc7f0d8b254d7b475818d0d733
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,98 @@@
++module TemplateTests
++
++using DocStringExtensions
++
++@template DEFAULT =
++    """
++    (DEFAULT)
++
++    $(DOCSTRING)
++    """
++
++@template TYPES =
++    """
++    (TYPES)
++
++    $(TYPEDEF)
++
++    $(DOCSTRING)
++    """
++
++@template (METHODS, MACROS) =
++    """
++    (METHODS, MACROS)
++
++    $(SIGNATURES)
++
++    $(DOCSTRING)
++
++    $(METHODLIST)
++    """
++
++"constant `K`"
++const K = 1
++
++"mutable struct `T`"
++mutable struct T end
++
++"method `f`"
++f(x) = x
++
++"method `g`"
++g(::Type{T}) where {T} = T # Issue 32
++
++"macro `@m`"
++macro m(x) end
++
++module InnerModule
++
++    import ..TemplateTests
++
++    using DocStringExtensions
++
++    @template DEFAULT = TemplateTests
++
++    @template METHODS = TemplateTests
++
++    @template MACROS =
++        """
++        (MACROS)
++
++        $(DOCSTRING)
++
++        $(SIGNATURES)
++        """
++
++    "constant `K`"
++    const K = 1
++
++    "mutable struct `T`"
++    mutable struct T end
++
++    "method `f`"
++    f(x) = x
++
++    "macro `@m`"
++    macro m(x) end
++end
++
++module OtherModule
++
++    import ..TemplateTests
++
++    using DocStringExtensions
++
++    @template TYPES = TemplateTests
++    @template MACROS = TemplateTests.InnerModule
++
++    "mutable struct `T`"
++    mutable struct T end
++
++    "macro `@m`"
++    macro m(x) end
++
++    "method `f`"
++    f(x) = x
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dd93ef7520bf2a9a26b3058905e557f556c169d3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,415 @@@
++const DSE = DocStringExtensions
++
++include("templates.jl")
++
++module M
++
++export f
++
++f(x) = x
++
++g(x = 1, y = 2, z = 3; kwargs...) = x
++
++const A{T} = Union{Vector{T}, Matrix{T}}
++
++h_1(x::A) = x
++h_2(x::A{Int}) = x
++h_3(x::A{T}) where {T} = x
++
++i_1(x; y = x) = x * y
++i_2(x::Int; y = x) = x * y
++i_3(x::T; y = x) where {T} = x * y
++i_4(x; y::T = zero(T), z::U = zero(U)) where {T, U} = x + y + z
++
++j_1(x, y) = x * y # two arguments, no keyword arguments
++j_1(x; y = x) = x * y # one argument, one keyword argument
++
++mutable struct T
++    a
++    b
++    c
++end
++
++struct K
++    K(; a = 1) = new()
++end
++
++
++abstract type AbstractType <: Integer end
++
++struct CustomType{S, T <: Integer} <: Integer
++end
++
++primitive type BitType8 8 end
++
++primitive type BitType32 <: Real 32 end
++
++end
++
++@testset "DocStringExtensions" begin
++    @testset "Base assumptions" begin
++        # The package heavily relies on type and docsystem-related methods and types from
++        # Base, which are generally undocumented and their behaviour might change at any
++        # time. This set of tests is tests and documents the assumptions the package makes
++        # about them.
++        #
++        # The testset is not comprehensive -- i.e. DocStringExtensions makes use of
++        # undocumented features that are not tested here. Should you come across anything
++        # like that, please add a test here.
++        #
++
++        # Getting keyword arguments of a method.
++        #
++        # Used in src/utilities.jl for the keywords() function.
++        #
++        # The methodology is based on a snippet in Base at base/replutil.jl:572-576
++        # (commit 3b45cdc9aab0). It uses the undocumented Base.kwarg_decl() function.
++        @test isdefined(Base, :kwarg_decl)
++        # Its signature is kwarg_decl(m::Method, kwtype::DataType). The second argument
++        # should be the type of the kwsorter from the corresponding MethodTable.
++        @test isa(methods(M.j_1), Base.MethodList)
++        @test isdefined(methods(M.j_1), :mt)
++        local mt = methods(M.j_1).mt
++        @test isa(mt, Core.MethodTable)
++        @test isdefined(mt, :kwsorter)
++        # .kwsorter is not always defined -- namely, it seems when none of the methods
++        # have keyword arguments:
++        @test isdefined(methods(M.f).mt, :kwsorter) === false
++        # M.j_1 has two methods. Fetch the single argument one..
++        local m = which(M.j_1, (Any,))
++        @test isa(m, Method)
++        # .. which should have a single keyword argument, :y
++        # Base.kwarg_decl returns a Vector{Any} of the keyword arguments.
++        local kwargs = Base.kwarg_decl(m, typeof(mt.kwsorter))
++        @test isa(kwargs, Vector{Any})
++        @test kwargs == [:y]
++        # Base.kwarg_decl will return a Tuple{} for some reason when called on a method
++        # that does not have any arguments
++        m = which(M.j_1, (Any,Any)) # fetch the no-keyword method
++        @test Base.kwarg_decl(m, typeof(methods(M.j_1).mt.kwsorter)) == Tuple{}()
++    end
++    @testset "format" begin
++        # Setup.
++        doc = Docs.DocStr(Core.svec(), nothing, Dict())
++        buf = IOBuffer()
++
++        # Errors.
++        @test_throws ErrorException DSE.format(nothing, buf, doc)
++
++        @testset "imports & exports" begin
++            # Module imports.
++            doc.data = Dict(
++                :binding => Docs.Binding(Main, :M),
++                :typesig => Union{},
++            )
++            DSE.format(IMPORTS, buf, doc)
++            str = String(take!(buf))
++            @test occursin("\n  - `Base`\n", str)
++            @test occursin("\n  - `Core`\n", str)
++
++            # Module exports.
++            DSE.format(EXPORTS, buf, doc)
++            str = String(take!(buf))
++            @test occursin("\n  - [`f`](@ref)\n", str)
++        end
++
++        @testset "type fields" begin
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :T),
++                :fields => Dict(
++                    :a => "one",
++                    :b => "two",
++                ),
++            )
++            DSE.format(FIELDS, buf, doc)
++            str = String(take!(buf))
++            @test occursin("  - `a`", str)
++            @test occursin("  - `b`", str)
++            @test occursin("  - `c`", str)
++            @test occursin("one", str)
++            @test occursin("two", str)
++        end
++
++        @testset "method lists" begin
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :f),
++                :typesig => Tuple{Any},
++                :module => M,
++            )
++            DSE.format(METHODLIST, buf, doc)
++            str = String(take!(buf))
++            @test occursin("```julia", str)
++            @test occursin("f(x)", str)
++            @test occursin(joinpath("test", "tests.jl"), str)
++        end
++
++        @testset "method signatures" begin
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :f),
++                :typesig => Tuple{Any},
++                :module => M,
++            )
++            DSE.format(SIGNATURES, buf, doc)
++            str = String(take!(buf))
++            @test occursin("\n```julia\n", str)
++            @test occursin("\nf(x)\n", str)
++            @test occursin("\n```\n", str)
++
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :g),
++                :typesig => Union{Tuple{}, Tuple{Any}},
++                :module => M,
++            )
++            DSE.format(SIGNATURES, buf, doc)
++            str = String(take!(buf))
++            @test occursin("\n```julia\n", str)
++            @test occursin("\ng()\n", str)
++            @test occursin("\ng(x)\n", str)
++            @test occursin("\n```\n", str)
++
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :g),
++                :typesig => Union{Tuple{}, Tuple{Any}, Tuple{Any, Any}, Tuple{Any, Any, Any}},
++                :module => M,
++            )
++            DSE.format(SIGNATURES, buf, doc)
++            str = String(take!(buf))
++            @test occursin("\n```julia\n", str)
++            @test occursin("\ng()\n", str)
++            @test occursin("\ng(x)\n", str)
++            @test occursin("\ng(x, y)\n", str)
++            @test occursin("\ng(x, y, z; kwargs...)\n", str)
++            @test occursin("\n```\n", str)
++        end
++
++        @testset "function names" begin
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :f),
++                :typesig => Tuple{Any},
++                :module => M,
++            )
++            DSE.format(FUNCTIONNAME, buf, doc)
++            str = String(take!(buf))
++            @test str == "f"
++        end
++
++        @testset "type definitions" begin
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :AbstractType),
++                :typesig => Union{},
++                :module => M,
++            )
++            DSE.format(TYPEDEF, buf, doc)
++            str = String(take!(buf))
++            @test str == "\n```julia\nabstract type AbstractType <: Integer\n```\n\n"
++
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :CustomType),
++                :typesig => Union{},
++                :module => M,
++            )
++            DSE.format(TYPEDEF, buf, doc)
++            str = String(take!(buf))
++            @test str == "\n```julia\nstruct CustomType{S, T<:Integer} <: Integer\n```\n\n"
++
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :BitType8),
++                :typesig => Union{},
++                :module => M,
++            )
++            DSE.format(TYPEDEF, buf, doc)
++            str = String(take!(buf))
++            @test str == "\n```julia\nprimitive type BitType8 8\n```\n\n"
++
++            doc.data = Dict(
++                :binding => Docs.Binding(M, :BitType32),
++                :typesig => Union{},
++                :module => M,
++            )
++            DSE.format(TYPEDEF, buf, doc)
++            str = String(take!(buf))
++            @test str == "\n```julia\nprimitive type BitType32 <: Real 32\n```\n\n"
++        end
++    end
++    @testset "templates" begin
++        let fmt = expr -> Markdown.plain(eval(:(@doc $expr)))
++            @test occursin("(DEFAULT)", fmt(:(TemplateTests.K)))
++            @test occursin("(TYPES)", fmt(:(TemplateTests.T)))
++            @test occursin("(METHODS, MACROS)", fmt(:(TemplateTests.f)))
++            @test occursin("(METHODS, MACROS)", fmt(:(TemplateTests.g)))
++            @test occursin("(METHODS, MACROS)", fmt(:(TemplateTests.@m)))
++
++            @test occursin("(DEFAULT)", fmt(:(TemplateTests.InnerModule.K)))
++            @test occursin("(DEFAULT)", fmt(:(TemplateTests.InnerModule.T)))
++            @test occursin("(METHODS, MACROS)", fmt(:(TemplateTests.InnerModule.f)))
++            @test occursin("(MACROS)", fmt(:(TemplateTests.InnerModule.@m)))
++
++            @test occursin("(TYPES)", fmt(:(TemplateTests.OtherModule.T)))
++            @test occursin("(MACROS)", fmt(:(TemplateTests.OtherModule.@m)))
++            @test fmt(:(TemplateTests.OtherModule.f)) == "method `f`\n"
++        end
++    end
++    @testset "utilities" begin
++        @testset "keywords" begin
++            @test DSE.keywords(M.T, first(methods(M.T))) == Symbol[]
++            @test DSE.keywords(M.K, first(methods(M.K))) == [:a]
++            @test DSE.keywords(M.f, first(methods(M.f))) == Symbol[]
++            let f = (() -> ()),
++                m = first(methods(f))
++                @test DSE.keywords(f, m) == Symbol[]
++            end
++            let f = ((a) -> ()),
++                m = first(methods(f))
++                @test DSE.keywords(f, m) == Symbol[]
++            end
++            let f = ((; a = 1) -> ()),
++                m = first(methods(f))
++                @test DSE.keywords(f, m) == [:a]
++            end
++            let f = ((; a = 1, b = 2) -> ()),
++                m = first(methods(f))
++                @test DSE.keywords(f, m) == [:a, :b]
++            end
++            let f = ((; a...) -> ()),
++                m = first(methods(f))
++                @test DSE.keywords(f, m) == [Symbol("a...")]
++            end
++            # Tests for #42
++            let f = M.i_1, m = first(methods(f))
++                @test DSE.keywords(f, m) == [:y]
++            end
++            let f = M.i_2, m = first(methods(f))
++                @test DSE.keywords(f, m) == [:y]
++            end
++            let f = M.i_3, m = first(methods(f))
++                @test DSE.keywords(f, m) == [:y]
++            end
++            let f = M.i_4, m = first(methods(f))
++                @test DSE.keywords(f, m) == [:y, :z]
++            end
++        end
++        @testset "arguments" begin
++            @test DSE.arguments(first(methods(M.T))) == [:a, :b, :c]
++            @test DSE.arguments(first(methods(M.K))) == Symbol[]
++            @test DSE.arguments(first(methods(M.f))) == [:x]
++            let m = first(methods(() -> ()))
++                @test DSE.arguments(m) == Symbol[]
++            end
++            let m = first(methods((a) -> ()))
++                @test DSE.arguments(m) == [:a]
++            end
++            let m = first(methods((; a = 1) -> ()))
++                @test DSE.arguments(m) == Symbol[]
++            end
++            let m = first(methods((x; a = 1, b = 2) -> ()))
++                @test DSE.arguments(m) == Symbol[:x]
++            end
++            let m = first(methods((; a...) -> ()))
++                @test DSE.arguments(m) == Symbol[]
++            end
++        end
++        @testset "printmethod" begin
++            let b = Docs.Binding(M, :T),
++                f = M.T,
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "T(a, b, c)"
++            end
++            let b = Docs.Binding(M, :K),
++                f = M.K,
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "K(; a)"
++            end
++            let b = Docs.Binding(M, :f),
++                f = M.f,
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "f(x)"
++            end
++            let b = Docs.Binding(Main, :f),
++                f = () -> (),
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "f()"
++            end
++            let b = Docs.Binding(Main, :f),
++                f = (a) -> (),
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "f(a)"
++            end
++            let b = Docs.Binding(Main, :f),
++                f = (; a = 1) -> (),
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "f(; a)"
++            end
++            let b = Docs.Binding(Main, :f),
++                f = (; a = 1, b = 2) -> (),
++                m = first(methods(f))
++                # Keywords are not ordered, so check for both combinations.
++                @test DSE.printmethod(b, f, m) in ("f(; a, b)", "f(; b, a)")
++            end
++            let b = Docs.Binding(Main, :f),
++                f = (; a...) -> (),
++                m = first(methods(f))
++                @test DSE.printmethod(b, f, m) == "f(; a...)"
++            end
++            let b = Docs.Binding(Main, :f),
++                f = (; a = 1, b = 2, c...) -> (),
++                m = first(methods(f))
++                # Keywords are not ordered, so check for both combinations.
++                @test DSE.printmethod(b, f, m) in ("f(; a, b, c...)", "f(; b, a, c...)")
++            end
++        end
++        @testset "getmethods" begin
++            @test length(DSE.getmethods(M.f, Union{})) == 1
++            @test length(DSE.getmethods(M.f, Tuple{})) == 0
++            @test length(DSE.getmethods(M.f, Union{Tuple{}, Tuple{Any}})) == 1
++            @test length(DSE.getmethods(M.h_3, Tuple{M.A{Int}})) == 1
++            @test length(DSE.getmethods(M.h_3, Tuple{Vector{Int}})) == 1
++            @test length(DSE.getmethods(M.h_3, Tuple{Array{Int, 3}})) == 0
++        end
++        @testset "methodgroups" begin
++            @test length(DSE.methodgroups(M.f, Tuple{Any}, M)) == 1
++            @test length(DSE.methodgroups(M.f, Tuple{Any}, M)[1]) == 1
++            @test length(DSE.methodgroups(M.h_1, Tuple{M.A}, M)) == 1
++            @test length(DSE.methodgroups(M.h_1, Tuple{M.A}, M)[1]) == 1
++            @test length(DSE.methodgroups(M.h_2, Tuple{M.A{Int}}, M)) == 1
++            @test length(DSE.methodgroups(M.h_2, Tuple{M.A{Int}}, M)[1]) == 1
++            @test length(DSE.methodgroups(M.h_3, Tuple{M.A}, M)[1]) == 1
++        end
++        @testset "alltypesigs" begin
++            @test DSE.alltypesigs(Union{}) == Any[]
++            @test DSE.alltypesigs(Union{Tuple{}}) == Any[Tuple{}]
++            @test DSE.alltypesigs(Tuple{}) == Any[Tuple{}]
++
++            # TODO: Clean me up
++            T = Type{T} where {T}
++            @test DSE.alltypesigs(T) ==
++                Base.rewrap_unionall.(DSE.uniontypes(Base.unwrap_unionall(T)), T)
++        end
++        @testset "groupby" begin
++            let groups = DSE.groupby(Int, Vector{Int}, collect(1:10)) do each
++                    mod(each, 3), each
++                end
++                @test groups == Pair{Int, Vector{Int}}[
++                    0 => [3, 6, 9],
++                    1 => [1, 4, 7, 10],
++                    2 => [2, 5, 8],
++                ]
++            end
++        end
++        @testset "url" begin
++            @test !isempty(DSE.url(first(methods(sin))))
++            @test !isempty(DSE.url(first(methods(DSE.parsedocs))))
++            @test !isempty(DSE.url(first(methods(M.f))))
++            @test !isempty(DSE.url(first(methods(M.K))))
++        end
++        @testset "comparemethods" begin
++            let f = first(methods(M.f)),
++                g = first(methods(M.g))
++                @test !DSE.comparemethods(f, f)
++                @test DSE.comparemethods(f, g)
++                @test !DSE.comparemethods(g, f)
++            end
++        end
++    end
++end
++
++DSE.parsedocs(DSE)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d39ab661330d474eddee6fe265fc699c8ef833bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++https://github.com/JuliaDocs/DocStringExtensions.jl/releases
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..569ca845cc23baa967b2bb5e899001046ffc95ae
new file mode 120000 (symlink)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++Documenter.jl-0.20.0
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..69cb76019a474330e99666f147ecb85e44de1ce6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++comment: false
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba33e69a22bc077265b4cdb2256e09423fa64bfa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++language: julia
++
++os:
++  - linux
++  - osx
++
++julia:
++  - 0.7
++  - 1.0
++  - nightly
++
++notifications:
++  email: false
++
++after_success:
++  - julia --project=coverage/ -e 'using Pkg; Pkg.instantiate()'
++  - julia --project=coverage/ coverage/coverage.jl
++
++jobs:
++  include:
++    - stage: "Documentation"
++      julia: 1.0
++      os: linux
++      script:
++        - julia --project=docs/ -e 'using Pkg; Pkg.instantiate(); Pkg.develop(PackageSpec(path=pwd()))'
++        - julia --project=docs/ docs/make.jl
++      after_success: skip
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fe4057629147c12c4f477631c5eb5c6d8ccce637
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,121 @@@
++# Documenter.jl changelog
++
++## Version `v0.20.0`
++
++* Documenter v0.20 requires at least Julia v0.7. ([#795][github-795])
++
++* ![BREAKING][badge-breaking] Documentation deployment via the `deploydocs` function has changed considerably.
++
++  - The user-facing directories (URLs) of different versions and what gets displayed in the version selector have changed. By default, Documenter now creates the `stable/` directory (as before) and a directory for every minor version (`vX.Y/`). The `release-X.Y` directories are no longer created. ([#706][github-706], [#813][github-813], [#817][github-817])
++
++    Technically, Documenter now deploys actual files only to `dev/` and `vX.Y.Z/` directories. The directories (URLs) that change from version to version (e.g. `latest/`, `vX.Y`) are implemented as symlinks on the `gh-pages` branch.
++
++    The version selector will only display `vX.Y/`, `stable/` and `dev/` directories by default. This behavior can be customized with the `versions` keyword of `deploydocs`.
++
++  - Documentation from the development branch (e.g. `master`) now deploys to `dev/` by default (instead of `latest/`). This can be customized with the `devurl` keyword. ([#802][github-802])
++
++  - The `latest` keyword to `deploydocs` has been deprecated and renamed to `devbranch`. ([#802][github-802])
++
++  - The `julia` and `osname` keywords to `deploydocs` are now deprecated. ([#816][github-816])
++
++  - The default values of the `target`, `deps` and `make` keywords to `deploydocs` have been changed. See the default format change below for more information. ([#826][github-826])
++
++  **For upgrading:**
++
++  - If you are using the `latest` keyword, then just use `devbranch` with the same value instead.
++
++  - Update links that point to `latest/` to point to `dev/` instead (e.g. in the README).
++
++  - Remove any links to the `release-X.Y` branches and remove the directories from your `gh-pages` branch.
++
++  - The operating system and Julia version should be specified in the Travis build stage configuration (via `julia:` and `os:` options, see "Hosting Documentation" in the manual for more details) or by checking the `TRAVIS_JULIA_VERSION` and `TRAVIS_OS_NAME` environment variables in `make.jl` yourself.
++
++* ![BREAKING][badge-breaking] `makedocs` will now build Documenter's native HTML output by default and `deploydocs`' defaults now assume the HTML output. ([#826][github-826])
++
++  - The default value of the `format` keyword of `makedocs` has been changed to `:html`.
++
++  - The default value of the `target` keyword to `deploydocs` has been changed to `"build"`.
++
++  - The default value of the `make` and `deps` keywords to `deploydocs` have been changed to `nothing`.
++
++  **For upgrading:** If you are relying on the Markdown/MkDocs output, you now need to:
++
++  - In `makedocs`, explicitly set `format = :markdown`
++
++  - In `deploydocs`, explicitly set
++
++    ```julia
++    target = "site"
++    deps = Deps.pip("pygments", "mkdocs")
++    make = () -> run(`mkdocs build`)
++    ```
++
++  - Explicitly import `DocumenterMarkdown` in `make.jl`. See the `MarkdownWriter` deprecation below.
++
++  If you already specify any of the changed keywords, then you do not need to make any changes to those keywords you already set.
++
++  However, if you are setting any of the values to the new defaults (e.g. when you are already using the HTML output), you may now rely on the new defaults.
++
++* ![Deprecation][badge-deprecation] The Markdown/MkDocs (`format = :markdown`) and PDF/LaTeX (`format = :latex`) outputs now require an external package to be loaded ([DocumenterMarkdown](https://github.com/JuliaDocs/DocumenterMarkdown.jl) and [DocumenterLaTeX](https://github.com/JuliaDocs/DocumenterLaTeX.jl), respectively). ([#833][github-833])
++
++  **For upgrading:** Make sure that the respective extra package is installed and then just add `using DocumenterMarkdown` or `using DocumenterLaTeX` to `make.jl`.
++
++* ![BREAKING][badge-breaking] "Pretty URLs" are enabled by default now for the HTML output. The default value of the `html_prettyurls` has been changed to `true`.
++
++  For a page `foo/page.md` Documenter now generates `foo/page/index.html`, instead of `foo/page.html`.
++  On GitHub pages deployments it means that your URLs look like  `foo/page/` instead of `foo/page.html`.
++
++  For local builds you should explicitly set `html_prettyurls = false`.
++
++  **For upgrading:** If you wish to retain the old behavior, set `html_prettyurls = false` in `makedocs`. If you already set `html_prettyurls`, you do not need to change anything.
++
++* ![BREAKING][badge-breaking] The `Travis.genkeys` and `Documenter.generate` functions have been moved to a separate [DocumenterTools.jl package](https://github.com/JuliaDocs/DocumenterTools.jl). ([#789][github-789])
++
++* ![Enhancement][badge-enhancement] If Documenter is not able to determine which Git hosting service is being used to host the source, the "Edit on XXX" links become "Edit source" with a generic icon. ([#804][github-804])
++
++* ![Enhancement][badge-enhancement] The at-blocks now support `MIME"text/html"` rendering of objects (e.g. for interactive plots). I.e. if a type has `show(io, ::MIME"text/html", x)` defined, Documenter now uses that when rendering the objects in the document. ([#764][github-764])
++
++* ![Enhancement][badge-enhancement] Enhancements to the sidebar. When loading a page, the sidebar will jump to the current page now. Also, the scrollbar in WebKit-based browsers look less intrusive now. ([#792][github-792], [#854][github-854], [#863][github-863])
++
++* ![Enhancement][badge-enhancement] Minor style enhancements to admonitions. ([#841][github-841])
++
++* ![Bugfix][badge-bugfix] The at-blocks that execute code can now handle `include` statements. ([#793][github-793], [#794][github-794])
++
++* ![Bugfix][badge-bugfix] At-docs blocks no longer give an error when containing empty lines. ([#823][github-823], [#824][github-824])
++
++[github-706]: https://github.com/JuliaDocs/Documenter.jl/pull/706
++[github-764]: https://github.com/JuliaDocs/Documenter.jl/pull/764
++[github-789]: https://github.com/JuliaDocs/Documenter.jl/pull/789
++[github-792]: https://github.com/JuliaDocs/Documenter.jl/pull/792
++[github-793]: https://github.com/JuliaDocs/Documenter.jl/pull/793
++[github-794]: https://github.com/JuliaDocs/Documenter.jl/pull/794
++[github-795]: https://github.com/JuliaDocs/Documenter.jl/pull/795
++[github-802]: https://github.com/JuliaDocs/Documenter.jl/pull/802
++[github-804]: https://github.com/JuliaDocs/Documenter.jl/pull/804
++[github-813]: https://github.com/JuliaDocs/Documenter.jl/pull/813
++[github-816]: https://github.com/JuliaDocs/Documenter.jl/pull/816
++[github-817]: https://github.com/JuliaDocs/Documenter.jl/pull/817
++[github-823]: https://github.com/JuliaDocs/Documenter.jl/pull/823
++[github-824]: https://github.com/JuliaDocs/Documenter.jl/pull/824
++[github-826]: https://github.com/JuliaDocs/Documenter.jl/pull/826
++[github-833]: https://github.com/JuliaDocs/Documenter.jl/pull/833
++[github-841]: https://github.com/JuliaDocs/Documenter.jl/pull/841
++[github-854]: https://github.com/JuliaDocs/Documenter.jl/pull/854
++[github-863]: https://github.com/JuliaDocs/Documenter.jl/pull/863
++
++
++[badge-breaking]: https://img.shields.io/badge/BREAKING-red.svg
++[badge-deprecation]: https://img.shields.io/badge/deprecation-orange.svg
++[badge-feature]: https://img.shields.io/badge/feature-green.svg
++[badge-enhancement]: https://img.shields.io/badge/enhancement-blue.svg
++[badge-bugfix]: https://img.shields.io/badge/bugfix-purple.svg
++
++<!--
++# Badges
++
++![BREAKING][badge-breaking]
++![Deprecation][badge-deprecation]
++![Feature][badge-feature]
++![Enhancement][badge-enhancement]
++![Bugfix][badge-bugfix]
++-->
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1a2af4961d07107b84788c145277dd6b0af9683e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++The Documenter.jl package is licensed under the MIT "Expat" License:
++
++> Copyright (c) 2016: Michael Hatherly.
++> 
++> Permission is hereby granted, free of charge, to any person obtaining a copy
++> of this software and associated documentation files (the "Software"), to deal
++> in the Software without restriction, including without limitation the rights
++> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++> copies of the Software, and to permit persons to whom the Software is
++> furnished to do so, subject to the following conditions:
++> 
++> The above copyright notice and this permission notice shall be included in all
++> copies or substantial portions of the Software.
++> 
++> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++> SOFTWARE.
++> 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..72a2d186a863fd401f83ee71f886bce79d66bf49
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++
++# Documenter
++
++*A documentation generator for Julia.*
++
++| **Documentation**                                                               | **Build Status**                                                                                |
++|:-------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|
++| [![][docs-stable-img]][docs-stable-url] [![][docs-dev-img]][docs-dev-url] | [![][travis-img]][travis-url] [![][appveyor-img]][appveyor-url] [![][codecov-img]][codecov-url] |
++
++
++## Installation
++
++The package can be installed with the Julia package manager.
++From the Julia REPL, type `]` to enter the Pkg REPL mode and run:
++
++```
++pkg> add Documenter
++```
++
++Or, equivalently, via the `Pkg` API:
++
++```julia
++julia> import Pkg; Pkg.add("Documenter")
++```
++
++## Documentation
++
++- [**STABLE**][docs-stable-url] &mdash; **documentation of the most recently tagged version.**
++- [**DEVEL**][docs-dev-url] &mdash; *documentation of the in-development version.*
++
++## Project Status
++
++The package is tested against Julia `0.7`, `1.0` and the nightly builds of the Julia `master` branch on Linux, macOS, and Windows.
++
++Support for Julia `0.4`, `0.5` and `0.6` has been dropped in the latest version, but older versions of Documenter may still work (Documenter versions `0.8`, `0.11` and `0.19`, respectively).
++
++## Questions and Contributions
++
++Usage questions can be posted on the [Julia Discourse forum][discourse-tag-url] under the `documenter` tag, in the #documentation channel of the [Julia Slack](https://julialang.org/community/) and/or in the [JuliaDocs Gitter chat room][gitter-url].
++
++Contributions are very welcome, as are feature requests and suggestions. Please open an [issue][issues-url] if you encounter any problems. The [contributing page][contrib-url] has a few guidelines that should be followed when opening pull requests and contributing code.
++
++[contrib-url]: https://juliadocs.github.io/Documenter.jl/latest/man/contributing/
++[discourse-tag-url]: https://discourse.julialang.org/tags/documenter
++[gitter-url]: https://gitter.im/juliadocs/users
++
++[docs-dev-img]: https://img.shields.io/badge/docs-dev-blue.svg
++[docs-dev-url]: https://juliadocs.github.io/Documenter.jl/latest
++
++[docs-stable-img]: https://img.shields.io/badge/docs-stable-blue.svg
++[docs-stable-url]: https://juliadocs.github.io/Documenter.jl/stable
++
++[travis-img]: https://travis-ci.org/JuliaDocs/Documenter.jl.svg?branch=master
++[travis-url]: https://travis-ci.org/JuliaDocs/Documenter.jl
++
++[appveyor-img]: https://ci.appveyor.com/api/projects/status/xx7nimfpnl1r4gx0?svg=true
++[appveyor-url]: https://ci.appveyor.com/project/JuliaDocs/documenter-jl
++
++[codecov-img]: https://codecov.io/gh/JuliaDocs/Documenter.jl/branch/master/graph/badge.svg
++[codecov-url]: https://codecov.io/gh/JuliaDocs/Documenter.jl
++
++[issues-url]: https://github.com/JuliaDocs/Documenter.jl/issues
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4e2a4a0ceb8965f3f93a251f334062c7c92eb8ea
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++julia 0.7
++DocStringExtensions 0.2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c3acffe7e3f4c663df8b792eca6032ba47603d14
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++environment:
++  matrix:
++  - julia_version: 0.7
++  - julia_version: 1.0
++  - julia_version: latest
++
++platform:
++  - x86 # 32-bit
++  - x64 # 64-bit
++
++## uncomment the following lines to allow failures on nightly julia
++## (tests will run but not make your overall status red)
++#matrix:
++#  allow_failures:
++#  - julia_version: latest
++
++branches:
++  only:
++    - master
++    - /release-.*/
++
++notifications:
++  - provider: Email
++    on_build_success: false
++    on_build_failure: false
++    on_build_status_changed: false
++
++install:
++  - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))
++
++build_script:
++  - echo "%JL_BUILD_SCRIPT%"
++  - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"
++
++test_script:
++  - echo "%JL_TEST_SCRIPT%"
++  - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ee2798d3fbc10eb527b708b41842d0a0078f8acd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,63 @@@
++<?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="16.5mm"
++   height="8.6603003mm"
++   viewBox="0 0 58.464567 30.686103"
++   id="svg2"
++   version="1.1"
++   inkscape:version="0.91 r13725"
++   sodipodi:docname="arrow.svg">
++  <defs
++     id="defs4" />
++  <sodipodi:namedview
++     id="base"
++     pagecolor="#ffffff"
++     bordercolor="#666666"
++     borderopacity="1.0"
++     inkscape:pageopacity="0.0"
++     inkscape:pageshadow="2"
++     inkscape:zoom="11.2"
++     inkscape:cx="14.209234"
++     inkscape:cy="29.780479"
++     inkscape:document-units="px"
++     inkscape:current-layer="layer1"
++     showgrid="false"
++     inkscape:window-width="1920"
++     inkscape:window-height="1053"
++     inkscape:window-x="0"
++     inkscape:window-y="27"
++     inkscape:window-maximized="1" />
++  <metadata
++     id="metadata7">
++    <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(0,-1021.6761)">
++    <path
++       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
++       d="m 0,1021.6761 35.433071,0 -17.716536,30.6861 z"
++       id="path4140"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="cccc" />
++  </g>
++</svg>
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b6c9e1d81f24d7e630dc40b15fe6272277986270
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,601 @@@
++/*
++ * The default CSS style for Documenter.jl generated sites
++ *
++ * Heavily inspired by the Julia Sphinx theme
++ *     https://github.com/JuliaLang/JuliaDoc
++ * which extends the sphinx_rtd_theme
++ *     https://github.com/snide/sphinx_rtd_theme
++ *
++ * Part of Documenter.jl
++ *     https://github.com/JuliaDocs/Documenter.jl
++ *
++ * License: MIT
++ */
++
++/* fonts */
++body, input {
++  font-family: 'Lato', 'Helvetica Neue', Arial, sans-serif;
++  font-size: 16px;
++  color: #222;
++  text-rendering: optimizeLegibility;
++}
++
++pre, code, kbd {
++  font-family: Inconsolata, Monaco, courier, monospace;
++  font-size: 0.90em;
++}
++
++pre code {
++  font-size: 1em;
++}
++
++a {
++    color: #2980b9;
++    text-decoration: none;
++}
++
++a:hover {
++    color: #3091d1;
++}
++
++a:visited {
++    color: #9b59b6;
++}
++
++body {
++    line-height: 1.5;
++}
++
++h1 {
++    font-size: 1.75em;
++}
++
++/* Unless the <h1> the is very first thing on the page (i.e. the second element
++ * in the <article>, * after the <header>, we add some additional styling to it
++ * to make it stand out a bit more. This way we get a reasonable fallback if CSS3
++ * selectors are not supported in the browser.
++ */
++article > h1:not(:nth-child(2)) {
++    margin: 2.5em 0 0;
++    padding-bottom: 0.30em;
++    border-bottom: 1px solid #e5e5e5;
++}
++h2 {
++    font-size: 1.50em;
++    margin: 2.3em 0 0;
++    padding-bottom: 0.25em;
++    border-bottom: 1px solid #e5e5e5;
++}
++h3 {
++    font-size: 1.25em;
++    margin: 2.0em 0 0;
++}
++h4 { font-size: 1.15em; }
++h5 { font-size: 1.10em; }
++h6 { font-size: 1em; }
++
++h4, h5, h6 {
++    margin-top: 1.5em;
++    margin-bottom: 1em;
++}
++
++img {
++    max-width: 100%;
++}
++
++table {
++    border-collapse: collapse;
++    margin: 1em 0;
++}
++
++th, td {
++    border: 1px solid #e1e4e5;
++    padding: 0.5em 1em;
++}
++
++th {
++    border-bottom-width: 2px;
++}
++
++tr:nth-child(even) {
++    background-color: #f3f6f6;
++}
++
++hr {
++    border: 0;
++    border-top: 1px solid #e5e5e5;
++}
++
++/* Inline code and code blocks */
++
++code {
++    padding: 0.1em;
++    background-color: rgba(0,0,0,.04);
++    border-radius: 3px;
++}
++
++pre {
++    background-color: #f5f5f5;
++    border: 1px solid #dddddd;
++    border-radius: 3px;
++    padding: 0.5em;
++    overflow: auto;
++}
++
++pre code {
++    padding: 0;
++    background-color: initial;
++}
++
++kbd {
++    font-size: 0.70em;
++    display: inline-block;
++    padding: 0.1em 0.5em 0.4em 0.5em;
++    line-height: 1.0em;
++    color: #444d56;
++    vertical-align: middle;
++    background-color: #fafbfc;
++    border: solid 1px #c6cbd1;
++    border-bottom-color: #959da5;
++    border-radius: 3px;
++    box-shadow: inset 0 -1px 0 #959da5;
++}
++
++/* Headers in admonitions and docstrings */
++.admonition h1,
++article section.docstring h1 {
++    font-size: 1.25em;
++}
++
++.admonition h2,
++article section.docstring h2 {
++    font-size: 1.10em;
++}
++
++.admonition h3,
++.admonition h4,
++.admonition h5,
++.admonition h6,
++article section.docstring h3,
++article section.docstring h4,
++article section.docstring h5,
++article section.docstring h6 {
++    font-size: 1em;
++}
++
++/* Navigation */
++nav.toc {
++    position: fixed;
++    top: 0;
++    left: 0;
++    bottom: 0;
++    width: 20em;
++    display: flex;
++    flex-flow: column nowrap;
++    overflow-y: auto;
++    padding: 1em 0 0 0;
++    background-color: #fcfcfc;
++    box-shadow: inset -14px 0px 5px -12px rgb(210,210,210);
++}
++
++nav.toc .logo {
++    margin: 0 auto;
++    display: block;
++    max-height: 6em;
++    max-width: 18em;
++}
++
++nav.toc h1 {
++    text-align: center;
++    margin-top: .57em;
++    margin-bottom: 0;
++}
++
++nav.toc select {
++    display: block;
++    height: 2em;
++    flex-shrink: 0;
++    padding: 0 1.6em 0 1em;
++    min-width: 7em;
++    max-width: 90%;
++    max-width: calc(100% - 5em);
++    margin: 0 auto;
++    font-size: .83em;
++    border: 1px solid #c9c9c9;
++    border-radius: 1em;
++
++    /* TODO: doesn't seem to be centered on Safari */
++    text-align: center;
++    text-align-last: center;
++
++    appearance: none;
++    -moz-appearance: none;
++    -webkit-appearance: none;
++
++    background: white url("arrow.svg");
++    background-size: 1.155em;
++    background-repeat: no-repeat;
++    background-position: right;
++}
++
++nav.toc select:hover {
++    border: 1px solid #a0a0a0;
++}
++
++nav.toc select option {
++    text-align: center;
++}
++
++nav.toc input {
++    display: block;
++    height: 2em;
++    width: 90%;
++    width: calc(100% - 5em);
++    margin: 1.2em auto;
++    padding: 0 1em;
++    border: 1px solid #c9c9c9;
++    border-radius: 1em;
++    font-size: .83em;
++}
++
++nav.toc > ul * {
++    margin: 0;
++}
++
++nav.toc > ul {
++    min-height: 2em;
++    overflow-y: auto;
++    margin: 0;
++}
++
++nav.toc > ul > li:last-child {
++    padding-bottom: 1em;
++}
++
++nav.toc ul {
++    color: #404040;
++    padding: 0;
++    list-style: none;
++}
++
++nav.toc ul .toctext {
++    color: inherit;
++    display: block;
++}
++
++nav.toc ul a:hover {
++    color: #fcfcfc;
++    background-color: #4e4a4a;
++}
++
++nav.toc ul.internal a {
++    color: inherit;
++    display: block;
++}
++
++nav.toc ul.internal a:hover {
++    background-color: #d6d6d6;
++}
++
++nav.toc ul.internal {
++    background-color: #e3e3e3;
++    box-shadow: inset -14px 0px 5px -12px rgb(210,210,210);
++    list-style: none;
++}
++
++nav.toc ul.internal li.toplevel {
++    border-top: 1px solid #909090;
++    font-weight: bold;
++}
++
++nav.toc ul.internal li.toplevel:first-child {
++    border-top: none;
++}
++
++nav.toc .toctext {
++    padding-top: 0.3em;
++    padding-bottom: 0.3em;
++    padding-right: 1em;
++}
++
++nav.toc ul .toctext {
++    padding-left: 1em;
++}
++
++nav.toc ul ul .toctext {
++    padding-left: 2em;
++}
++
++nav.toc ul ul ul .toctext {
++    padding-left: 3em;
++}
++
++nav.toc li.current > .toctext {
++    border-top: 1px solid #c9c9c9;
++    border-bottom: 1px solid #c9c9c9;
++    color: #404040;
++    font-weight: bold;
++    background-color: white;
++}
++
++nav.toc ul::-webkit-scrollbar {
++    width: .4em;
++    background: none;
++}
++
++nav.toc ul::-webkit-scrollbar-thumb {
++    border-radius: 5px;
++    background: #c9c9c9;
++}
++
++nav.toc ul::-webkit-scrollbar-thumb:hover {
++    border-radius: 5px;
++    background: #aaaaaa;
++}
++
++article {
++    margin-left: 20em;
++    min-width: 20em;
++    max-width: 48em;
++    padding: 2em;
++}
++
++article > header {}
++
++article > header div#topbar {
++    display: none;
++}
++
++article > header nav ul {
++    display: inline-block;
++    list-style: none;
++    margin: 0;
++    padding: 0;
++}
++
++article > header nav li {
++    display: inline-block;
++    padding-right: 0.2em;
++}
++
++article > header nav li:before {
++    content: "»";
++    padding-right: 0.2em;
++}
++
++article > header .edit-page {
++    float: right;
++}
++
++article > footer {}
++
++article > footer a.prev {
++    float: left;
++}
++article > footer a.next {
++    float: right;
++}
++
++article > footer a .direction:after {
++    content: ": ";
++}
++
++article hr {
++    margin: 1em 0;
++}
++
++article section.docstring {
++    border: 1px solid #ddd;
++    margin: 0.5em 0;
++    padding: 0.5em;
++    border-radius: 3px;
++}
++
++article section.docstring .docstring-header {
++    margin-bottom: 1em;
++}
++
++article section.docstring .docstring-binding {
++    color: #333;
++    font-weight: bold;
++}
++
++article section.docstring .docstring-category {
++    font-style: italic;
++}
++
++article section.docstring a.source-link {
++    display: block;
++    font-weight: bold;
++}
++
++.nav-anchor,
++.nav-anchor:hover,
++.nav-anchor:visited {
++    color: #333;
++}
++
++/*
++ * Admonitions
++ *
++ * Colors (title, body)
++ * warning: #f0b37e #ffedcc (orange)
++ * note:    #6ab0de #e7f2fa (blue)
++ * tip:     #1abc9c #dbfaf4 (green)
++*/
++.admonition {
++    border-radius: 3px;
++    background-color: #eeeeee;
++    margin: 1em 0;
++}
++
++.admonition-title {
++    border-radius: 3px 3px 0 0;
++    background-color: #9b9b9b;
++    padding: 0.15em 0.5em;
++}
++
++.admonition-text {
++    padding: 0.5em;
++}
++
++.admonition-text > :first-child {
++    margin-top: 0;
++}
++
++.admonition-text > :last-child {
++    margin-bottom: 0;
++}
++
++.admonition > .admonition-title:before {
++    font-family: "FontAwesome";
++    margin-right: 5px;
++    content: "\f06a";
++}
++
++.admonition.warning > .admonition-title {
++    background-color: #f0b37e;
++}
++
++.admonition.warning {
++    background-color: #ffedcc;
++}
++
++.admonition.note > .admonition-title {
++    background-color: #6ab0de;
++}
++
++.admonition.note {
++    background-color: #e7f2fa;
++}
++
++.admonition.tip > .admonition-title {
++    background-color: #1abc9c;
++}
++
++.admonition.tip {
++    background-color: #dbfaf4;
++}
++
++
++/* footnotes */
++.footnote {
++    padding-left: 0.8em;
++    border-left: 2px solid #ccc;
++}
++
++/* Search page */
++#search-results .category {
++    font-size: smaller;
++}
++
++/* Overriding the <code> block style of highligh.js.
++ * We have to override the padding and the background-color, since we style this
++ * part ourselves. Specifically, we style the <pre> surrounding the <code>, while
++ * highlight.js applies the .hljs style directly to the <code> tag.
++ */
++.hljs {
++    background-color: transparent;
++    padding: 0;
++}
++
++@media only screen and (max-width: 768px) {
++    nav.toc {
++        position: fixed;
++        width: 16em;
++        left: -16em;
++        -webkit-overflow-scrolling: touch;
++        -webkit-transition-property: left; /* Safari */
++        -webkit-transition-duration: 0.3s; /* Safari */
++        transition-property: left;
++        transition-duration: 0.3s;
++        -webkit-transition-timing-function: ease-out; /* Safari */
++        transition-timing-function: ease-out;
++        z-index: 2;
++        box-shadow: 5px 0px 5px 0px rgb(210,210,210);
++    }
++
++    nav.toc.show {
++        left: 0;
++    }
++
++    article {
++        margin-left: 0;
++        padding: 3em 0.9em 0 0.9em; /* top right bottom left */
++        overflow-wrap: break-word;
++    }
++
++    article > header {
++        position: fixed;
++        left: 0;
++        z-index: 1;
++    }
++
++    article > header nav, hr {
++        display: none;
++    }
++
++    article > header div#topbar {
++        display: block; /* is mobile */
++        position: fixed;
++        width: 100%;
++        height: 1.5em;
++        padding-top: 1em;
++        padding-bottom: 1em;
++        background-color: #fcfcfc;
++        box-shadow: 0 1px 3px rgba(0,0,0,.26);
++        top: 0;
++        -webkit-transition-property: top; /* Safari */
++        -webkit-transition-duration: 0.3s; /* Safari */
++        transition-property: top;
++        transition-duration: 0.3s;
++    }
++
++    article > header div#topbar.headroom--unpinned.headroom--not-top.headroom--not-bottom {
++        top: -4em;
++        -webkit-transition-property: top; /* Safari */
++        -webkit-transition-duration: 0.7s; /* Safari */
++        transition-property: top;
++        transition-duration: 0.7s;
++    }
++
++    article > header div#topbar span {
++        width: 80%;
++        height: 1.5em;
++        margin-top: -0.1em;
++        margin-left: 0.9em;
++        font-size: 1.2em;
++        overflow: hidden;
++    }
++
++    article > header div#topbar a.fa-bars {
++        float: right;
++        padding: 0.6em;
++        margin-top: -0.6em;
++        margin-right: 0.3em;
++        font-size: 1.5em;
++    }
++
++    article > header div#topbar a.fa-bars:visited {
++        color: #3091d1;
++    }
++
++    article table {
++        overflow-x: auto;
++        display: block;
++    }
++
++    article div.MathJax_Display {
++        overflow: scroll;
++    }
++
++    article span.MathJax {
++        overflow: hidden;
++    }
++}
++
++@media only screen and (max-width: 320px) {
++    body {
++        font-size: 15px;
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..661e7e5571896a9e755fdf978cc94c8439d8c6ec
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,133 @@@
++/*
++ * Part of Documenter.jl
++ *     https://github.com/JuliaDocs/Documenter.jl
++ *
++ * License: MIT
++ */
++
++requirejs.config({
++    paths: {
++        'jquery': 'file:///usr/share/javascript/jquery/jquery.min.js',
++        'jqueryui': 'file:///usr/share/javascript/jquery-ui/jquery-ui.min.js',
++              //'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.9.3/headroom.min',
++              'headroom': 'http://localhost',
++        'mathjax': 'file:///usr/share/javascript/mathjax/MathJax.js?config=TeX-AMS_HTML',
++        'highlight': 'file:///usr/lib/nodejs/highlight.js/highlight.js',
++        'highlight-julia': 'file:////usr/lib/nodejs/highlight.js/languages/julia.js',
++        'highlight-julia-repl': 'file:////usr/lib/nodejs/highlight.js/languages/julia-repl.js',
++    },
++    shim: {
++        'mathjax' : {
++            exports: "MathJax"
++        },
++        'highlight-julia': ['highlight'],
++        'highlight-julia-repl': ['highlight'],
++    }
++});
++
++// Load MathJax
++require(['mathjax'], function(MathJax) {
++    MathJax.Hub.Config({
++      "tex2jax": {
++        inlineMath: [['$','$'], ['\\(','\\)']],
++        processEscapes: true
++      }
++    });
++    MathJax.Hub.Config({
++      config: ["MMLorHTML.js"],
++      jax: [
++        "input/TeX",
++        "output/HTML-CSS",
++        "output/NativeMML"
++      ],
++      extensions: [
++        "MathMenu.js",
++        "MathZoom.js",
++        "TeX/AMSmath.js",
++        "TeX/AMSsymbols.js",
++        "TeX/autobold.js",
++        "TeX/autoload-all.js"
++      ]
++    });
++    MathJax.Hub.Config({
++      TeX: { equationNumbers: { autoNumber: "AMS" } }
++    });
++})
++
++require(['jquery', 'highlight', 'highlight-julia', 'highlight-julia-repl'], function($, hljs) {
++    $(document).ready(function() {
++        hljs.initHighlighting();
++    })
++
++})
++
++// update the version selector with info from the siteinfo.js and ../versions.js files
++require(['jquery'], function($) {
++    $(document).ready(function() {
++        var version_selector = $("#version-selector");
++
++        // add the current version to the selector based on siteinfo.js, but only if the selector is empty
++        if (typeof DOCUMENTER_CURRENT_VERSION !== 'undefined' && $('#version-selector > option').length == 0) {
++            var option = $("<option value='#' selected='selected'>" + DOCUMENTER_CURRENT_VERSION + "</option>");
++            version_selector.append(option);
++        }
++
++        if (typeof DOC_VERSIONS !== 'undefined') {
++            var existing_versions = $('#version-selector > option');
++            var existing_versions_texts = existing_versions.map(function(i,x){return x.text});
++            DOC_VERSIONS.forEach(function(each) {
++                var version_url = documenterBaseURL + "/../" + each;
++                var existing_id = $.inArray(each, existing_versions_texts);
++                // if not already in the version selector, add it as a new option,
++                // otherwise update the old option with the URL and enable it
++                if (existing_id == -1) {
++                    var option = $("<option value='" + version_url + "'>" + each + "</option>");
++                    version_selector.append(option);
++                } else {
++                    var option = existing_versions[existing_id];
++                    option.value = version_url;
++                    option.disabled = false;
++                }
++            });
++        }
++
++        // only show the version selector if the selector has been populated
++        if ($('#version-selector > option').length > 0) {
++            version_selector.css("visibility", "visible");
++        }
++
++        // Scroll the navigation bar to the currently selected menu item
++        $("nav.toc > ul").get(0).scrollTop = $(".current").get(0).offsetTop - $("nav.toc > ul").get(0).offsetTop;
++    })
++
++})
++
++// mobile
++require(['jquery', 'headroom'], function($, Headroom) {
++    $(document).ready(function() {
++        var navtoc = $("nav.toc");
++        $("nav.toc li.current a.toctext").click(function() {
++            navtoc.toggleClass('show');
++        });
++        $("article > header div#topbar a.fa-bars").click(function(ev) {
++            ev.preventDefault();
++            navtoc.toggleClass('show');
++            if (navtoc.hasClass('show')) {
++                var title = $("article > header div#topbar span").text();
++                $("nav.toc ul li a:contains('" + title + "')").focus();
++            }
++        });
++        $("article#docs").bind('click', function(ev) {
++            if ($(ev.target).is('div#topbar a.fa-bars')) {
++                return;
++            }
++            if (navtoc.hasClass('show')) {
++                navtoc.removeClass('show');
++            }
++        });
++        if ($("article > header div#topbar").css('display') == 'block') {
++            var headroom = new Headroom(document.querySelector("article > header div#topbar"), {"tolerance": {"up": 10, "down": 10}});
++            headroom.init();
++        }
++    })
++})
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f99b3786cab52700a8b382181816c1e685eb4b16
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,250 @@@
++/*
++ * Part of Documenter.jl
++ *     https://github.com/JuliaDocs/Documenter.jl
++ *
++ * License: MIT
++ */
++
++// parseUri 1.2.2
++// (c) Steven Levithan <stevenlevithan.com>
++// MIT License
++function parseUri (str) {
++      var     o   = parseUri.options,
++              m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
++              uri = {},
++              i   = 14;
++
++      while (i--) uri[o.key[i]] = m[i] || "";
++
++      uri[o.q.name] = {};
++      uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
++              if ($1) uri[o.q.name][$1] = $2;
++      });
++
++      return uri;
++};
++parseUri.options = {
++      strictMode: false,
++      key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
++      q:   {
++              name:   "queryKey",
++              parser: /(?:^|&)([^&=]*)=?([^&]*)/g
++      },
++      parser: {
++              strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
++              loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
++      }
++};
++
++requirejs.config({
++    paths: {
++        'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min',
++        'lunr': 'https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.1/lunr.min',
++        'lodash': 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min',
++    }
++});
++
++var currentScript = document.currentScript;
++
++require(["jquery", "lunr", "lodash"], function($, lunr, _) {
++    $("#search-form").submit(function(e) {
++        e.preventDefault()
++    })
++
++    // list below is the lunr 2.1.3 list minus the intersect with names(Base)
++    // (all, any, get, in, is, which) and (do, else, for, let, where, while, with)
++    // ideally we'd just filter the original list but it's not available as a variable
++    lunr.stopWordFilter = lunr.generateStopWordFilter([
++        'a',
++        'able',
++        'about',
++        'across',
++        'after',
++        'almost',
++        'also',
++        'am',
++        'among',
++        'an',
++        'and',
++        'are',
++        'as',
++        'at',
++        'be',
++        'because',
++        'been',
++        'but',
++        'by',
++        'can',
++        'cannot',
++        'could',
++        'dear',
++        'did',
++        'does',
++        'either',
++        'ever',
++        'every',
++        'from',
++        'got',
++        'had',
++        'has',
++        'have',
++        'he',
++        'her',
++        'hers',
++        'him',
++        'his',
++        'how',
++        'however',
++        'i',
++        'if',
++        'into',
++        'it',
++        'its',
++        'just',
++        'least',
++        'like',
++        'likely',
++        'may',
++        'me',
++        'might',
++        'most',
++        'must',
++        'my',
++        'neither',
++        'no',
++        'nor',
++        'not',
++        'of',
++        'off',
++        'often',
++        'on',
++        'only',
++        'or',
++        'other',
++        'our',
++        'own',
++        'rather',
++        'said',
++        'say',
++        'says',
++        'she',
++        'should',
++        'since',
++        'so',
++        'some',
++        'than',
++        'that',
++        'the',
++        'their',
++        'them',
++        'then',
++        'there',
++        'these',
++        'they',
++        'this',
++        'tis',
++        'to',
++        'too',
++        'twas',
++        'us',
++        'wants',
++        'was',
++        'we',
++        'were',
++        'what',
++        'when',
++        'who',
++        'whom',
++        'why',
++        'will',
++        'would',
++        'yet',
++        'you',
++        'your'
++        ])
++
++    // add . as a separator, because otherwise "title": "Documenter.Anchors.add!"
++    // would not find anything if searching for "add!", only for the entire qualification
++    lunr.tokenizer.separator = /[\s\-\.]+/
++
++    // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names
++    lunr.trimmer = function (token) {
++        return token.update(function (s) {
++            return s.replace(/^[^a-zA-Z0-9@!]+/, '').replace(/[^a-zA-Z0-9@!]+$/, '')
++        })
++    }
++
++    lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'juliaStopWordFilter')
++    lunr.Pipeline.registerFunction(lunr.trimmer, 'juliaTrimmer')
++
++    var index = lunr(function () {
++        this.ref('location')
++        this.field('title')
++        this.field('text')
++        documenterSearchIndex['docs'].forEach(function(e) {
++            this.add(e)
++        }, this)
++    })
++    var store = {}
++
++    documenterSearchIndex['docs'].forEach(function(e) {
++        store[e.location] = {title: e.title, category: e.category}
++    })
++
++    $(function(){
++        function update_search(querystring) {
++            tokens = lunr.tokenizer(querystring)
++            results = index.query(function (q) {
++                tokens.forEach(function (t) {
++                    q.term(t.toString(), {
++                        fields: ["title"],
++                        boost: 100,
++                        usePipeline: false,
++                        editDistance: 0,
++                        wildcard: lunr.Query.wildcard.NONE
++                    })
++                    q.term(t.toString(), {
++                        fields: ["title"],
++                        boost: 10,
++                        usePipeline: false,
++                        editDistance: 2,
++                        wildcard: lunr.Query.wildcard.NONE
++                    })
++                    q.term(t.toString(), {
++                        fields: ["text"],
++                        boost: 1,
++                        usePipeline: true,
++                        editDistance: 0,
++                        wildcard: lunr.Query.wildcard.NONE
++                    })
++                })
++            })
++            $('#search-info').text("Number of results: " + results.length)
++            $('#search-results').empty()
++            results.forEach(function(result) {
++                data = store[result.ref]
++                link = $('<a>')
++                link.text(data.title)
++                link.attr('href', documenterBaseURL+'/'+result.ref)
++                cat = $('<span class="category">('+data.category+')</span>')
++                li = $('<li>').append(link).append(" ").append(cat)
++                $('#search-results').append(li)
++            })
++        }
++
++        function update_search_box() {
++            querystring = $('#search-query').val()
++            update_search(querystring)
++        }
++
++        $('#search-query').keyup(_.debounce(update_search_box, 250))
++        $('#search-query').change(update_search_box)
++
++        search_query_uri = parseUri(window.location).queryKey["q"]
++        if(search_query_uri !== undefined) {
++            search_query = decodeURIComponent(search_query_uri.replace(/\+/g, '%20'))
++            $("#search-query").val(search_query)
++        }
++        update_search_box();
++    })
++})
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ad71724091839eb7e65c2d26aae30589e027b473
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,77 @@@
++% font settings
++\usepackage{fontspec, newunicodechar, polyglossia}
++
++\setsansfont{Lato}[Scale=MatchLowercase, Ligatures=TeX]
++\setmonofont{Roboto Mono}[Scale=MatchLowercase]
++\renewcommand{\familydefault}{\sfdefault}
++%
++
++% colours
++\usepackage{xcolor}
++
++\definecolor{light-blue}{HTML}{6b85dd}
++\definecolor{dark-blue}{HTML}{4266d5}
++\definecolor{light-red}{HTML}{d66661}
++\definecolor{dark-red}{HTML}{c93d39}
++\definecolor{light-green}{HTML}{6bab5b}
++\definecolor{dark-green}{HTML}{3b972e}
++\definecolor{light-purple}{HTML}{aa7dc0}
++\definecolor{dark-purple}{HTML}{945bb0}
++%
++
++% maths
++\usepackage{amsmath, amssymb}
++%
++
++% listings
++\usepackage{listings, minted}
++
++\lstset{
++    basicstyle = \small\ttfamily,
++    breaklines = true,
++    columns = fullflexible,
++    frame = leftline,
++    keepspaces = true,
++    showstringspaces = false,
++    xleftmargin = 3pt,
++}
++
++\setminted{
++    breaklines = true,
++    fontsize = \small,
++    frame = leftline,
++}
++%
++
++% tables
++\usepackage{tabulary}
++%
++
++% hyperref
++\usepackage{hyperref}
++\hypersetup{
++    pdfpagelabels,
++    bookmarks,
++    hyperindex,
++    unicode = true,
++    linkcolor = dark-blue,
++    urlcolor = dark-purple,
++    colorlinks = true,
++}
++%
++
++% table of contents
++\maxtocdepth{subsection}
++%
++
++% paragraphs
++\setlength{\parindent}{0pt}
++\nonzeroparskip
++%
++
++% adjust margins
++\setulmarginsandblock{1.5in}{1in}{*}
++\setlrmarginsandblock{1.5in}{1in}{*}
++\setheaderspaces{1in}{*}{*}
++\checkandfixthelayout
++%
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f7ae84ab159d70fecd8713b3e6ccdc59bb324d6a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++div.wy-menu-vertical ul.current li.toctree-l3 a {
++  font-weight: bold;
++}
++
++a.documenter-source {
++  float: right;
++}
++
++.documenter-methodtable pre {
++    margin-left: 0px;
++    margin-right: 0px;
++    margin-top:  0px;
++    padding:     0px;
++}
++
++.documenter-methodtable pre.documenter-inline {
++    display: inline;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3561b109f9faa9dbe02247d56c79904b232a5659
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++MathJax.Hub.Config({
++  "tex2jax": {
++    inlineMath: [['$','$'], ['\\(','\\)']],
++    processEscapes: true
++  }
++});
++MathJax.Hub.Config({
++  config: ["MMLorHTML.js"],
++  jax: [
++    "input/TeX",
++    "output/HTML-CSS",
++    "output/NativeMML"
++  ],
++  extensions: [
++    "MathMenu.js",
++    "MathZoom.js",
++    "TeX/AMSmath.js",
++    "TeX/AMSsymbols.js",
++    "TeX/autobold.js",
++    "TeX/autoload-all.js"
++  ]
++});
++MathJax.Hub.Config({
++  TeX: { equationNumbers: { autoNumber: "AMS" } }
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4fbdc4772d56a7197a3b6bedab54e40d21bb6ff0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++[deps]
++Coverage = "a2441757-f6aa-5fb2-8edb-039e3f45d037"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c15a01cbbfcf0196ee42e9e436201b2b9cd521d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++# Only run coverage from linux nightly build on travis.
++get(ENV, "TRAVIS_OS_NAME", "")       == "linux"   || exit()
++get(ENV, "TRAVIS_JULIA_VERSION", "") == "nightly" || exit()
++
++using Coverage
++
++cd(joinpath(dirname(@__FILE__), "..")) do
++    Codecov.submit(Codecov.process_folder())
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..849bca9eb78f2801cfb28aaec558f4695e4f9f69
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,81 @@@
++[[Base64]]
++uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
++
++[[Dates]]
++deps = ["Printf"]
++uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
++
++[[Distributed]]
++deps = ["LinearAlgebra", "Random", "Serialization", "Sockets"]
++uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
++
++[[DocStringExtensions]]
++deps = ["LibGit2", "Markdown", "Pkg", "Test"]
++git-tree-sha1 = "a016e0bfe98a748c4488e2248c2ef4c67d6fdd35"
++uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
++version = "0.5.0"
++
++[[DocumenterTools]]
++deps = ["Base64", "DocStringExtensions", "LibGit2"]
++git-tree-sha1 = "519f8026e8f719ec018b70cfb394ae3756b427b1"
++repo-rev = "master"
++repo-url = "https://github.com/JuliaDocs/DocumenterTools.jl"
++uuid = "46bb7b6e-9a58-11e8-21f8-9f2f45a0fcba"
++version = "0.0.0"
++
++[[InteractiveUtils]]
++deps = ["LinearAlgebra", "Markdown"]
++uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
++
++[[LibGit2]]
++uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
++
++[[Libdl]]
++uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
++
++[[LinearAlgebra]]
++deps = ["Libdl"]
++uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
++
++[[Logging]]
++uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
++
++[[Markdown]]
++deps = ["Base64"]
++uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
++
++[[Pkg]]
++deps = ["Dates", "LibGit2", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"]
++uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
++
++[[Printf]]
++deps = ["Unicode"]
++uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
++
++[[REPL]]
++deps = ["InteractiveUtils", "Markdown", "Sockets"]
++uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
++
++[[Random]]
++deps = ["Serialization"]
++uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
++
++[[SHA]]
++uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
++
++[[Serialization]]
++uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
++
++[[Sockets]]
++uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
++
++[[Test]]
++deps = ["Distributed", "InteractiveUtils", "Logging", "Random"]
++uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
++
++[[UUIDs]]
++deps = ["Random"]
++uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
++
++[[Unicode]]
++uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..359718f8da8e67446f13145782c9207d8179cbf2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++[deps]
++DocumenterTools = "46bb7b6e-9a58-11e8-21f8-9f2f45a0fcba"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ca2870d9a99346bce76a2c8f9d810a57b0835a6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,56 @@@
++using Documenter, DocumenterTools
++
++makedocs(
++    modules = [Documenter, DocumenterTools],
++    clean = false,
++    assets = ["assets/favicon.ico"],
++    sitename = "Documenter.jl",
++    authors = "Michael Hatherly, Morten Piibeleht, and contributors.",
++    analytics = "UA-89508993-1",
++    linkcheck = !("skiplinks" in ARGS),
++    pages = [
++        "Home" => "index.md",
++        "Manual" => Any[
++            "Guide" => "man/guide.md",
++            "man/examples.md",
++            "man/syntax.md",
++            "man/doctests.md",
++            "man/latex.md",
++            hide("man/hosting.md", [
++                "man/hosting/walkthrough.md"
++            ]),
++            "man/other-formats.md",
++        ],
++        "Library" => Any[
++            "Public" => "lib/public.md",
++            hide("Internals" => "lib/internals.md", Any[
++                "lib/internals/anchors.md",
++                "lib/internals/builder.md",
++                "lib/internals/cross-references.md",
++                "lib/internals/docchecks.md",
++                "lib/internals/docsystem.md",
++                "lib/internals/doctests.md",
++                "lib/internals/documenter.md",
++                "lib/internals/documentertools.md",
++                "lib/internals/documents.md",
++                "lib/internals/dom.md",
++                "lib/internals/expanders.md",
++                "lib/internals/formats.md",
++                "lib/internals/mdflatten.md",
++                "lib/internals/selectors.md",
++                "lib/internals/textdiff.md",
++                "lib/internals/utilities.md",
++                "lib/internals/writers.md",
++            ])
++        ],
++        "contributing.md",
++    ],
++    # Use clean URLs, unless built as a "local" build
++    html_prettyurls = !("local" in ARGS),
++    html_canonical = "https://juliadocs.github.io/Documenter.jl/stable/",
++)
++
++deploydocs(
++    repo = "github.com/JuliaDocs/Documenter.jl.git",
++    target = "build",
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d7931951e12841f34f95a647d7dc5992259fbd5d
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c0c8a1be405a1b348389887d404f1cf15e10b81
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..51f7432bc6a4848eeabddb1f5f246f1452853ab0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,59 @@@
++# Contributing
++
++This page details the some of the guidelines that should be followed when contributing to this package.
++
++
++## Branches
++
++From `Documenter` version `0.3` onwards `release-*` branches are used for tagged minor versions of this package. This follows the same approach used in the main Julia repository, albeit on a much more modest scale.
++
++Please open pull requests against the `master` branch rather than any of the `release-*` branches whenever possible.
++
++### Backports
++
++Bug fixes are backported to the `release-*` branches using `git cherry-pick -x` by a JuliaDocs member and will become available in point releases of that particular minor version of the package.
++
++Feel free to nominate commits that should be backported by opening an issue. Requests for new point releases to be tagged in `METADATA.jl` can also be made in the same way.
++
++### `release-*` branches
++
++  * Each new minor version `x.y.0` gets a branch called `release-x.y` (a [protected branch](https://help.github.com/articles/about-protected-branches/)).
++  * New versions are usually tagged only from the `release-x.y` branches.
++  * For patch releases, changes get backported to the `release-x.y` branch via a single PR with the standard name "Backports for x.y.z" and label ["Type: Backport"](https://github.com/JuliaDocs/Documenter.jl/pulls?q=label%3A%22Type%3A+Backport%22). The PR message links to all the PRs that are providing commits to the backport. The PR gets merged as a merge commit (i.e. not squashed).
++  * The old `release-*` branches may be removed once they have outlived their usefulness.
++  * Patch version [milestones](https://github.com/JuliaDocs/Documenter.jl/milestones) are used to keep track of which PRs get backported etc.
++
++
++## Style Guide
++
++Follow the style of the surrounding text when making changes. When adding new features please try to stick to the following points whenever applicable.
++
++### Julia
++
++  * 4-space indentation;
++  * modules spanning entire files should not be indented, but modules that have surrounding code should;
++  * no blank lines at the start or end of files;
++  * do not manually align syntax such as `=` or `::` over adjacent lines;
++  * use `function ... end` when a method definition contains more than one toplevel expression;
++  * related short-form method definitions don't need a new line between them;
++  * unrelated or long-form method definitions must have a blank line separating each one;
++  * surround all binary operators with whitespace except for `::`, `^`, and `:`;
++  * files containing a single `module ... end` must be named after the module;
++  * method arguments should be ordered based on the amount of usage within the method body;
++  * methods extended from other modules must follow their inherited argument order, not the above rule;
++  * explicit `return` should be preferred except in short-form method definitions;
++  * avoid dense expressions where possible e.g. prefer nested `if`s over complex nested `?`s;
++  * include a trailing `,` in vectors, tuples, or method calls that span several lines;
++  * do not use multiline comments (`#=` and `=#`);
++  * wrap long lines as near to 92 characters as possible, this includes docstrings;
++  * follow the standard naming conventions used in `Base`.
++
++### Markdown
++
++  * Use unbalanced `#` headers, i.e. no `#` on the right hand side of the header text;
++  * include a single blank line between toplevel blocks;
++  * unordered lists must use `*` bullets with two preceding spaces;
++  * do *not* hard wrap lines;
++  * use emphasis (`*`) and bold (`**`) sparingly;
++  * always use fenced code blocks instead of indented blocks;
++  * follow the conventions outlined in the Julia documentation page on documentation.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8a5b50c5dc76e3ae721d61545db1f9a0b44f22cb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++# Documenter.jl
++
++*A documentation generator for Julia.*
++
++A package for building documentation from docstrings and markdown files.
++
++!!! note
++
++    Please read through the
++    [Documentation](https://docs.julialang.org/en/latest/manual/documentation/) section
++    of the main Julia manual if this is your first time using Julia's documentation system.
++    Once you've read through how to write documentation for your code then come back here.
++
++## Package Features
++
++- Write all your documentation in [Markdown](https://en.wikipedia.org/wiki/Markdown).
++- Minimal configuration.
++- Supports Julia `0.7` and `1.0`.
++- Doctests Julia code blocks.
++- Cross references for docs and section headers.
++- [``\LaTeX`` syntax](@ref latex_syntax) support.
++- Checks for missing docstrings and incorrect cross references.
++- Generates tables of contents and docstring indexes.
++- Automatically builds and deploys docs from Travis to GitHub Pages.
++
++The [Package Guide](@ref) provides a tutorial explaining how to get started using Documenter.
++
++Some examples of packages using Documenter can be found on the [Examples](@ref) page.
++
++See the [Index](@ref main-index) for the complete list of documented functions and types.
++
++## Manual Outline
++
++```@contents
++Pages = [
++    "man/guide.md",
++    "man/examples.md",
++    "man/syntax.md",
++    "man/doctests.md",
++    "man/hosting.md",
++    "man/latex.md",
++    "man/contributing.md",
++]
++Depth = 1
++```
++
++## Library Outline
++
++```@contents
++Pages = ["lib/public.md", "lib/internals.md"]
++```
++
++### [Index](@id main-index)
++
++```@index
++Pages = ["lib/public.md"]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b78ce0e726699a9dff19ca61d49cc9c1c38c20e9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++# Internal Documentation
++
++This page lists all the documented internals of the `Documenter` module and submodules.
++
++## Contents
++
++```@contents
++Pages = [joinpath("internals", f) for f in readdir("internals")]
++```
++
++## Index
++
++A list of all internal documentation sorted by module.
++
++```@index
++Pages = [joinpath("internals", f) for f in readdir("internals")]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9d8fa231823303f3ff8c7d45e9c1eb8f01780eed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Anchors
++
++```@autodocs
++Modules = [Documenter.Anchors]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..366b6cdcec07c19a9f7c638989afc329ba5932e2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Builder
++
++```@autodocs
++Modules = [Documenter.Builder]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4a05a0eabed4da72fa33df89a5d154410e1808fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# CrossReferences
++
++```@autodocs
++Modules = [Documenter.CrossReferences]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..229bd1860870b5aac2a6a5ffefda4fc78f552e3d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# DocChecks
++
++```@autodocs
++Modules = [Documenter.DocChecks]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..39f1be38fd1e3c5083e02bb83e01d2731369b919
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# DocSystem
++
++```@autodocs
++Modules = [Documenter.DocSystem]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d2ef53d992468314e4da49193cf52009d20f7af8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# DocTests
++
++```@autodocs
++Modules = [Documenter.DocTests]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..de28117576cc1a38abd8c9ff6de6ab3a1b99e519
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++# Documenter
++
++```@docs
++Documenter.gitrm_copy
++Documenter.git_push
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba3966f5010d37a282a1acc600888170b7eee00d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++# DocumenterTools
++
++```@docs
++DocumenterTools.package_devpath
++```
++
++## Generator
++
++```@autodocs
++Modules = [DocumenterTools.Generator]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4589b71a1785539d1deb41773ea3247305a47b96
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Documents
++
++```@autodocs
++Modules = [Documenter.Documents]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ce030713cd94e4f2097c60f2fc7ec325be72436c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# DOM
++
++```@autodocs
++Modules = [Documenter.Utilities.DOM]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..605a98b077ed2d2d5c8674fd09d379c6e66ff1ca
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Expanders
++
++```@autodocs
++Modules = [Documenter.Expanders]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..baaedd5990455c827cd9bb45f026f49db71bb833
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Formats
++
++```@autodocs
++Modules = [Documenter.Formats]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cc46364ab9714a3186d06cf3e7e19863655668de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# MDFlatten
++
++```@autodocs
++Modules = [Documenter.Utilities.MDFlatten]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..56e4fea3742a5ebf1fcc30942e9feab964a2beef
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Selectors
++
++```@autodocs
++Modules = [Documenter.Selectors]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2c6b6fdd111acc6d49099351d562815db81ca366
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# TextDiff
++
++```@autodocs
++Modules = [Documenter.Utilities.TextDiff]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cc940381fe644aa8671b8a12938ae6dda6b1c093
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# Utilities
++
++```@autodocs
++Modules = [Documenter.Utilities]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3333376803718e569a92614b9b90e0bf2cd26529
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++# Writers
++
++```@autodocs
++Modules = [
++    Documenter.Writers,
++    Documenter.Writers.MarkdownWriter,
++    Documenter.Writers.HTMLWriter,
++    Documenter.Writers.LaTeXWriter,
++]
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f0ebbd3656b104cab7523e0674e60918e667454d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,36 @@@
++# Public Documentation
++
++Documentation for `Documenter.jl`'s public interface.
++
++See [Internal Documentation](@ref) for internal package docs covering all submodules.
++
++## Contents
++
++```@contents
++Pages = ["public.md"]
++```
++
++## Index
++
++```@index
++Pages = ["public.md"]
++```
++
++## Public Interface
++
++```@docs
++Documenter
++makedocs
++hide
++deploydocs
++Deps
++Deps.pip
++```
++
++## DocumenterTools
++
++```@docs
++DocumenterTools.generate
++DocumenterTools.Travis.genkeys
++DocumenterTools.Travis
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..aacc188d0dcaa9cb273a0abc35e87b01ba791a4a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,310 @@@
++# Doctests
++
++Documenter will, by default, try to run `jldoctest` code blocks that it finds in the generated
++documentation. This can help to avoid documentation examples from becoming outdated,
++incorrect, or misleading. It's recommended that as many of a package's examples be runnable
++by Documenter's doctest.
++
++This section of the manual outlines how to go about enabling doctests for code blocks in
++your package's documentation.
++
++## "Script" Examples
++
++The first, of two, types of doctests is the "script" code block. To make Documenter detect
++this kind of code block the following format must be used:
++
++````markdown
++```jldoctest
++a = 1
++b = 2
++a + b
++
++# output
++
++3
++```
++````
++
++The code block's "language" must be `jldoctest` and must include a line containing the text `#
++output`. The text before this line is the contents of the script which is run. The text that
++appears after `# output` is the textual representation that would be shown in the Julia REPL
++if the script had been `include`d.
++
++The actual output produced by running the "script" is compared to the expected result and
++any difference will result in [`makedocs`](@ref) throwing an error and terminating.
++
++Note that the amount of whitespace appearing above and below the `# output` line is not
++significant and can be increased or decreased if desired.
++
++It is possible to suppress the output from the doctest by setting the `output` keyword
++argument to `false`, for example
++
++````markdown
++```jldoctest; output = false
++a = 1
++b = 2
++a + b
++
++# output
++
++3
++```
++````
++
++Note that the output of the script will still be compared to the expected result,
++i.e. what is `# output` section, but the `# output` section will be suppressed in
++the rendered documentation.
++
++## REPL Examples
++
++The other kind of doctest is a simulated Julia REPL session. The following format is
++detected by Documenter as a REPL doctest:
++
++````markdown
++```jldoctest
++julia> a = 1
++1
++
++julia> b = 2;
++
++julia> c = 3;  # comment
++
++julia> a + b + c
++6
++```
++````
++
++As with script doctests, the code block must have it's language set to `jldoctest`. When a code
++block contains one or more `julia> ` at the start of a line then it is assumed to be a REPL
++doctest. Semi-colons, `;`, at the end of a line works in the same way as in the Julia REPL
++and will suppress the output, although the line is still evaluated.
++
++Note that not all features of the REPL are supported such as shell and help modes.
++
++## Exceptions
++
++Doctests can also test for thrown exceptions and their stacktraces. Comparing of the actual
++and expected results is done by checking whether the expected result matches the start of
++the actual result. Hence, both of the following errors will match the actual result.
++
++````markdown
++```jldoctest
++julia> div(1, 0)
++ERROR: DivideError: integer division error
++ in div(::Int64, ::Int64) at ./int.jl:115
++
++julia> div(1, 0)
++ERROR: DivideError: integer division error
++```
++````
++
++If instead the first `div(1, 0)` error was written as
++
++````markdown
++```jldoctest
++julia> div(1, 0)
++ERROR: DivideError: integer division error
++ in div(::Int64, ::Int64) at ./int.jl:114
++```
++````
++
++where line `115` is replaced with `114` then the doctest will fail.
++
++In the second `div(1, 0)`, where no stacktrace is shown, it may appear to the reader that
++it is expected that no stacktrace will actually be displayed when they attempt to try to
++recreate the error themselves. To indicate to readers that the output result is truncated
++and does not display the entire (or any of) the stacktrace you may write `[...]` at the
++line where checking should stop, i.e.
++
++````markdown
++```jldoctest
++julia> div(1, 0)
++ERROR: DivideError: integer division error
++[...]
++```
++````
++
++## Preserving Definitions Between Blocks
++
++Every doctest block is evaluated inside its own `module`. This means that definitions
++(types, variables, functions etc.) from a block can *not* be used in the next block.
++For example:
++
++````markdown
++```jldoctest
++julia> foo = 42
++42
++```
++````
++
++The variable `foo` will not be defined in the next block:
++
++````markdown
++```jldoctest
++julia> println(foo)
++ERROR: UndefVarError: foo not defined
++```
++````
++
++To preserve definitions it is possible to label blocks in order to collect several blocks
++into the same module. All blocks with the same label (in the same file) will be evaluated
++in the same module, and hence share scope. This can be useful if the same definitions are
++used in more than one block, with for example text, or other doctest blocks, in between.
++Example:
++
++````markdown
++```jldoctest mylabel
++julia> foo = 42
++42
++```
++````
++
++Now, since the block below has the same label as the block above, the variable `foo` can
++be used:
++
++````markdown
++```jldoctest mylabel
++julia> println(foo)
++42
++```
++````
++
++!!! note
++
++    Labeled doctest blocks does not need to be consecutive (as in the example above) to be
++    included in the same module. They can be interspaced with unlabeled blocks or blocks
++    with another label.
++
++## Setup Code
++
++Doctests may require some setup code that must be evaluated prior to that of the actual
++example, but that should not be displayed in the final documentation. For this purpose a
++`@meta` block containing a `DocTestSetup = ...` value can be used. In the example below,
++the function `foo` is defined inside a `@meta` block. This block will be evaluated at
++the start of the following doctest blocks:
++
++````markdown
++```@meta
++DocTestSetup = quote
++    function foo(x)
++        return x^2
++    end
++end
++```
++
++```jldoctest
++julia> foo(2)
++4
++```
++
++```@meta
++DocTestSetup = nothing
++```
++````
++
++The `DocTestSetup = nothing` is not strictly necessary, but good practice nonetheless to
++help avoid unintentional definitions in following doctest blocks.
++
++Another option is to use the `setup` keyword argument, which is convenient for short definitions,
++and for setups needed in inline docstrings.
++
++````markdown
++```jldoctest; setup = :(foo(x) = x^2)
++julia> foo(2)
++4
++```
++````
++
++!!! note
++
++    The `DocTestSetup` and the `setup` values are **re-evaluated** at the start of *each* doctest block
++    and no state is shared between any code blocks.
++    To preserve definitions see [Preserving Definitions Between Blocks](@ref).
++
++## Filtering Doctests
++
++A part of the output of a doctest might be non-deterministic, e.g. pointer addresses and timings.
++It is therefore possible to filter a doctest so that the deterministic part can still be tested.
++
++A filter takes the form of a regular expression.
++In a doctest, each match in the expected output and the actual output is removed before the two outputs are compared.
++Filters are added globally, i.e. applied to all doctests in the documentation, by passing a list of regular expressions to
++`makedocs` with the keyword `doctestfilters`.
++
++For more fine grained control it is possible to define filters in `@meta` blocks by assigning them
++to the `DocTestFilters` variable, either as a single regular expression (`DocTestFilters = [r"foo"]`)
++or as a vector of several regex (`DocTestFilters = [r"foo", r"bar"]`).
++
++An example is given below where some of the non-deterministic output from `@time` is filtered.
++
++````markdown
++```@meta
++DocTestFilters = r"[0-9\.]+ seconds \(.*\)"
++```
++
++```jldoctest
++julia> @time [1,2,3,4]
++  0.000003 seconds (5 allocations: 272 bytes)
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++
++```@meta
++DocTestFilters = nothing
++```
++````
++
++The `DocTestFilters = nothing` is not strictly necessary, but good practice nonetheless to
++help avoid unintentional filtering in following doctest blocks.
++
++Another option is to use the `filter` keyword argument. This defines a doctest-local filter
++which is only active for the specific doctest. Note that such filters are not shared between
++named doctests either. It is possible to define a filter by a single regex (filter = r"foo")
++or as a list of regex (filter = [r"foo", r"bar"]). Example:
++
++````markdown
++```jldoctest; filter = r"[0-9\.]+ seconds \(.*\)"
++julia> @time [1,2,3,4]
++  0.000003 seconds (5 allocations: 272 bytes)
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++````
++
++!!! note
++
++    The global filters, filters defined in `@meta` blocks, and filters defined with the `filter`
++    keyword argument are all applied to each doctest.
++
++## Fixing Outdated Doctests
++
++To fix outdated doctests, the `doctest` flag to [`makedocs`](@ref) can be set to
++`doctest = :fix`. This will run the doctests, and overwrite the old results with
++the new output.
++
++!!! note
++
++    The `:fix` option currently only works for LF line endings (`'\n'`)
++
++!!! note
++
++    It is recommended to `git commit` any code changes before running the doctest fixing.
++    That way it is simple to restore to the previous state if the fixing goes wrong.
++
++!!! note
++
++    There are some corner cases where the fixing algorithm may replace the wrong code snippet.
++    It is therefore recommended to manually inspect the result of the fixing before committing.
++
++
++## Skipping Doctests
++
++Doctesting can be disabled by setting the [`makedocs`](@ref) keyword `doctest = false`.
++This should only be done when initially laying out the structure of a package's
++documentation, after which it's encouraged to always run doctests when building docs.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7319cb8f3036aa879b3e1a25c6b4a0346c0e33ac
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,67 @@@
++# Examples
++
++Sometimes the best way to learn how to use a new package is to look for
++examples of what others have already built with it.
++
++The following packages use Documenter to build their documentation and so
++should give a good overview of what this package is currently able to do.
++
++!!! note
++
++    Packages are listed alphabetically. If you have a package that uses Documenter then
++    please open a PR that adds it to the appropriate list below; a simple way to do so
++    is to navigate to
++    https://github.com/JuliaDocs/Documenter.jl/edit/master/docs/src/man/examples.md.
++
++    The `make.jl` file for all listed packages will be tested to check for potential
++    regressions prior to tagging new Documenter releases whenever possible.
++
++## Registered
++
++Packages that have tagged versions available in `METADATA.jl`.
++
++- [Augmentor.jl](https://evizero.github.io/Augmentor.jl/)
++- [BanditOpt.jl](https://v-i-s-h.github.io/BanditOpt.jl/latest/)
++- [BeaData.jl](https://stephenbnicar.github.io/BeaData.jl/latest/)
++- [Bio.jl](https://biojulia.net/Bio.jl/latest/)
++- [ControlSystems.jl](http://juliacontrol.github.io/ControlSystems.jl/latest/)
++- [Currencies.jl](https://juliafinance.github.io/Currencies.jl/latest/)
++- [DiscretePredictors.jl](https://github.com/v-i-s-h/DiscretePredictors.jl)
++- [Documenter.jl](https://juliadocs.github.io/Documenter.jl/latest/)
++- [EvolvingGraphs.jl](https://etymoio.github.io/EvolvingGraphs.jl/latest/)
++- [ExtractMacro.jl](https://carlobaldassi.github.io/ExtractMacro.jl/latest/)
++- [EzXML.jl](https://bicycle1885.github.io/EzXML.jl/latest/)
++- [FourierFlows.jl](https://FourierFlows.github.io/FourierFlows.jl/latest/)
++- [Gadfly.jl](http://gadflyjl.org/stable/)
++- [GeoStats.jl](http://juliohm.github.io/GeoStats.jl/latest/)
++- [Highlights.jl](https://juliadocs.github.io/Highlights.jl/latest/)
++- [IntervalConstraintProgramming.jl](https://juliaintervals.github.io/IntervalConstraintProgramming.jl/latest/)
++- [Luxor.jl](https://juliagraphics.github.io/Luxor.jl/stable/)
++- [MergedMethods.jl](https://michaelhatherly.github.io/MergedMethods.jl/latest/)
++- [Mimi.jl](http://anthofflab.berkeley.edu/Mimi.jl/stable/)
++- [NumericSuffixes.jl](https://michaelhatherly.github.io/NumericSuffixes.jl/latest/)
++- [OhMyREPL.jl](https://github.com/KristofferC/OhMyREPL.jl)
++- [OnlineStats.jl](http://joshday.github.io/OnlineStats.jl/latest/)
++- [POMDPs.jl](http://juliapomdp.github.io/POMDPs.jl/latest/)
++- [PhyloNetworks.jl](http://crsl4.github.io/PhyloNetworks.jl/latest/)
++- [PrivateModules.jl](https://michaelhatherly.github.io/PrivateModules.jl/latest/)
++- [Query.jl](http://www.queryverse.org/Query.jl/stable/)
++- [TaylorSeries.jl](http://www.juliadiff.org/TaylorSeries.jl/latest/)
++- [Weave.jl](http://weavejl.mpastell.com/stable/)
++
++## Documentation repositories
++
++Some projects or organizations maintain dedicated documentation repositories that are
++separate from specific packages.
++
++- [DifferentialEquations.jl](http://docs.juliadiffeq.org/latest/)
++- [JuliaDocs landing page](https://juliadocs.github.io/latest/)
++- [JuliaMusic](https://juliamusic.github.io/JuliaMusic_documentation.jl/latest/)
++- [Plots.jl](https://docs.juliaplots.org/latest/)
++
++## Unregistered
++
++Packages that are not available in `METADATA.jl` and may be works-in-progress.
++Please do take that into consideration when browsing this list.
++
++- [AnonymousTypes.jl](https://michaelhatherly.github.io/AnonymousTypes.jl/latest/)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..322d91bcb5b0934dcfd8fe9e727dca7c253bd129
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,327 @@@
++# Package Guide
++
++Documenter is designed to do one thing -- combine markdown files and inline docstrings from
++Julia's docsystem into a single inter-linked document. What follows is a step-by-step guide
++to creating a simple document.
++
++
++## Installation
++
++Documenter can be installed using the Julia package manager.
++From the Julia REPL, type `]` to enter the Pkg REPL mode and run
++
++```
++pkg> add Documenter
++```
++
++
++## Setting up the Folder Structure
++
++!!! note
++    The function [`DocumenterTools.generate`](@ref) from the `DocumenterTools` package
++    can generate the basic structure that Documenter expects.
++
++Firstly, we need a Julia module to document. This could be a package generated via
++`PkgDev.generate` or a single `.jl` script accessible via Julia's `LOAD_PATH`. For this
++guide we'll be using a package called `Example.jl` that has the following directory layout:
++
++```
++Example/
++    src/
++        Example.jl
++    ...
++```
++
++Note that the `...` just represent unimportant files and folders.
++
++We must decide on a location where we'd like to store the documentation for this package.
++It's recommended to use a folder named `docs/` in the toplevel of the package, like so
++
++```
++Example/
++    docs/
++        ...
++    src/
++        Example.jl
++    ...
++```
++
++Inside the `docs/` folder we need to add two things. A source folder which will contain the
++markdown files that will be used to build the finished document and a Julia script that will
++be used to control the build process. The following names are recommended
++
++```
++docs/
++    src/
++    make.jl
++```
++
++
++## Building an Empty Document
++
++With our `docs/` directory now setup we're going to build our first document. It'll just be
++a single empty file at the moment, but we'll be adding to it later on.
++
++Add the following to your `make.jl` file
++
++```julia
++using Documenter, Example
++
++makedocs(sitename="My Documentation")
++```
++
++This assumes you've installed Documenter as discussed in [Installation](@ref) and that your
++`Example.jl` package can be found by Julia.
++
++!!! note
++
++    If your source directory is not accessible through Julia's LOAD_PATH, you might wish to
++    add the following line at the top of make.jl
++
++    ```julia
++    push!(LOAD_PATH,"../src/")
++    ```
++
++Now add an `index.md` file to the `src/` directory. The name has no particular significance
++though and you may name it whatever you like. We'll stick to `index.md` for this guide.
++
++Leave the newly added file empty and then run the following command from the `docs/` directory
++
++```sh
++$ julia make.jl
++```
++
++Note that `$` just represents the prompt character. You don't need to type that.
++
++If you'd like to see the output from this command in color use
++
++```sh
++$ julia --color=yes make.jl
++```
++
++When you run that you should see the following output
++
++```
++Documenter: setting up build directory.
++Documenter: expanding markdown templates.
++Documenter: building cross-references.
++Documenter: running document checks.
++ > checking for missing docstrings.
++ > running doctests.
++ > checking footnote links.
++Documenter: populating indices.
++Documenter: rendering document.
++```
++
++The `docs/` folder should contain a new directory -- called `build/`. It's structure should
++look like the following
++
++```
++build/
++    assets/
++        arrow.svg
++        documenter.css
++        documenter.js
++        search.js
++    index.html
++    search.html
++    search_index.js
++```
++
++!!! warning
++
++    **Never** `git commit` the contents of `build` (or any other content generated by
++    Documenter) to your repository's `master` branch. Always commit generated files to the
++    `gh-pages` branch of your repository. This helps to avoid including unnecessary changes
++    for anyone reviewing commits that happen to include documentation changes.
++
++    See the [Hosting Documentation](@ref) section for details regarding how you should go
++    about setting this up correctly.
++
++At this point `build/index.html` should be an empty page since `src/index.md` is empty. You
++can try adding some text to `src/index.md` and re-running the `make.jl` file to see the
++changes.
++
++
++## Adding Some Docstrings
++
++Next we'll splice a docstring defined in the `Example` module into the `index.md` file. To
++do this first document a function in that module:
++
++```julia
++module Example
++
++export func
++
++"""
++    func(x)
++
++Returns double the number `x` plus `1`.
++"""
++func(x) = 2x + 1
++
++end
++```
++
++Then in the `src/index.md` file add the following
++
++````markdown
++# Example.jl Documentation
++
++```@docs
++func(x)
++```
++````
++
++When we next run `make.jl` the docstring for `Example.func(x)` should appear in place of
++the `@docs` block in `build/index.md`. Note that *more than one* object can be referenced
++inside a `@docs` block -- just place each one on a separate line.
++
++Note that a `@docs` block is evaluated in the `Main` module. This means that each object
++listed in the block must be visible there. The module can be changed to something else on
++a per-page basis with a `@meta` block as in the following
++
++````markdown
++# Example.jl Documentation
++
++```@meta
++CurrentModule = Example
++```
++
++```@docs
++func(x)
++```
++````
++
++### Filtering included docstrings
++
++In some cases you may want to include a docstring for a `Method` that extends a
++`Function` from a different module -- such as `Base`. In the following example we extend
++`Base.length` with a new definition for the struct `T` and also add a docstring:
++
++```julia
++struct T
++    # ...
++end
++
++"""
++Custom `length` docs for `T`.
++"""
++Base.length(::T) = 1
++```
++
++When trying to include this docstring with
++
++````markdown
++```@docs
++length
++```
++````
++
++all the docs for `length` will be included -- even those from other modules. There are two
++ways to solve this problem. Either include the type in the signature with
++
++````markdown
++```@docs
++length(::T)
++```
++````
++
++or declare the specific modules that [`makedocs`](@ref) should include with
++
++```julia
++makedocs(
++    # options
++    modules = [MyModule]
++)
++```
++
++
++## Cross Referencing
++
++It may be necessary to refer to a particular docstring or section of your document from
++elsewhere in the document. To do this we can make use of Documenter's cross-referencing
++syntax which looks pretty similar to normal markdown link syntax. Replace the contents of
++`src/index.md` with the following
++
++````markdown
++# Example.jl Documentation
++
++```@docs
++func(x)
++```
++
++- link to [Example.jl Documentation](@ref)
++- link to [`func(x)`](@ref)
++````
++
++So we just have to replace each link's url with `@ref` and write the name of the thing we'd
++link to cross-reference. For document headers it's just plain text that matches the name of
++the header and for docstrings enclose the object in backticks.
++
++This also works across different pages in the same way. Note that these sections and
++docstrings must be unique within a document.
++
++
++## Navigation
++
++Documenter can auto-generate tables of contents and docstring indexes for your document with
++the following syntax. We'll illustrate these features using our `index.md` file from the
++previous sections. Add the following to that file
++
++````markdown
++# Example.jl Documentation
++
++```@contents
++```
++
++## Functions
++
++```@docs
++func(x)
++```
++
++## Index
++
++```@index
++```
++````
++
++The `@contents` block will generate a nested list of links to all the section headers in
++the document. By default it will gather all the level 1 and 2 headers from every page in the
++document, but this can be adjusted using `Pages` and `Depth` settings as in the following
++
++````markdown
++```@contents
++Pages = ["foo.md", "bar.md"]
++Depth = 3
++```
++````
++
++The `@index` block will generate a flat list of links to all the docs that that have been
++spliced into the document using `@docs` blocks. As with the `@contents` block the pages to
++be included can be set with a `Pages = [...]` line. Since the list is not nested `Depth` is
++not supported for `@index`.
++
++
++## Pages in the Sidebar
++
++By default all the pages (`.md` files) in your source directory get added to the sidebar,
++sorted by their filenames. However, in most cases you want to use the `pages` argument to
++[`makedocs`](@ref) to control how the sidebar looks like. The basic usage is as follows:
++
++```julia
++makedocs(
++    ...,
++    pages = [
++        "page.md",
++        "Page title" => "page2.md",
++        "Subsection" => [
++            ...
++        ]
++    ]
++)
++```
++
++Using the `pages` argument you can organize your pages into subsections and hide some pages
++from the sidebar with the help of the [`hide`](@ref) functions.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1787afc3da67691711ca92cf87e23d0bf8dac9e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,262 @@@
++# Hosting Documentation
++
++After going through the [Package Guide](@ref) and [Doctests](@ref) page you will need to
++host the generated documentation somewhere for potential users to read. This guide will
++describe how to setup automatic updates for your package docs using the Travis build service
++and GitHub Pages. This is the same approach used by this package to host its own docs --
++the docs you're currently reading.
++
++!!! note
++
++    Following this guide should be the *final* step you take after you are comfortable with
++    the syntax and build process used by `Documenter.jl`. It is recommended that you only
++    proceed with the steps outlined here once you have successfully managed to build your
++    documentation locally with Documenter.
++
++    This guide assumes that you already have [GitHub](https://github.com/) and
++    [Travis](https://travis-ci.com/) accounts setup. If not then go set those up first and
++    then return here.
++
++
++## Overview
++
++Once set up correctly, the following will happen each time you push new updates to your
++package repository:
++
++- Travis buildbots will start up and run your package tests in a "Test" stage.
++- After the Test stage completes, a single bot will run a new "Documentation" stage, which
++  will build the documentation.
++- If the documentation is built successfully, the bot will attempt to push the generated
++  HTML pages back to GitHub.
++
++Note that the hosted documentation does not update when you make pull requests; you see
++updates only when you merge to `master` or push new tags.
++
++The following sections outline how to enable this for your own package.
++
++
++## SSH Deploy Keys
++
++Deploy keys provide push access to a *single* repository, to allow secure deployment of
++generated documentation from Travis to GitHub. The SSH keys can be generated with the
++`Travis.genkeys` from the [DocumenterTools](https://github.com/JuliaDocs/DocumenterTools.jl)
++package.
++
++!!! note
++
++    You will need several command line programs (`which`, `git` and `ssh-keygen`) to be
++    installed for the following steps to work. If DocumenterTools fails, please see the the
++    [SSH Deploy Keys Walkthrough](@ref) section for instruction on how to generate the keys
++    manually (including in Windows).
++
++
++Install and load DocumenterTools with
++
++```
++pkg> add DocumenterTools
++```
++```julia-repl
++julia> using DocumenterTools
++```
++
++Then call the [`Travis.genkeys`](@ref) function as follows:
++
++```julia-repl
++julia> using MyPackage
++julia> Travis.genkeys(MyPackage)
++```
++
++where `MyPackage` is the name of the package you would like to create deploy keys for. The
++output will look similar to the text below:
++
++```
++INFO: add the public key below to https://github.com/USER/REPO/settings/keys
++      with read/write access:
++
++[SSH PUBLIC KEY HERE]
++
++INFO: add a secure environment variable named 'DOCUMENTER_KEY' to
++      https://travis-ci.org/USER/REPO/settings with value:
++
++[LONG BASE64 ENCODED PRIVATE KEY]
++```
++
++Follow the instructions that are printed out, namely:
++
++ 1. Add the public ssh key to your settings page for the GitHub repository that you are
++    setting up by following the `.../settings/key` link provided. Click on **`Add deploy
++    key`**, enter the name **`documenter`** as the title, and copy the public key into the
++    **`Key`** field. Check **`Allow write access`** to allow Documenter to commit the
++    generated documentation to the repo.
++
++ 2. Next add the long private key to the Travis settings page using the provided link. Again
++    note that you should include **no whitespace** when copying the key. In the **`Environment
++    Variables`** section add a key with the name `DOCUMENTER_KEY` and the value that was printed
++    out. **Do not** set the variable to be displayed in the build log. Then click **`Add`**.
++
++    !!! warning "Security warning"
++
++        To reiterate: make sure that the "Display value in build log" option is **OFF** for
++        the variable, so that it does not get printed when the tests run. This
++        base64-encoded string contains the *unencrypted* private key that gives full write
++        access to your repository, so it must be kept safe.  Also, make sure that you never
++        expose this variable in your tests, nor merge any code that does. You can read more
++        about Travis environment variables in [Travis User Documentation](https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings).
++
++!!! note
++
++    There are more explicit instructions for adding the keys to GitHub and Travis in the
++    [SSH Deploy Keys Walkthrough](@ref) section of the manual.
++
++## `.travis.yml` Configuration
++
++To tell Travis that we want a new build stage we can add the following to the `.travis.yml`
++file:
++
++```yaml
++jobs:
++  include:
++    - stage: "Documentation"
++      julia: 1.0
++      os: linux
++      script:
++        - julia --project=docs/ -e 'using Pkg; Pkg.instantiate();
++                                    Pkg.develop(PackageSpec(path=pwd()))'
++        - julia --project=docs/ docs/make.jl
++      after_success: skip
++```
++
++where the `julia:` and `os:` entries decide the worker from which the docs are built and
++deployed. In the example above we will thus build and deploy the documentation from a linux
++worker running Julia 1.0. For more information on how to setup a build stage, see the Travis
++manual for [Build Stages](https://docs.travis-ci.com/user/build-stages).
++
++The three lines in the `script:` section do the following:
++
++ 1. Instantiate the doc-building environment (i.e. `docs/Project.toml`, see below).
++ 2. Install your package in the doc-build environment.
++ 3. Run the docs/make.jl script, which builds and deploys the documentation.
++
++The doc-build environment `docs/Project.toml` includes Documenter and other doc-build
++dependencies your package might have. If Documenter is the only dependency, then the
++`Project.toml` should include the following:
++
++```toml
++[deps]
++Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
++
++[compat]
++Documenter = "~0.20"
++```
++
++Note that it is recommended that you have a `[compat]` section, like the one above, in your
++`Project.toml` file, which would restrict Documenter's version that gets installed when the
++build runs. This is to make sure that your builds do not start failing suddenly due to a new
++major release of Documenter, which may include breaking changes. However, it also means that
++you will not get updates to Documenter automatically, and hence need to upgrade Documenter's
++major version yourself.
++
++
++## The `deploydocs` Function
++
++At the moment your `docs/make.jl` file probably only contains
++
++```julia
++using Documenter, PACKAGE_NAME
++
++makedocs()
++```
++
++We'll need to add an additional function call to this file after [`makedocs`](@ref) which
++would perform the deployment of the docs to the `gh-pages` branch.
++Add the following at the end of the file:
++
++```julia
++deploydocs(
++    repo = "github.com/USER_NAME/PACKAGE_NAME.jl.git",
++)
++```
++
++where `USER_NAME` and `PACKAGE_NAME` must be set to the appropriate names.
++Note that `repo` should not specify any protocol, i.e. it should not begin with `https://`
++or `git@`.
++
++See the [`deploydocs`](@ref) function documentation for more details.
++
++
++
++## `.gitignore`
++
++Add the following to your package's `.gitignore` file
++
++```
++docs/build/
++```
++
++These are needed to avoid committing generated content to your repository.
++
++## `gh-pages` Branch
++
++By default, Documenter pushes documentation to the `gh-pages` branch. If the branch does not
++exist it will be created automatically by [`deploydocs`](@ref). If does exist then
++Documenter simply adds an additional commit with the built documentation. You should be
++aware that Documenter may overwrite existing content without warning.
++
++If you wish to create the `gh-pages` branch manually the that can be done following
++[these instructions](https://coderwall.com/p/0n3soa/create-a-disconnected-git-branch).
++
++## Documentation Versions
++
++The documentation is deployed as follows:
++
++- Documentation built for a tag `vX.Y.Z` will be stored in a folder `vX.Y.Z`.
++
++- Documentation built from the `devbranch` branch (`master` by default) is stored a folder
++  determined by the `devurl` keyword to [`deploydocs`](@ref) (`dev` by default).
++
++Which versions that will show up in the version selector is determined by the
++`versions` argument to [`deploydocs`](@ref).
++
++Unless a custom domain is being used, the pages are found at:
++
++```
++https://USER_NAME.github.io/PACKAGE_NAME.jl/vX.Y.Z
++https://USER_NAME.github.io/PACKAGE_NAME.jl/dev
++```
++
++By default Documenter will create a link called `stable` that points to the latest release
++
++```
++https://USER_NAME.github.io/PACKAGE_NAME.jl/stable
++```
++
++It is recommended to use this link, rather then the versioned links, since it will be updated
++with new releases.
++
++Once your documentation has been pushed to the `gh-pages` branch you should add links to
++your `README.md` pointing to the `stable` (and perhaps `dev`) documentation URLs. It is common
++practice to make use of "badges" similar to those used for Travis and AppVeyor build
++statuses or code coverage. Adding the following to your package `README.md` should be all
++that is necessary:
++
++```markdown
++[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://USER_NAME.github.io/PACKAGE_NAME.jl/stable)
++[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://USER_NAME.github.io/PACKAGE_NAME.jl/dev)
++```
++
++`PACKAGE_NAME` and `USER_NAME` should be replaced with their appropriate values. The colour
++and text of the image can be changed by altering `docs-stable-blue` as described on
++[shields.io](https://shields.io), though it is recommended that package authors follow this
++standard to make it easier for potential users to find documentation links across multiple
++package README files.
++
++---
++
++**Final Remarks**
++
++That should be all that is needed to enable automatic documentation building. Pushing new
++commits to your `master` branch should trigger doc builds. **Note that other branches do not
++trigger these builds and neither do pull requests by potential contributors.**
++
++If you would like to see a more complete example of how this process is setup then take a
++look at this package's repository for some inspiration.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f927c0243a56c85f59d8cc6faf631b87dcf23298
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5e7fbe7a719e1f142d1ebeed8c92f48e62e065c3
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..112da3f291dccd1c5bcd9f389b89b76582140720
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d2fb3eba98ee2aad428d70134e254ab875f840ff
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2511626ffa3f59ec0fc0c8ef7209fd1be454719d
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d1e4871ad68e3c5e97351a12ab7ed8b27ac0f601
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,165 @@@
++# SSH Deploy Keys Walkthrough
++
++If the instructions in [SSH Deploy Keys](@ref) did not work for you (for example,
++`ssh-keygen` is not installed), don't worry! This walkthrough will guide you through the
++process. There are three main steps:
++
++1. [Generating an SSH Key](@ref)
++2. [Adding the Public Key to GitHub](@ref)
++3. [Adding the Private Key to Travis](@ref)
++
++## Generating an SSH Key
++
++The first step is to generate an SSH key. An SSH key is made up of two components: a
++*public* key, which can be shared publicly, and a *private* key, which you should ensure is
++**never** shared publicly.
++
++The public key usually looks something like this
++
++```
++ssh-rsa [base64-encoded-key] [optional-comment]
++```
++
++And the private key usually look something like this
++
++```
++-----BEGIN RSA PRIVATE KEY-----
++ ... base64-encoded key over several lines ...
++-----END RSA PRIVATE KEY-----
++```
++
++### If you have `ssh-keygen` installed
++
++If you have `ssh-keygen` installed, but `Travis.genkeys()` didn't work, you can generate an
++SSH key as follows. First, generate a key using `ssh-keygen` and save it to the file
++`privatekey`:
++
++```julia
++shell> ssh-keygen -N "" -f privatekey
++```
++
++Next, we need to encode the private key in Base64. Run the following command:
++
++```julia
++julia> read("privatekey", String) |> base64encode |>  println
++```
++
++Copy and paste the output somewhere. This is your *private key* and is required for the step
++[Adding the Private Key to Travis](@ref).
++
++Now we need to get the public key. Run the following command:
++
++```julia
++julia> read("privatekey.pub", String) |> println
++```
++
++Copy and paste the output somewhere. This is your *public key* and is required for the step
++[Adding the Public Key to GitHub](@ref).
++
++### If you do not have `ssh-keygen`
++
++If you're using Windows, you probably don't have `ssh-keygen` installed. Instead, we're
++going to use a program called PuTTY. The first step in the process to generate a new SSH key
++is to download PuTTY:
++
++* Download and install [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/)
++
++PuTTY is actually a collection of a few different programs. We need to use PuTTYgen. Open
++it, and you should get a window that looks like:
++
++![](puttygen.png)
++
++Now we need to generate a key.
++
++* Click the "Generate" button, then follow the instructions and move the mouse around to
++  create randomness.
++
++Once you've moved the mouse enough, the window should look like:
++
++![](puttygen-generated.png)
++
++Now we need to save the public key somewhere.
++
++* Copy the text in the box titled "Public key for pasting into OpenSSH authorized_keys file"
++  and paste it somewhere for later. This is your *public key* and is required for the step
++  [Adding the Public Key to GitHub](@ref)
++
++Finally, we need to save the private key somewhere.
++
++* Click the "Conversions" tab, and then click "Export OpenSSH key". Save that file
++  somewhere. That file is your *private key* and is required for the [Adding the Private Key
++  to Travis](@ref) step.
++
++  ![](puttygen-export-private-key.png)
++
++  !!! note
++
++      Don't save your key via the "Save private key" button as this will save the key in the
++      wrong format.
++
++If you made it this far, congratulations! You now have the private and public keys needed to
++set up automatic deployment of your documentation. The next steps are to add the keys to
++GitHub and Travis.
++
++
++## Adding the Public Key to GitHub
++
++In this section, we explain how to upload a public SSH key to GitHub. By this point, you
++should have generated a public key and saved it to a file. If you haven't done this, go read
++[Generating an SSH Key](@ref).
++
++Go to `https://github.com/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings/keys` and click "Add
++deploy key". You should get to a page that looks like:
++
++![](github-add-deploy-key.png)
++
++Now we need to fill in three pieces of information.
++
++1. Have "Title" be e.g. "Documenter".
++2. Copy and paste the *public key* that we generated in the [Generating an SSH Key](@ref)
++   step into the "Key" field.
++3. Make sure that the "Allow write access" box is checked.
++
++Once you're done, click "Add key". Congratulations! You've added the public key
++to GitHub. The next step is to add the private key to Travis.
++
++
++## Adding the Private Key to Travis
++
++In this section, we explain how to upload a private SSH key to Travis. By this point, you
++should have generated a private key and saved it to a file. If you haven't done this, go
++read [Generating an SSH Key](@ref).
++
++First, we need to Base64 encode the private key. Open Julia, and run the command
++
++```julia
++julia> read("path/to/private/key", String) |> Documenter.base64encode |> println
++```
++
++Copy the resulting output.
++
++Next, go to `https://travis-ci.org/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings`. Scroll down
++to the "Environment Variables" section. It should look like this:
++
++![](travis-variables.png)
++
++Now, add a new environment variable called `DOCUMENTER_KEY`, and set its value to the output
++from the Julia command above (make sure to remove the surrounding quotes).
++
++Finally, check that the "Display value in build log" is switched off and then click "Add".
++Congratulations! You've added the private key to Travis.
++
++!!! warning "Security warning"
++
++    To reiterate: make sure that the "Display value in build log" option is **OFF** for
++    the variable, so that it does not get printed when the tests run. This
++    base64-encoded string contains the *unencrypted* private key that gives full write
++    access to your repository, so it must be kept safe.  Also, make sure that you never
++    expose this variable in your tests, nor merge any code that does. You can read more
++    about Travis environment variables in [Travis User Documentation](https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings).
++
++---
++
++**Final Remarks**
++
++You should now be able to continue on with the [Hosting Documentation](@ref).
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c9f040a249b0b640808941c262a9489536e1e51f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,83 @@@
++# [``\LaTeX`` Syntax](@id latex_syntax)
++
++The following section describes how to add equations written using ``\LaTeX`` to your
++documentation.
++
++## Escaping Characters in Docstrings
++
++Since some characters used in ``\LaTeX`` syntax are treated differently in docstrings they
++need to be escaped using a `\` character as in the following example:
++
++```julia
++"""
++Here's some inline maths: \$\\sqrt[n]{1 + x + x^2 + \\ldots}\$.
++
++Here's an equation:
++
++\$\\frac{n!}{k!(n - k)!} = \\binom{n}{k}\$
++
++This is the binomial coefficient.
++"""
++func(x) = # ...
++```
++
++To avoid needing to escape the special characters the `doc""` string macro can be used:
++
++```julia
++doc"""
++Here's some inline maths: $\sqrt[n]{1 + x + x^2 + \ldots}$.
++
++Here's an equation:
++
++$\frac{n!}{k!(n - k)!} = \binom{n}{k}$
++
++This is the binomial coefficient.
++"""
++func(x) = # ...
++```
++
++A related issue is how to add dollar signs to a docstring. They need to be
++double-escaped as follows:
++```julia
++"""
++The cost was \\\$1.
++"""
++```
++
++## Inline Equations
++
++```markdown
++Here's some inline maths: ``\sqrt[n]{1 + x + x^2 + \ldots}``.
++```
++
++which will be displayed as
++
++---
++
++Here's some inline maths: ``\sqrt[n]{1 + x + x^2 + \ldots}``.
++
++---
++
++## Display Equations
++
++````markdown
++Here's an equation:
++
++```math
++\frac{n!}{k!(n - k)!} = \binom{n}{k}
++```
++
++This is the binomial coefficient.
++````
++
++which will be displayed as
++
++---
++
++Here's an equation:
++
++```math
++\frac{n!}{k!(n - k)!} = \binom{n}{k}
++```
++
++This is the binomial coefficient.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7745c4a13b43de9f3f8e898ee850602307e96e4c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,169 @@@
++# Other Output Formats
++
++In addition to the default native HTML output, plugin packages enable Documenter to generate
++output in other formats. Once the corresponding package is loaded, the output format can be
++specified using the `format` option in [`makedocs`](@ref).
++
++
++## Markdown & MkDocs
++
++Markdown output requires the [`DocumenterMarkdown`](https://github.com/JuliaDocs/DocumenterMarkdown.jl)
++package to be available and loaded.
++For Travis setups, add the package to the `docs/Project.toml` environment as a dependency.
++You also need to import the package in `make.jl`:
++
++```
++using DocumenterMarkdown
++```
++
++When `DocumenterMarkdown` is loaded, you can specify `format = :markdown` in [`makedocs`](@ref).
++Documenter will then output a set of Markdown files to the `build` directory that can then
++further be processed with [MkDocs](https://www.mkdocs.org/) into HTML pages.
++
++MkDocs, of course, is not the only option you have -- any markdown to HTML converter should
++work fine with some amount of setting up.
++
++!!! note
++
++    Markdown output used to be the default option (i.e. when leaving the `format` option
++    unspecified). The default now is the HTML output.
++
++### The MkDocs `mkdocs.yml` file
++
++A MkDocs build is controlled by the `mkdocs.yml` configuration file. Add the file with the
++following content to the `docs/` directory:
++
++```yaml
++site_name:        PACKAGE_NAME.jl
++repo_url:         https://github.com/USER_NAME/PACKAGE_NAME.jl
++site_description: Description...
++site_author:      USER_NAME
++
++theme: readthedocs
++
++extra_css:
++  - assets/Documenter.css
++
++extra_javascript:
++  - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML
++  - assets/mathjaxhelper.js
++
++markdown_extensions:
++  - extra
++  - tables
++  - fenced_code
++  - mdx_math
++
++docs_dir: 'build'
++
++pages:
++  - Home: index.md
++```
++
++If you have run Documenter and it has generated a `build/` directory, you can now try running
++`mkdocs build` -- this should now generate the `site/` directory.
++You should also add the `docs/site/` directory into your `.gitignore` file, which should now
++look like:
++
++```
++docs/build/
++docs/site/
++```
++
++This is only a basic skeleton. Read through the MkDocs documentation if you would like to
++know more about the available settings.
++
++
++### Deployment with MkDocs
++
++To deploy MkDocs on Travis, you also need to provide additional keyword arguments to
++[`deploydocs`](@ref). Your [`deploydocs`](@ref) call should look something like
++
++```julia
++deploydocs(
++    repo   = "github.com/USER_NAME/PACKAGE_NAME.jl.git",
++    deps   = Deps.pip("mkdocs", "pygments", "python-markdown-math"),
++    make   = () -> run(`mkdocs build`)
++    target = "site"
++)
++```
++
++* `deps` serves to provide the required Python dependencies to build the documentation
++* `make` specifies the function that calls `mkdocs` to perform the second build step
++* `target`, which specified which files get copied to `gh-pages`, needs to point to the
++  `site/` directory
++
++In the example above we include the dependencies [mkdocs](https://www.mkdocs.org)
++and [`python-markdown-math`](https://github.com/mitya57/python-markdown-math).
++The former makes sure that MkDocs is installed to deploy the documentation,
++and the latter provides the `mdx_math` markdown extension to exploit MathJax
++rendering of latex equations in markdown. Other dependencies should be
++included here.
++
++
++### ``\LaTeX``: MkDocs and MathJax
++
++To get MkDocs to display ``\LaTeX`` equations correctly we need to update several of this
++configuration files described in the [Package Guide](@ref).
++
++`docs/make.jl` should add the `python-markdown-math` dependency to allow for equations to
++be rendered correctly.
++
++```julia
++# ...
++
++deploydocs(
++    deps = Deps.pip("pygments", "mkdocs", "python-markdown-math"),
++    # ...
++)
++```
++
++This package should also be installed locally so that you can preview the generated
++documentation prior to pushing new commits to a repository.
++
++```sh
++$ pip install python-markdown-math
++```
++
++The `docs/mkdocs.yml` file must add the `python-markdown-math` extension, called `mdx_math`,
++as well as two MathJax JavaScript files:
++
++```yaml
++# ...
++markdown_extensions:
++  - mdx_math
++  # ...
++
++extra_javascript:
++  - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML
++  - assets/mathjaxhelper.js
++# ...
++```
++
++**Final Remarks**
++
++Following this guide and adding the necessary changes to the configuration files should
++enable properly rendered mathematical equations within your documentation both locally and
++when built and deployed using the Travis built service.
++
++
++## PDF Output via LaTeX
++
++LaTeX/PDF output requires the [`DocumenterLaTeX`](https://github.com/JuliaDocs/DocumenterLaTeX.jl)
++package to be available and loaded in `make.jl` with
++
++```
++using DocumenterLaTeX
++```
++
++When `DocumenterLaTeX` is loaded, you can set `format = :latex` in [`makedocs`](@ref),
++and Documenter will generate a PDF version of the documentation using LaTeX.
++
++* You need `pdflatex` command to be installed and available to Documenter.
++* You need the [minted](https://ctan.org/pkg/minted) LaTeX package and its backend source
++  highlighter [Pygments](http://pygments.org/) installed.
++* You need the [Lato](http://www.latofonts.com/lato-free-fonts/) and
++  [Roboto Mono](https://fonts.google.com/specimen/Roboto+Mono) fonts installed.
++
++You should also specify the `sitename` and `authors` keywords for `makedocs` when using the
++LaTeX output.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e1f28fd28bd9f3bb6b78cfbad9b3f15334913393
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,559 @@@
++# Syntax
++
++This section of the manual describes the syntax used by Documenter to build documentation.
++
++```@contents
++Pages = ["syntax.md"]
++```
++
++## `@docs` block
++
++Splice one or more docstrings into a document in place of the code block, i.e.
++
++````markdown
++```@docs
++Documenter
++makedocs
++deploydocs
++```
++````
++
++This block type is evaluated within the `CurrentModule` module if defined, otherwise within
++`Main`, and so each object listed in the block should be visible from that
++module. Undefined objects will raise warnings during documentation generation and cause the
++code block to be rendered in the final document unchanged.
++
++Objects may not be listed more than once within the document. When duplicate objects are
++detected an error will be raised and the build process will be terminated.
++
++To ensure that all docstrings from a module are included in the final document the `modules`
++keyword for [`makedocs`](@ref) can be set to the desired module or modules, i.e.
++
++```julia
++makedocs(
++    modules = [Documenter],
++)
++```
++
++which will cause any unlisted docstrings to raise warnings when [`makedocs`](@ref) is
++called. If `modules` is not defined then no warnings are printed, even if a document has
++missing docstrings.
++
++## `@autodocs` block
++
++Automatically splices all docstrings from the provided modules in place of the code block.
++This is equivalent to manually adding all the docstrings in a `@docs` block.
++
++````markdown
++```@autodocs
++Modules = [Foo, Bar]
++Order   = [:function, :type]
++```
++````
++
++The above `@autodocs` block adds all the docstrings found in modules `Foo` and `Bar` that
++refer to functions or types to the document.
++
++Each module is added in order and so all docs from `Foo` will appear before those of `Bar`.
++Possible values for the `Order` vector are
++
++- `:module`
++- `:constant`
++- `:type`
++- `:function`
++- `:macro`
++
++If no `Order` is provided then the order listed above is used.
++
++When a potential docstring is found in one of the listed modules, but does not match any
++value from `Order` then it will be omitted from the document. Hence `Order` acts as a basic
++filter as well as sorter.
++
++In addition to `Order`, a `Pages` vector may be included in `@autodocs` to filter docstrings
++based on the source file in which they are defined:
++
++````markdown
++```@autodocs
++Modules = [Foo]
++Pages   = ["a.jl", "b.jl"]
++```
++````
++
++In the above example docstrings from module `Foo` found in source files that end in `a.jl`
++and `b.jl` are included. The page order provided by `Pages` is also used to sort the
++docstrings. Note that page matching is done using the end of the provided strings and so
++`a.jl` will be matched by *any* source file that ends in `a.jl`, i.e. `src/a.jl` or
++`src/foo/a.jl`.
++
++To include only the exported names from the modules listed in `Modules` use `Private = false`.
++In a similar way `Public = false` can be used to only show the unexported names. By
++default both of these are set to `true` so that all names will be shown.
++
++````markdown
++Functions exported from `Foo`:
++
++```@autodocs
++Modules = [Foo]
++Private = false
++Order = [:function]
++```
++
++Private types in module `Foo`:
++
++```@autodocs
++Modules = [Foo]
++Public = false
++Order = [:type]
++```
++````
++
++!!! note
++
++    When more complex sorting and filtering is needed then use `@docs` to define it
++    explicitly.
++
++## `@ref` link
++
++Used in markdown links as the URL to tell Documenter to generate a cross-reference
++automatically. The text part of the link can be a docstring, header name, or GitHub PR/Issue
++number.
++
++````markdown
++# Syntax
++
++... [`makedocs`](@ref) ...
++
++# Functions
++
++```@docs
++makedocs
++```
++
++... [Syntax](@ref) ...
++
++... [#42](@ref) ...
++````
++
++Plain text in the "text" part of a link will either cross-reference a header, or, when it is
++a number preceded by a `#`, a GitHub issue/pull request. Text wrapped in backticks will
++cross-reference a docstring from a `@docs` block.
++
++`@ref`s may refer to docstrings or headers on different pages as well as the current page
++using the same syntax.
++
++Note that depending on what the `CurrentModule` is set to, a docstring `@ref` may need to
++be prefixed by the module which defines it.
++
++### Duplicate Headers
++
++In some cases a document may contain multiple headers with the same name, but on different
++pages or of different levels. To allow `@ref` to cross-reference a duplicate header it must
++be given a name as in the following example
++
++```markdown
++# [Header](@id my_custom_header_name)
++
++...
++
++## Header
++
++... [Custom Header](@ref my_custom_header_name) ...
++```
++
++The link that wraps the named header is removed in the final document. The text for a named
++`@ref ...` does not need to match the header that it references. Named `@ref ...`s may refer
++to headers on different pages in the same way as unnamed ones do.
++
++Duplicate docstring references do not occur since splicing the same docstring into a
++document more than once is disallowed.
++
++### Named doc `@ref`s
++
++Docstring `@ref`s can also be "named" in a similar way to headers as shown in the
++[Duplicate Headers](@ref) section above. For example
++
++```julia
++module Mod
++
++"""
++Both of the following references point to `g` found in module `Main.Other`:
++
++  * [`Main.Other.g`](@ref)
++  * [`g`](@ref Main.Other.g)
++
++"""
++f(args...) = # ...
++
++end
++```
++
++This can be useful to avoid having to write fully qualified names for references that
++are not imported into the current module, or when the text displayed in the link is
++used to add additional meaning to the surrounding text, such as
++
++```markdown
++Use [`for i = 1:10 ...`](@ref for) to loop over all the numbers from 1 to 10.
++```
++
++!!! note
++
++    Named doc `@ref`s should be used sparingly since writing unqualified names may, in some
++    cases, make it difficult to tell *which* function is being referred to in a particular
++    docstring if there happen to be several modules that provide definitions with the same
++    name.
++
++## `@meta` block
++
++This block type is used to define metadata key/value pairs that can be used elsewhere in the
++page. Currently recognised keys:
++- `CurrentModule`: module where Documenter evaluates, for example, [`@docs`-block](@ref)
++  and [`@ref`-link](@ref)s.
++- `DocTestSetup`: code to be evaluated before a doctest, see the [Setup Code](@ref)
++  section under [Doctests](@ref).
++- `DocTestFilters`: filters to deal with, for example, unpredictable output from doctests,
++  see the [Filtering Doctests](@ref) section under [Doctests](@ref).
++- `EditURL`: link to where the page can be edited. This defaults to the `.md` page itself,
++  but if the source is something else (for example if the `.md` page is generated as part of
++  the doc build) this can be set, either as a local link, or an absolute url.
++
++Example:
++
++````markdown
++```@meta
++CurrentModule = FooBar
++DocTestSetup  = quote
++    using MyPackage
++end
++DocTestFilters = [r"Stacktrace:[\s\S]+"]
++EditURL = "link/to/source/file"
++```
++````
++
++Note that `@meta` blocks are always evaluated in `Main`.
++
++## `@index` block
++
++Generates a list of links to docstrings that have been spliced into a document. Valid
++settings are `Pages`, `Modules`, and `Order`. For example:
++
++````markdown
++```@index
++Pages   = ["foo.md"]
++Modules = [Foo, Bar]
++Order   = [:function, :type]
++```
++````
++
++When `Pages` or `Modules` are not provided then all pages or modules are included. `Order`
++defaults to
++
++```julia
++[:module, :constant, :type, :function, :macro]
++```
++
++if not specified. `Order` and `Modules` behave the same way as in [`@autodocs` block](@ref)s
++and filter out docstrings that do not match one of the modules or categories specified.
++
++Note that the values assigned to `Pages`, `Modules`, and `Order` may be any valid Julia code
++and thus can be something more complex that an array literal if required, i.e.
++
++````markdown
++```@index
++Pages = map(file -> joinpath("man", file), readdir("man"))
++```
++````
++
++It should be noted though that in this case `Pages` may not be sorted in the order that is
++expected by the user. Try to stick to array literals as much as possible.
++
++## `@contents` block
++
++Generates a nested list of links to document sections. Valid settings are `Pages` and `Depth`.
++
++````markdown
++```@contents
++Pages = ["foo.md"]
++Depth = 5
++```
++````
++
++As with `@index` if `Pages` is not provided then all pages are included. The default
++`Depth` value is `2`.
++
++## `@example` block
++
++Evaluates the code block and inserts the result into the final document along with the
++original source code.
++
++````markdown
++```@example
++a = 1
++b = 2
++a + b
++```
++````
++
++The above `@example` block will splice the following into the final document
++
++````markdown
++```julia
++a = 1
++b = 2
++a + b
++```
++
++```
++3
++```
++````
++
++Leading and trailing newlines are removed from the rendered code blocks. Trailing whitespace
++on each line is also removed.
++
++**Hiding Source Code**
++
++Code blocks may have some content that does not need to be displayed in the final document.
++`# hide` comments can be appended to lines that should not be rendered, i.e.
++
++````markdown
++```@example
++import Random # hide
++Random.seed!(1) # hide
++A = rand(3, 3)
++b = [1, 2, 3]
++A \ b
++```
++````
++
++Note that appending `# hide` to every line in an `@example` block will result in the block
++being hidden in the rendered document. The results block will still be rendered though.
++`@setup` blocks are a convenient shorthand for hiding an entire block, including the output.
++
++**`stdout` and `stderr`**
++
++The Julia output streams are redirected to the results block when evaluating `@example`
++blocks in the same way as when running doctest code blocks.
++
++**`nothing` Results**
++
++When the `@example` block evaluates to `nothing` then the second block is not displayed.
++Only the source code block will be shown in the rendered document. Note that if any output
++from either `stdout` or `stderr` is captured then the results block will be displayed even
++if `nothing` is returned.
++
++**Named `@example` Blocks**
++
++By default `@example` blocks are run in their own anonymous `Module`s to avoid side-effects
++between blocks. To share the same module between different blocks on a page the `@example`
++can be named with the following syntax
++
++````markdown
++```@example 1
++a = 1
++```
++
++```@example 1
++println(a)
++```
++````
++
++The name can be any text, not just integers as in the example above, i.e. `@example foo`.
++
++Named `@example` blocks can be useful when generating documentation that requires
++intermediate explanation or multimedia such as plots as illustrated in the following example
++
++````markdown
++First we define some functions
++
++```@example 1
++using PyPlot # hide
++f(x) = sin(2x) + 1
++g(x) = cos(x) - x
++```
++
++and then we plot `f` over the interval from ``-π`` to ``π``
++
++```@example 1
++x = linspace(-π, π)
++plot(x, f(x), color = "red")
++savefig("f-plot.svg"); nothing # hide
++```
++
++![](f-plot.svg)
++
++and then we do the same with `g`
++
++```@example 1
++plot(x, g(x), color = "blue")
++savefig("g-plot.svg"); nothing # hide
++```
++
++![](g-plot.svg)
++````
++
++Note that `@example` blocks are evaluated within the directory of `build` where the file
++will be rendered . This means than in the above example `savefig` will output the `.svg`
++files into that directory. This allows the images to be easily referenced without needing to
++worry about relative paths.
++
++`@example` blocks automatically define `ans` which, as in the Julia REPL, is bound to the
++value of the last evaluated expression. This can be useful in situations such as the
++following one where where binding the object returned by `plot` to a named variable would
++look out of place in the final rendered documentation:
++
++````markdown
++```@example
++using Gadfly # hide
++plot([sin, x -> 2sin(x) + x], -2π, 2π)
++draw(SVG("plot.svg", 6inch, 4inch), ans); nothing # hide
++```
++
++![](plot.svg)
++````
++
++**Delayed Execution of `@example` Blocks**
++
++`@example` blocks accept a keyword argument `continued` which can be set to `true` or `false`
++(defaults to `false`). When `continued = true` the execution of the code is delayed until the
++next `continued = false` `@example`-block. This is needed for example when the expression in
++a block is not complete. Example:
++
++````markdown
++```@example half-loop; continued = true
++for i in 1:3
++    j = i^2
++```
++Some text explaining what we should do with `j`
++```@example half-loop
++    println(j)
++end
++```
++````
++
++Here the first block is not complete -- the loop is missing the `end`. Thus, by setting
++`continued = true` here we delay the evaluation of the first block, until we reach the
++second block. A block with `continued = true` does not have any output.
++
++## `@repl` block
++
++These are similar to `@example` blocks, but adds a `julia> ` prompt before each toplevel
++expression. `;` and `# hide` syntax may be used in `@repl` blocks in the same way as in the
++Julia REPL and `@example` blocks.
++
++````markdown
++```@repl
++a = 1
++b = 2
++a + b
++```
++````
++
++will generate
++
++````markdown
++```julia
++julia> a = 1
++1
++
++julia> b = 2
++2
++
++julia> a + b
++3
++```
++````
++
++Named `@repl <name>` blocks behave in the same way as named `@example <name>` blocks.
++
++## `@setup <name>` block
++
++These are similar to `@example` blocks, but both the input and output are hidden from the
++final document. This can be convenient if there are several lines of setup code that need to be
++hidden.
++
++!!! note
++
++    Unlike `@example` and `@repl` blocks, `@setup` requires a `<name>` attribute to associate it
++    with downstream `@example <name>` and `@repl <name>` blocks.
++
++````markdown
++```@setup abc
++using RDatasets
++using DataFrames
++iris = dataset("datasets", "iris")
++```
++
++```@example abc
++println(iris)
++```
++````
++
++
++## `@eval` block
++
++Evaluates the contents of the block and inserts the resulting value into the final document.
++
++In the following example we use the PyPlot package to generate a plot and display it in the
++final document.
++
++````markdown
++```@eval
++using PyPlot
++
++x = linspace(-π, π)
++y = sin(x)
++
++plot(x, y, color = "red")
++savefig("plot.svg")
++
++nothing
++```
++
++![](plot.svg)
++````
++
++Note that each `@eval` block evaluates its contents within a separate module. When
++evaluating each block the present working directory, `pwd`, is set to the directory in
++`build` where the file will be written to.
++
++Also, instead of returning `nothing` in the example above we could have returned a new
++`Markdown.MD` object through `Markdown.parse`. This can be more appropriate when the
++filename is not known until evaluation of the block itself.
++
++!!! note
++
++    In most cases `@example` is preferred over `@eval`. Just like in normal Julia code where
++    `eval` should be only be considered as a last resort, `@eval` should be treated in the
++    same way.
++
++
++## `@raw <format>` block
++
++Allows code to be inserted into the final document verbatim. E.g. to insert custom HTML or
++LaTeX code into the output.
++
++The `format` argument is mandatory and Documenter uses it to determine whether a particular
++block should be copied over to the output or not. Currently supported formats are `html`
++and `latex`, used by the respective writers. A `@raw` block whose `format` is not
++recognized is usually ignored, so it is possible to have a raw block for each output format
++without the blocks being duplicated in the output.
++
++The following example shows how SVG code with custom styling can be included into documents
++using the `@raw` block.
++
++````markdown
++```@raw html
++<svg style="display: block; margin: 0 auto;" width="5em" heigth="5em">
++      <circle cx="2.5em" cy="2.5em" r="2em" stroke="black" stroke-width=".1em" fill="red" />
++</svg>
++```
++````
++
++It will show up as follows, with code having been copied over verbatim to the HTML file.
++
++```@raw html
++<svg style="display: block; margin: 0 auto;" width="5em" heigth="5em">
++      <circle cx="2.5em" cy="2.5em" r="2em" stroke="black" stroke-width=".1em" fill="red" />
++    (SVG)
++</svg>
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c1f711519369e97e30d64470b336d16a998d80e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,127 @@@
++"""
++Defines the [`Anchor`](@ref) and [`AnchorMap`](@ref) types.
++
++`Anchor`s and `AnchorMap`s are used to represent links between objects within a document.
++"""
++module Anchors
++
++using DocStringExtensions
++
++# Types.
++# ------
++
++"""
++Stores an arbitrary object called `.object` and it's location within a document.
++
++**Fields**
++
++- `object` -- the stored object.
++- `order`  -- ordering of `object` within the entire document.
++- `file`   -- the destination file, in `build`, where the object will be written to.
++- `id`     -- the generated "slug" identifying the object.
++- `nth`    -- integer that unique-ifies anchors with the same `id`.
++"""
++mutable struct Anchor
++    object :: Any
++    order  :: Int
++    file   :: String
++    id     :: String
++    nth    :: Int
++    Anchor(object) = new(object, 0, "", "", 1)
++end
++
++"""
++Tree structure representating anchors in a document and their relationships with eachother.
++
++**Object Hierarchy**
++
++    id -> file -> anchors
++
++Each `id` maps to a `file` which in turn maps to a vector of `Anchor` objects.
++"""
++mutable struct AnchorMap
++    map   :: Dict{String, Dict{String, Vector{Anchor}}}
++    count :: Int
++    AnchorMap() = new(Dict(), 0)
++end
++
++# Add anchor.
++# -----------
++
++"""
++$(SIGNATURES)
++
++Adds a new [`Anchor`](@ref) to the [`AnchorMap`](@ref) for a given `id` and `file`.
++
++Either an actual [`Anchor`](@ref) object may be provided or any other object which is
++automatically wrapped in an [`Anchor`](@ref) before being added to the [`AnchorMap`](@ref).
++"""
++function add!(m::AnchorMap, anchor::Anchor, id, file)
++    filemap = get!(m.map, id, Dict{String, Vector{Anchor}}())
++    anchors = get!(filemap, file, Anchor[])
++    push!(anchors, anchor)
++    anchor.order = m.count += 1
++    anchor.file  = file
++    anchor.id    = id
++    anchor.nth   = length(anchors)
++    anchor
++end
++add!(m::AnchorMap, object, id, file) = add!(m, Anchor(object), id, file)
++
++# Anchor existance.
++# -----------------
++
++"""
++$(SIGNATURES)
++
++Does the given `id` exist within the [`AnchorMap`](@ref)? A `file` and integer `n` may also
++be provided to narrow the search for existance.
++"""
++exists(m::AnchorMap, id, file, n) = exists(m, id, file) && 1 ≤ n ≤ length(m.map[id][file])
++exists(m::AnchorMap, id, file)    = exists(m, id) && haskey(m.map[id], file)
++exists(m::AnchorMap, id)          = haskey(m.map, id)
++
++# Anchor uniqueness.
++# ------------------
++
++"""
++$(SIGNATURES)
++
++Is the `id` unique within the given [`AnchorMap`](@ref)? May also specify the `file`.
++"""
++function isunique(m::AnchorMap, id)
++    exists(m, id) &&
++    length(m.map[id]) === 1 &&
++    isunique(m, id, first(first(m.map[id])))
++end
++function isunique(m::AnchorMap, id, file)
++    exists(m, id, file) &&
++    length(m.map[id][file]) === 1
++end
++
++# Get anchor.
++# -----------
++
++"""
++$(SIGNATURES)
++
++Returns the [`Anchor`](@ref) object matching `id`. `file` and `n` may also be provided. An
++`Anchor` is returned, or `nothing` in case of no match.
++"""
++function anchor(m::AnchorMap, id)
++    isunique(m, id) ?
++        anchor(m, id, first(first(m.map[id])), 1) :
++        nothing
++end
++function anchor(m::AnchorMap, id, file)
++    isunique(m, id, file) ?
++        anchor(m, id, file, 1) :
++        nothing
++end
++function anchor(m::AnchorMap, id, file, n)
++    exists(m, id, file, n) ?
++        m.map[id][file][n]   :
++        nothing
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..616c68d7e718f4f2ebcde71c72fd70198fc5083c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,213 @@@
++"""
++Defines the `Documenter.jl` build "pipeline" named [`DocumentPipeline`](@ref).
++
++Each stage of the pipeline performs an action on a [`Documents.Document`](@ref) object.
++These actions may involve creating directory structures, expanding templates, running
++doctests, etc.
++"""
++module Builder
++
++import ..Documenter:
++    Anchors,
++    Documents,
++    Documenter,
++    Utilities
++
++import .Utilities: Selectors
++
++using DocStringExtensions
++
++# Document Pipeline.
++# ------------------
++
++"""
++The default document processing "pipeline", which consists of the following actions:
++
++- [`SetupBuildDirectory`](@ref)
++- [`ExpandTemplates`](@ref)
++- [`CrossReferences`](@ref)
++- [`CheckDocument`](@ref)
++- [`Populate`](@ref)
++- [`RenderDocument`](@ref)
++
++"""
++abstract type DocumentPipeline <: Selectors.AbstractSelector end
++
++"""
++Creates the correct directory layout within the `build` folder and parses markdown files.
++"""
++abstract type SetupBuildDirectory <: DocumentPipeline end
++
++"""
++Executes a sequence of actions on each node of the parsed markdown files in turn.
++"""
++abstract type ExpandTemplates <: DocumentPipeline end
++
++"""
++Finds and sets URLs for each `@ref` link in the document to the correct destinations.
++"""
++abstract type CrossReferences <: DocumentPipeline end
++
++"""
++Checks that all documented objects are included in the document and runs doctests on all
++valid Julia code blocks.
++"""
++abstract type CheckDocument <: DocumentPipeline end
++
++"""
++Populates the `ContentsNode`s and `IndexNode`s with links.
++"""
++abstract type Populate <: DocumentPipeline end
++
++"""
++Writes the document tree to the `build` directory.
++"""
++abstract type RenderDocument <: DocumentPipeline end
++
++Selectors.order(::Type{SetupBuildDirectory})   = 1.0
++Selectors.order(::Type{ExpandTemplates})       = 2.0
++Selectors.order(::Type{CrossReferences})       = 3.0
++Selectors.order(::Type{CheckDocument})         = 4.0
++Selectors.order(::Type{Populate})              = 5.0
++Selectors.order(::Type{RenderDocument})        = 6.0
++
++Selectors.matcher(::Type{T}, doc::Documents.Document) where {T <: DocumentPipeline} = true
++
++Selectors.strict(::Type{T}) where {T <: DocumentPipeline} = false
++
++function Selectors.runner(::Type{SetupBuildDirectory}, doc::Documents.Document)
++    Utilities.log(doc, "setting up build directory.")
++
++    # Frequently used fields.
++    build  = doc.user.build
++    source = doc.user.source
++
++    # The .user.source directory must exist.
++    isdir(source) || error("source directory '$(abspath(source))' is missing.")
++
++    # We create the .user.build directory.
++    # If .user.clean is set, we first clean the existing directory.
++    doc.user.clean && isdir(build) && rm(build; recursive = true)
++    isdir(build) || mkpath(build)
++
++    # We'll walk over all the files in the .user.source directory.
++    # The directory structure is copied over to .user.build. All files, with
++    # the exception of markdown files (identified by the extension) are copied
++    # over as well, since they're assumed to be images, data files etc.
++    # Markdown files, however, get added to the document and also stored into
++    # `mdpages`, to be used later.
++    mdpages = String[]
++    for (root, dirs, files) in walkdir(source)
++        for dir in dirs
++            d = normpath(joinpath(build, relpath(root, source), dir))
++            isdir(d) || mkdir(d)
++        end
++        for file in files
++            src = normpath(joinpath(root, file))
++            dst = normpath(joinpath(build, relpath(root, source), file))
++            if endswith(file, ".md")
++                push!(mdpages, Utilities.srcpath(source, root, file))
++                Documents.addpage!(doc, src, dst)
++            else
++                cp(src, dst; force = true)
++            end
++        end
++    end
++
++    # If the user hasn't specified the page list, then we'll just default to a
++    # flat list of all the markdown files we found, sorted by the filesystem
++    # path (it will group them by subdirectory, among others).
++    userpages = isempty(doc.user.pages) ? sort(mdpages) : doc.user.pages
++
++    # Populating the .navtree and .navlist.
++    # We need the for loop because we can't assign to the fields of the immutable
++    # doc.internal.
++    for navnode in walk_navpages(userpages, nothing, doc)
++        push!(doc.internal.navtree, navnode)
++    end
++
++    # Finally we populate the .next and .prev fields of the navnodes that point
++    # to actual pages.
++    local prev::Union{Documents.NavNode, Nothing} = nothing
++    for navnode in doc.internal.navlist
++        navnode.prev = prev
++        if prev !== nothing
++            prev.next = navnode
++        end
++        prev = navnode
++    end
++end
++
++"""
++$(SIGNATURES)
++
++Recursively walks through the [`Documents.Document`](@ref)'s `.user.pages` field,
++generating [`Documents.NavNode`](@ref)s and related data structures in the
++process.
++
++This implementation is the de facto specification for the `.user.pages` field.
++"""
++function walk_navpages(visible, title, src, children, parent, doc)
++    # parent can also be nothing (for top-level elements)
++    parent_visible = (parent === nothing) || parent.visible
++    if src !== nothing
++        src = normpath(src)
++        src in keys(doc.internal.pages) || error("'$src' is not an existing page!")
++    end
++    nn = Documents.NavNode(src, title, parent)
++    (src === nothing) || push!(doc.internal.navlist, nn)
++    nn.visible = parent_visible && visible
++    nn.children = walk_navpages(children, nn, doc)
++    nn
++end
++
++function walk_navpages(hps::Tuple, parent, doc)
++    @assert length(hps) == 4
++    walk_navpages(hps..., parent, doc)
++end
++
++walk_navpages(title::String, children::Vector, parent, doc) = walk_navpages(true, title, nothing, children, parent, doc)
++walk_navpages(title::String, page, parent, doc) = walk_navpages(true, title, page, [], parent, doc)
++
++walk_navpages(p::Pair, parent, doc) = walk_navpages(p.first, p.second, parent, doc)
++walk_navpages(ps::Vector, parent, doc) = [walk_navpages(p, parent, doc)::Documents.NavNode for p in ps]
++walk_navpages(src::String, parent, doc) = walk_navpages(true, nothing, src, [], parent, doc)
++
++
++function Selectors.runner(::Type{ExpandTemplates}, doc::Documents.Document)
++    Utilities.log(doc, "expanding markdown templates.")
++    Documenter.Expanders.expand(doc)
++end
++
++function Selectors.runner(::Type{CrossReferences}, doc::Documents.Document)
++    Utilities.log(doc, "building cross-references.")
++    Documenter.CrossReferences.crossref(doc)
++end
++
++function Selectors.runner(::Type{CheckDocument}, doc::Documents.Document)
++    Utilities.log(doc, "running document checks.")
++    Documenter.DocChecks.missingdocs(doc)
++    Documenter.DocTests.doctest(doc)
++    Documenter.DocChecks.footnotes(doc)
++    Documenter.DocChecks.linkcheck(doc)
++end
++
++function Selectors.runner(::Type{Populate}, doc::Documents.Document)
++    Utilities.log("populating indices.")
++    Documents.doctest_replace!(doc)
++    Documents.populate!(doc)
++end
++
++function Selectors.runner(::Type{RenderDocument}, doc::Documents.Document)
++    count = length(doc.internal.errors)
++    if doc.user.strict && count > 0
++        error("`makedocs` encountered $(count > 1 ? "errors" : "an error"). Terminating build")
++    else
++        Utilities.log(doc, "rendering document.")
++        Documenter.Writers.render(doc)
++    end
++end
++
++Selectors.runner(::Type{DocumentPipeline}, doc::Documents.Document) = nothing
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c22edbb1da642809ec445cbeb740025440b79f1d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,227 @@@
++"""
++Provides the [`crossref`](@ref) function used to automatically calculate link URLs.
++"""
++module CrossReferences
++
++import ..Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Expanders,
++    Formats,
++    Documenter,
++    Utilities
++
++using DocStringExtensions
++import Markdown
++
++"""
++$(SIGNATURES)
++
++Traverses a [`Documents.Document`](@ref) and replaces links containg `@ref` URLs with
++their real URLs.
++"""
++function crossref(doc::Documents.Document)
++    for (src, page) in doc.internal.pages
++        empty!(page.globals.meta)
++        for element in page.elements
++            crossref(page.mapping[element], page, doc)
++        end
++    end
++end
++
++function crossref(elem, page, doc)
++    Documents.walk(page.globals.meta, elem) do link
++        xref(link, page.globals.meta, page, doc)
++    end
++end
++
++# Dispatch to `namedxref` / `docsxref`.
++# -------------------------------------
++
++const NAMED_XREF = r"^@ref (.+)$"
++
++function xref(link::Markdown.Link, meta, page, doc)
++    link.url == "@ref"             ? basicxref(link, meta, page, doc) :
++    occursin(NAMED_XREF, link.url) ? namedxref(link, meta, page, doc) : nothing
++    return false # Stop `walk`ing down this `link` element.
++end
++xref(other, meta, page, doc) = true # Continue to `walk` through element `other`.
++
++function basicxref(link::Markdown.Link, meta, page, doc)
++    if length(link.text) === 1 && isa(link.text[1], Markdown.Code)
++        docsxref(link, link.text[1].code, meta, page, doc)
++    elseif isa(link.text, Vector)
++        # No `name` was provided, since given a `@ref`, so slugify the `.text` instead.
++        text = strip(sprint(Markdown.plain, Markdown.Paragraph(link.text)))
++        if occursin(r"#[0-9]+", text)
++            issue_xref(link, lstrip(text, '#'), meta, page, doc)
++        else
++            name = Utilities.slugify(text)
++            namedxref(link, name, meta, page, doc)
++        end
++    end
++end
++
++# Cross referencing headers.
++# --------------------------
++
++function namedxref(link::Markdown.Link, meta, page, doc)
++    # Extract the `name` from the `(@ref ...)`.
++    slug = match(NAMED_XREF, link.url)[1]
++    if isempty(slug)
++        text = sprint(Markdown.plaininline, link)
++        push!(doc.internal.errors, :cross_references)
++        Utilities.warn(page.source, "'$text' missing a name after '#'.")
++    else
++        if Anchors.exists(doc.internal.headers, slug)
++            namedxref(link, slug, meta, page, doc)
++        elseif length(link.text) === 1 && isa(link.text[1], Markdown.Code)
++            docsxref(link, slug, meta, page, doc)
++        else
++            namedxref(link, slug, meta, page, doc)
++        end
++    end
++end
++
++function namedxref(link::Markdown.Link, slug, meta, page, doc)
++    headers = doc.internal.headers
++    # Add the link to list of local uncheck links.
++    doc.internal.locallinks[link] = link.url
++    # Error checking: `slug` should exist and be unique.
++    # TODO: handle non-unique slugs.
++    if Anchors.exists(headers, slug)
++        if Anchors.isunique(headers, slug)
++            # Replace the `@ref` url with a path to the referenced header.
++            anchor   = Anchors.anchor(headers, slug)
++            path     = relpath(anchor.file, dirname(page.build))
++            link.url = string(path, '#', slug, '-', anchor.nth)
++        else
++            push!(doc.internal.errors, :cross_references)
++            Utilities.warn(page.source, "'$slug' is not unique.")
++        end
++    else
++        push!(doc.internal.errors, :cross_references)
++        Utilities.warn(page.source, "Reference for '$slug' could not be found.")
++    end
++end
++
++# Cross referencing docstrings.
++# -----------------------------
++
++function docsxref(link::Markdown.Link, code, meta, page, doc)
++    # Add the link to list of local uncheck links.
++    doc.internal.locallinks[link] = link.url
++    # Parse the link text and find current module.
++    keyword = Symbol(strip(code))
++    local ex
++    if haskey(Docs.keywords, keyword)
++        ex = QuoteNode(keyword)
++    else
++        try
++            ex = Meta.parse(code)
++        catch err
++            !isa(err, Meta.ParseError) && rethrow(err)
++            push!(doc.internal.errors, :cross_references)
++            Utilities.warn(page.source, "Unable to parse the reference '[`$code`](@ref)'.")
++            return
++        end
++    end
++    mod = get(meta, :CurrentModule, Main)
++
++    # Find binding and type signature associated with the link.
++    local binding
++    try
++        binding = Documenter.DocSystem.binding(mod, ex)
++    catch err
++        push!(doc.internal.errors, :cross_references)
++        Utilities.warn(page.source, "Unable to get the binding for '[`$code`](@ref)'.", err, ex, mod)
++        return
++    end
++
++    local typesig
++    try
++        typesig = Core.eval(mod, Documenter.DocSystem.signature(ex, rstrip(code)))
++    catch err
++        push!(doc.internal.errors, :cross_references)
++        Utilities.warn(page.source, "Unable to evaluate the type signature for '[`$code`](@ref)'.", err, ex, mod)
++        return
++    end
++
++    # Try to find a valid object that we can cross-reference.
++    object = find_object(doc, binding, typesig)
++    if object !== nothing
++        # Replace the `@ref` url with a path to the referenced docs.
++        docsnode = doc.internal.objects[object]
++        path     = relpath(docsnode.page.build, dirname(page.build))
++        slug     = Utilities.slugify(object)
++        link.url = string(path, '#', slug)
++    else
++        push!(doc.internal.errors, :cross_references)
++        Utilities.warn(page.source, "No doc found for reference '[`$code`](@ref)'.")
++    end
++end
++
++"""
++$(SIGNATURES)
++
++Find the included `Object` in the `doc` matching `binding` and `typesig`. The matching
++heuristic isn't too picky about what matches and will only fail when no `Binding`s matching
++`binding` have been included.
++"""
++function find_object(doc::Documents.Document, binding, typesig)
++    object = Utilities.Object(binding, typesig)
++    if haskey(doc.internal.objects, object)
++        # Exact object matching the requested one.
++        return object
++    else
++        objects = get(doc.internal.bindings, binding, Utilities.Object[])
++        if isempty(objects)
++            # No bindings match the requested object == FAILED.
++            return nothing
++        elseif length(objects) == 1
++            # Only one possible choice. Use it even if the signature doesn't match.
++            return objects[1]
++        else
++            candidate = find_object(binding, typesig)
++            if candidate in objects
++                # We've found an actual match out of the possible choices! Use it.
++                return candidate
++            else
++                # No match in the possible choices. Use the one that was first included.
++                return objects[1]
++            end
++        end
++    end
++end
++function find_object(binding, typesig)
++    if Documenter.DocSystem.defined(binding)
++        local λ = Documenter.DocSystem.resolve(binding)
++        return find_object(λ, binding, typesig)
++    else
++        return Utilities.Object(binding, typesig)
++    end
++end
++function find_object(λ::Union{Function, DataType}, binding, typesig)
++    if hasmethod(λ, typesig)
++        signature = getsig(λ, typesig)
++        return Utilities.Object(binding, signature)
++    else
++        return Utilities.Object(binding, typesig)
++    end
++end
++find_object(::Union{Function, DataType}, binding, ::Union{Union,Type{Union{}}}) = Utilities.Object(binding, Union{})
++find_object(other, binding, typesig) = Utilities.Object(binding, typesig)
++
++getsig(λ::Union{Function, DataType}, typesig) = Base.tuple_type_tail(which(λ, typesig).sig)
++
++
++# Issues/PRs cross referencing.
++# -----------------------------
++
++function issue_xref(link::Markdown.Link, num, meta, page, doc)
++    link.url = isempty(doc.internal.remote) ? link.url :
++        "https://github.com/$(doc.internal.remote)/issues/$num"
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1dd1302d5a269b36f7f5b52444da167085e36568
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,52 @@@
++"""
++Exported module that provides build and deploy dependencies and related functions.
++
++Currently only [`pip`](@ref) is implemented.
++"""
++module Deps
++
++export pip
++
++using DocStringExtensions
++
++"""
++$(SIGNATURES)
++
++Installs (as non-root user) all python packages listed in `deps`.
++
++# Examples
++
++```julia
++using Documenter
++
++makedocs(
++    # ...
++)
++
++deploydocs(
++    deps = Deps.pip("pygments", "mkdocs", "mkdocs-material"),
++    # ...
++)
++```
++"""
++function pip(deps...)
++    for dep in deps
++        run(`pip install --user $(dep)`)
++    end
++end
++
++
++function localbin()
++    Sys.islinux() ? joinpath(homedir(), ".local", "bin") :
++    Sys.isapple() ? joinpath(homedir(), "Library", "Python", "2.7", "bin") : ""
++end
++
++function updatepath!(p = localbin())
++    if occursin(p, ENV["PATH"])
++        ENV["PATH"]
++    else
++        ENV["PATH"] = "$p:$(ENV["PATH"])"
++    end
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0dae52fd67830d83350931ff80067652b80097bb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,224 @@@
++"""
++Provides the [`missingdocs`](@ref), [`footnotes`](@ref) and [`linkcheck`](@ref) functions
++for checking docs.
++"""
++module DocChecks
++
++import ..Documenter:
++    Documenter,
++    Documents,
++    Utilities
++
++using DocStringExtensions
++import Markdown
++
++# Missing docstrings.
++# -------------------
++
++"""
++$(SIGNATURES)
++
++Checks that a [`Documents.Document`](@ref) contains all available docstrings that are
++defined in the `modules` keyword passed to [`Documenter.makedocs`](@ref).
++
++Prints out the name of each object that has not had its docs spliced into the document.
++"""
++function missingdocs(doc::Documents.Document)
++    doc.user.checkdocs === :none && return
++    println(" > checking for missing docstrings.")
++    bindings = allbindings(doc.user.checkdocs, doc.user.modules)
++    for object in keys(doc.internal.objects)
++        if haskey(bindings, object.binding)
++            signatures = bindings[object.binding]
++            if object.signature ≡ Union{} || length(signatures) ≡ 1
++                delete!(bindings, object.binding)
++            elseif object.signature in signatures
++                delete!(signatures, object.signature)
++            end
++        end
++    end
++    n = reduce(+, map(length, values(bindings)), init=0)
++    if n > 0
++        b = IOBuffer()
++        println(b, "$n docstring$(n ≡ 1 ? "" : "s") potentially missing:\n")
++        for (binding, signatures) in bindings
++            for sig in signatures
++                println(b, "    $binding", sig ≡ Union{} ? "" : " :: $sig")
++            end
++        end
++        push!(doc.internal.errors, :missing_docs)
++        Utilities.warn(String(take!(b)))
++    end
++end
++
++function allbindings(checkdocs::Symbol, mods)
++    out = Dict{Utilities.Binding, Set{Type}}()
++    for m in mods
++        allbindings(checkdocs, m, out)
++    end
++    out
++end
++
++function allbindings(checkdocs::Symbol, mod::Module, out = Dict{Utilities.Binding, Set{Type}}())
++    for (obj, doc) in meta(mod)
++        isa(obj, IdDict{Any,Any}) && continue
++        name = nameof(obj)
++        isexported = Base.isexported(mod, name)
++        if checkdocs === :all || (isexported && checkdocs === :exports)
++            out[Utilities.Binding(mod, name)] = Set(sigs(doc))
++        end
++    end
++    out
++end
++
++meta(m) = Docs.meta(m)
++
++nameof(b::Base.Docs.Binding) = b.var
++nameof(x) = Base.nameof(x)
++
++sigs(x::Base.Docs.MultiDoc) = x.order
++sigs(::Any) = Type[Union{}]
++
++
++# Footnote checks.
++# ----------------
++"""
++$(SIGNATURES)
++
++Checks footnote links in a [`Documents.Document`](@ref).
++"""
++function footnotes(doc::Documents.Document)
++    println(" > checking footnote links.")
++    # A mapping of footnote ids to a tuple counter of how many footnote references and
++    # footnote bodies have been found.
++    #
++    # For all ids the final result should be `(N, 1)` where `N > 1`, i.e. one or more
++    # footnote references and a single footnote body.
++    footnotes = Dict{Documents.Page, Dict{String, Tuple{Int, Int}}}()
++    for (src, page) in doc.internal.pages
++        empty!(page.globals.meta)
++        orphans = Dict{String, Tuple{Int, Int}}()
++        for element in page.elements
++            Documents.walk(page.globals.meta, page.mapping[element]) do block
++                footnote(block, orphans)
++            end
++        end
++        footnotes[page] = orphans
++    end
++    for (page, orphans) in footnotes
++        for (id, (ids, bodies)) in orphans
++            # Multiple footnote bodies.
++            if bodies > 1
++                push!(doc.internal.errors, :footnote)
++                Utilities.warn(page.source, "Footnote '$id' has $bodies bodies.")
++            end
++            # No footnote references for an id.
++            if ids === 0
++                push!(doc.internal.errors, :footnote)
++                Utilities.warn(page.source, "Unused footnote named '$id'.")
++            end
++            # No footnote bodies for an id.
++            if bodies === 0
++                push!(doc.internal.errors, :footnote)
++                Utilities.warn(page.source, "No footnotes found for '$id'.")
++            end
++        end
++    end
++end
++
++function footnote(fn::Markdown.Footnote, orphans::Dict)
++    ids, bodies = get(orphans, fn.id, (0, 0))
++    if fn.text === nothing
++        # Footnote references: syntax `[^1]`.
++        orphans[fn.id] = (ids + 1, bodies)
++        return false # No more footnotes inside footnote references.
++    else
++        # Footnote body: syntax `[^1]:`.
++        orphans[fn.id] = (ids, bodies + 1)
++        return true # Might be footnotes inside footnote bodies.
++    end
++end
++
++footnote(other, orphans::Dict) = true
++
++# Link Checks.
++# ------------
++
++hascurl() = (try; success(`curl --version`); catch err; false; end)
++
++"""
++$(SIGNATURES)
++
++Checks external links using curl.
++"""
++function linkcheck(doc::Documents.Document)
++    if doc.user.linkcheck
++        if hascurl()
++            println(" > checking external URLs:")
++            for (src, page) in doc.internal.pages
++                println("   - ", src)
++                for element in page.elements
++                    Documents.walk(page.globals.meta, page.mapping[element]) do block
++                        linkcheck(block, doc)
++                    end
++                end
++            end
++        else
++            push!(doc.internal.errors, :linkcheck)
++            Utilities.warn("linkcheck requires `curl`.")
++        end
++    end
++    return nothing
++end
++
++function linkcheck(link::Markdown.Link, doc::Documents.Document)
++    INDENT = " "^6
++
++    # first, make sure we're not supposed to ignore this link
++    for r in doc.user.linkcheck_ignore
++        if linkcheck_ismatch(r, link.url)
++            printstyled(INDENT, "--- ", link.url, "\n", color=:normal)
++            return false
++        end
++    end
++
++    if !haskey(doc.internal.locallinks, link)
++        local result
++        try
++            result = read(`curl -sI $(link.url) --max-time 10`, String)
++        catch err
++            push!(doc.internal.errors, :linkcheck)
++            Utilities.warn("`curl -sI $(link.url)` failed:\n\n$(err)")
++            return false
++        end
++        local STATUS_REGEX   = r"^HTTP/(1.1|2) (\d+) (.+)$"m
++        if occursin(STATUS_REGEX, result)
++            status = parse(Int, match(STATUS_REGEX, result).captures[2])
++            if status < 300
++                printstyled(INDENT, "$(status) ", link.url, "\n", color=:green)
++            elseif status < 400
++                LOCATION_REGEX = r"^Location: (.+)$"m
++                if occursin(LOCATION_REGEX, result)
++                    location = strip(match(LOCATION_REGEX, result).captures[1])
++                    printstyled(INDENT, "$(status) ", link.url, "\n", color=:yellow)
++                    printstyled(INDENT, " -> ", location, "\n\n", color=:yellow)
++                else
++                    printstyled(INDENT, "$(status) ", link.url, "\n", color=:yellow)
++                end
++            else
++                push!(doc.internal.errors, :linkcheck)
++                printstyled(INDENT, "$(status) ", link.url, "\n", color=:red)
++            end
++        else
++            push!(doc.internal.errors, :linkcheck)
++            Utilities.warn("invalid result returned by `curl -sI $(link.url)`:\n\n$(result)")
++        end
++    end
++    return false
++end
++linkcheck(other, doc::Documents.Document) = true
++
++linkcheck_ismatch(r::String, url) = (url == r)
++linkcheck_ismatch(r::Regex, url) = occursin(r, url)
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d1a4240c61ee8f4e6d0794890173482e68f6386f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,270 @@@
++"""
++Provides a consistent interface to retreiving `DocStr` objects from the Julia
++docsystem in both `0.4` and `0.5`.
++"""
++module DocSystem
++
++using DocStringExtensions
++import Markdown
++import Base.Docs: MultiDoc, parsedoc, formatdoc, DocStr
++
++## Bindings ##
++
++"""
++Converts an object to a `Base.Docs.Binding` object.
++
++$(SIGNATURES)
++
++Supported inputs are:
++
++- `Binding`
++- `DataType`
++- `Function`
++- `Module`
++- `Symbol`
++
++Note that unsupported objects will throw an `ArgumentError`.
++"""
++binding(any::Any) = throw(ArgumentError("cannot convert `$(repr(any))` to a `Binding`."))
++
++#
++# The simple definitions.
++#
++binding(b::Docs.Binding) = binding(b.mod, b.var)
++binding(d::DataType)     = binding(d.name.module, d.name.name)
++binding(m::Module)       = binding(m, nameof(m))
++binding(s::Symbol)       = binding(Main, s)
++binding(f::Function)     = binding(typeof(f).name.module, typeof(f).name.mt.name)
++
++#
++# We need a lookup table for `IntrinsicFunction`s since they do not track their
++# own name and defining module.
++#
++# Note that `IntrinsicFunction` is exported from `Base` in `0.4`, but not in `0.5`.
++#
++let INTRINSICS = Dict(map(s -> getfield(Core.Intrinsics, s) => s, names(Core.Intrinsics, all=true)))
++    global binding(i::Core.IntrinsicFunction) = binding(Core.Intrinsics, INTRINSICS[i]::Symbol)
++end
++
++#
++# Normalise the parent module.
++#
++# This is done within the `Binding` constructor on `0.5`, but not on `0.4`.
++#
++function binding(m::Module, v::Symbol)
++    m = nameof(m) === v ? parentmodule(m) : m
++    Docs.Binding(m, v)
++end
++
++#
++# Pseudo-eval of `Expr`s to find their equivalent `Binding`.
++#
++binding(m::Module, x::Expr) =
++    Meta.isexpr(x, :.) ? binding(getmod(m, x.args[1]), x.args[2].value) :
++    Meta.isexpr(x, [:call, :macrocall, :curly]) ? binding(m, x.args[1]) :
++    Meta.isexpr(x, :where) ? binding(m, x.args[1].args[1]) :
++        error("`binding` cannot understand expression `$x`.")
++
++# Helper methods for the above `binding` method.
++getmod(m::Module, x::Expr) = getfield(getmod(m, x.args[1]), x.args[2].value)
++getmod(m::Module, s::Symbol) = getfield(m, s)
++
++binding(m::Module, q::QuoteNode) = binding(Main, q.value)
++
++binding(m::Module, λ::Any) = binding(λ)
++
++## Signatures. ##
++
++function signature(x, str::AbstractString)
++    ts = Base.Docs.signature(x)
++    (Meta.isexpr(x, :macrocall, 2) && !endswith(strip(str), "()")) ? :(Union{}) : ts
++end
++
++## Docstring containers. ##
++
++
++"""
++Construct a `MultiDoc` object from the provided argument.
++
++Valid inputs are:
++
++- `Markdown.MD`
++- `Docs.FuncDoc`
++- `Docs.TypeDoc`
++
++"""
++function multidoc end
++
++function multidoc(markdown::Markdown.MD)
++    md = MultiDoc()
++    sig = Union{}
++    push!(md.order, sig)
++    md.docs[sig] = docstr(markdown)
++    md
++end
++
++
++
++"""
++$(SIGNATURES)
++
++Construct a `DocStr` object from a `Markdown.MD` object.
++
++The optional keyword arguments are used to add new data to the `DocStr`'s
++`.data` dictionary.
++"""
++function docstr(md::Markdown.MD; kws...)
++    data = Dict{Symbol, Any}(
++        :path => md.meta[:path],
++        :module => md.meta[:module],
++        :linenumber => 0,
++    )
++    doc = DocStr(Core.svec(), md, data)
++    for (key, value) in kws
++        doc.data[key] = value
++    end
++    doc
++end
++docstr(other) = other
++
++
++## Formatting `DocStr`s. ##
++
++
++
++
++## Converting docstring caches. ##
++
++"""
++$(SIGNATURES)
++
++Converts a `0.4`-style docstring cache into a `0.5` one.
++
++The original docstring cache is not modified.
++"""
++function convertmeta(meta::IdDict{Any,Any})
++    if !haskey(CACHED, meta)
++        docs = IdDict{Any,Any}()
++        for (k, v) in meta
++            if !isa(k, Union{Number, AbstractString, IdDict{Any,Any}})
++                docs[binding(k)] = multidoc(v)
++            end
++        end
++        CACHED[meta] = docs
++    end
++    CACHED[meta]::IdDict{Any,Any}
++end
++const CACHED = IdDict{Any,Any}()
++
++
++## Get docs from modules.
++
++"""
++$(SIGNATURES)
++
++Find all `DocStr` objects that match the provided arguments:
++
++- `binding`: the name of the object.
++- `typesig`: the signature of the object. Default: `Union{}`.
++- `compare`: how to compare signatures? Exact (`==`) or subtypes (`<:`). Default: `<:`.
++- `modules`: which modules to search through. Default: *all modules*.
++- `aliases`: check aliases of `binding` when nothing is found. Default: `true`.
++
++Returns a `Vector{DocStr}` ordered by definition order in `0.5` and by
++`type_morespecific` in `0.4`.
++"""
++function getdocs(
++        binding::Docs.Binding,
++        typesig::Type = Union{};
++        compare = (==),
++        modules = Docs.modules,
++        aliases = true,
++    )
++    # Fall back to searching all modules if user provides no modules.
++    modules = isempty(modules) ? Docs.modules : modules
++    # Keywords are special-cased within the docsystem. Handle those first.
++    iskeyword(binding) && return [docstr(Base.Docs.keywords[binding.var])]
++    # Handle all the other possible bindings.
++    results = DocStr[]
++    for mod in modules
++        meta = getmeta(mod)
++        if haskey(meta, binding)
++            multidoc = meta[binding]::MultiDoc
++            for signature in multidoc.order
++                if compare(typesig, signature)
++                    doc = multidoc.docs[signature]
++                    doc.data[:binding] = binding
++                    doc.data[:typesig] = signature
++                    push!(results, doc)
++                end
++            end
++        end
++    end
++    if compare == (==)
++        # Exact matching of signatures:
++        #
++        # When we get a single match from using `==` as the comparision then we just return
++        # that one result.
++        #
++        # Otherwise we fallback to comparing signatures using `<:` to match, hopefully, a
++        # wider range of possible docstrings.
++        if length(results) == 1
++            results
++        else
++            getdocs(binding, typesig; compare = (<:), modules = modules, aliases = aliases)
++        end
++    else
++        # When nothing is found we check whether the `binding` is an alias of some other
++        # `Binding`. If so then we redo the search using that `Binding` instead.
++        if aliases && isempty(results) && (b = aliasof(binding)) != binding
++            getdocs(b, typesig; compare = compare, modules = modules)
++        else
++            results
++        end
++    end
++end
++
++"""
++$(SIGNATURES)
++
++Accepts objects of any type and tries to convert them to `Binding`s before
++searching for the `Binding` in the docsystem.
++
++Note that when conversion fails this method returns an empty `Vector{DocStr}`.
++"""
++function getdocs(object::Any, typesig::Type = Union{}; kws...)
++    binding = aliasof(object, object)
++    binding === object ? DocStr[] : getdocs(binding, typesig; kws...)
++end
++
++#
++# Helper methods used by the `getdocs` function above.
++#
++
++getmeta(m::Module) = Docs.meta(m)
++
++import Base.Docs: aliasof, resolve, defined
++
++
++aliasof(s::Symbol, b) = binding(s)
++
++iskeyword(b::Docs.Binding) = b.mod === Main && haskey(Base.Docs.keywords, b.var)
++ismacro(b::Docs.Binding) = startswith(string(b.var), '@')
++
++
++function category(b::Docs.Binding)
++    if iskeyword(b)
++        :keyword
++    elseif ismacro(b)
++        :macro
++    else
++        category(resolve(b))
++    end
++end
++category(::Function) = :function
++category(::DataType) = :type
++category(x::UnionAll) = category(Base.unwrap_unionall(x))
++category(::Module) = :module
++category(::Any) = :constant
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c978d38d188cb0e6732a36ac468d796a73b3c144
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,455 @@@
++"""
++Provides the [`doctest`](@ref) function that makes sure that the `jldoctest` code blocks
++in the documents and docstrings run and are up to date.
++"""
++module DocTests
++using DocStringExtensions
++
++import ..Documenter:
++    Documenter,
++    Documents,
++    Expanders,
++    Utilities
++
++import Markdown, REPL
++
++# Julia code block testing.
++# -------------------------
++
++# escape characters that has a meaning in regex
++regex_escape(str) = sprint(escape_string, str, "\\^\$.|?*+()[{")
++
++# helper to display linerange for error printing
++function find_codeblock_in_file(code, file)
++    content = read(Base.find_source_file(file), String)
++    content = replace(content, "\r\n" => "\n")
++    # make a regex of the code that matches leading whitespace
++    rcode = "\\h*" * replace(regex_escape(code), "\\n" => "\\n\\h*")
++    blockidx = findfirst(Regex(rcode), content)
++    if blockidx !== nothing
++        startline = countlines(IOBuffer(content[1:prevind(content, first(blockidx))]))
++        endline = startline + countlines(IOBuffer(code)) + 1 # +1 to include the closing ```
++        return ":$(startline)-$(endline)"
++    else
++        return ""
++    end
++end
++
++"""
++$(SIGNATURES)
++
++Traverses the document tree and tries to run each Julia code block encountered. Will abort
++the document generation when an error is thrown. Use `doctest = false` keyword in
++[`Documenter.makedocs`](@ref) to disable doctesting.
++"""
++function doctest(doc::Documents.Document)
++    if doc.user.doctest === :fix || doc.user.doctest
++        println(" > running doctests.")
++        for (src, page) in doc.internal.pages
++            empty!(page.globals.meta)
++            for element in page.elements
++                page.globals.meta[:CurrentFile] = page.source
++                Documents.walk(page.globals.meta, page.mapping[element]) do block
++                    doctest(block, page.globals.meta, doc, page)
++                end
++            end
++        end
++    else
++        Utilities.warn("Skipped doctesting.")
++    end
++end
++
++function doctest(block::Markdown.Code, meta::Dict, doc::Documents.Document, page)
++    lang = block.language
++    if startswith(lang, "jldoctest")
++        # Define new module or reuse an old one from this page if we have a named doctest.
++        name = match(r"jldoctest[ ]?(.*)$", split(lang, ';', limit = 2)[1])[1]
++        sym = isempty(name) ? gensym("doctest-") : Symbol("doctest-", name)
++        sandbox = get!(() -> Expanders.get_new_sandbox(sym), page.globals.meta, sym)
++
++        # Normalise line endings.
++        block.code = replace(block.code, "\r\n" => "\n")
++
++        # parse keyword arguments to doctest
++        d = Dict()
++        idx = findfirst(c -> c == ';', lang)
++        if idx !== nothing
++            kwargs = Meta.parse("($(lang[nextind(lang, idx):end]),)")
++            for kwarg in kwargs.args
++                if !(isa(kwarg, Expr) && kwarg.head === :(=) && isa(kwarg.args[1], Symbol))
++                    file = meta[:CurrentFile]
++                    lines = find_codeblock_in_file(block.code, file)
++                    Utilities.warn(
++                        """
++                        Invalid syntax for doctest keyword arguments in $(file)$(lines)
++                        Use ```jldoctest name; key1 = value1, key2 = value2
++
++                        ```$(lang)
++                        $(block.code)
++                        ```
++                        """
++                        )
++                    return false
++                end
++                d[kwarg.args[1]] = Core.eval(sandbox, kwarg.args[2])
++            end
++        end
++        meta[:LocalDocTestArguments] = d
++
++        for expr in [get(meta, :DocTestSetup, []); get(meta[:LocalDocTestArguments], :setup, [])]
++            Meta.isexpr(expr, :block) && (expr.head = :toplevel)
++            try
++                Core.eval(sandbox, expr)
++            catch e
++                push!(doc.internal.errors, :doctest)
++                @error("could not evaluate expression from doctest setup.",
++                    expression = expr, exception = e)
++                return false
++            end
++        end
++        if occursin(r"^julia> "m, block.code)
++            eval_repl(block, sandbox, meta, doc, page)
++        elseif occursin(r"^# output$"m, block.code)
++            eval_script(block, sandbox, meta, doc, page)
++        else
++            push!(doc.internal.errors, :doctest)
++            file = meta[:CurrentFile]
++            lines = find_codeblock_in_file(block.code, file)
++            Utilities.warn(
++                """
++                Invalid doctest block in $(file)$(lines)
++                Requires `julia> ` or `# output`
++
++                ```$(lang)
++                $(block.code)
++                ```
++                """
++            )
++        end
++       delete!(meta, :LocalDocTestArguments)
++    end
++    false
++end
++doctest(block, meta::Dict, doc::Documents.Document, page) = true
++
++function doctest(block::Markdown.MD, meta::Dict, doc::Documents.Document, page)
++    haskey(block.meta, :path) && (meta[:CurrentFile] = block.meta[:path])
++    return true
++end
++
++# Doctest evaluation.
++
++mutable struct Result
++    block  :: Markdown.Code # The entire code block that is being tested.
++    input  :: String # Part of `block.code` representing the current input.
++    output :: String # Part of `block.code` representing the current expected output.
++    file   :: String # File in which the doctest is written. Either `.md` or `.jl`.
++    value  :: Any        # The value returned when evaluating `input`.
++    hide   :: Bool       # Semi-colon suppressing the output?
++    stdout :: IOBuffer   # Redirected stdout/stderr gets sent here.
++    bt     :: Vector     # Backtrace when an error is thrown.
++
++    function Result(block, input, output, file)
++        new(block, input, rstrip(output, '\n'), file, nothing, false, IOBuffer())
++    end
++end
++
++function eval_repl(block, sandbox, meta::Dict, doc::Documents.Document, page)
++    for (input, output) in repl_splitter(block.code)
++        result = Result(block, input, output, meta[:CurrentFile])
++        for (ex, str) in Utilities.parseblock(input, doc, page; keywords = false)
++            # Input containing a semi-colon gets suppressed in the final output.
++            result.hide = REPL.ends_with_semicolon(str)
++            (value, success, backtrace, text) = Utilities.withoutput() do
++                disable_color() do
++                    Core.eval(sandbox, ex)
++                end
++            end
++            result.value = value
++            print(result.stdout, text)
++            if success
++                # Redefine the magic `ans` binding available in the REPL.
++                __ans__!(sandbox, result.value)
++            else
++                result.bt = backtrace
++            end
++        end
++        checkresult(sandbox, result, meta, doc)
++    end
++end
++
++function __ans__!(m::Module, value)
++    isdefined(m, :__ans__!) || Core.eval(m, :(__ans__!(value) = global ans = value))
++    return Core.eval(m, Expr(:call, () -> m.__ans__!(value)))
++end
++
++function eval_script(block, sandbox, meta::Dict, doc::Documents.Document, page)
++    # TODO: decide whether to keep `# output` syntax for this. It's a bit ugly.
++    #       Maybe use double blank lines, i.e.
++    #
++    #
++    #       to mark `input`/`output` separation.
++    input, output = split(block.code, "# output\n", limit = 2)
++    input  = rstrip(input, '\n')
++    output = lstrip(output, '\n')
++    result = Result(block, input, output, meta[:CurrentFile])
++    for (ex, str) in Utilities.parseblock(input, doc, page; keywords = false)
++        (value, success, backtrace, text) = Utilities.withoutput() do
++            Core.eval(sandbox, ex)
++        end
++        result.value = value
++        print(result.stdout, text)
++        if !success
++            result.bt = backtrace
++            break
++        end
++    end
++    checkresult(sandbox, result, meta, doc)
++end
++
++function filter_doctests(strings::NTuple{2, AbstractString},
++                         doc::Documents.Document, meta::Dict)
++    meta_block_filters = get(meta, :DocTestFilters, [])
++    meta_block_filters == nothing && meta_block_filters == []
++    doctest_local_filters = get(meta[:LocalDocTestArguments], :filter, [])
++    for r in [doc.user.doctestfilters; meta_block_filters; doctest_local_filters]
++        if all(occursin.((r,), strings))
++            strings = replace.(strings, (r => "",))
++        end
++    end
++    return strings
++end
++
++# Regex used here to replace gensym'd module names could probably use improvements.
++function checkresult(sandbox::Module, result::Result, meta::Dict, doc::Documents.Document)
++    sandbox_name = nameof(sandbox)
++    mod_regex = Regex("(Main\\.)?(Symbol\\(\"$(sandbox_name)\"\\)|$(sandbox_name))[,.]")
++    mod_regex_nodot = Regex(("(Main\\.)?$(sandbox_name)"))
++    outio = IOContext(result.stdout, :module => sandbox)
++    if isdefined(result, :bt) # An error was thrown and we have a backtrace.
++        # To avoid dealing with path/line number issues in backtraces we use `[...]` to
++        # mark ignored output from an error message. Only the text prior to it is used to
++        # test for doctest success/failure.
++        head = replace(split(result.output, "\n[...]"; limit = 2)[1], mod_regex  => "")
++        head = replace(head, mod_regex_nodot => "Main")
++        str  = replace(error_to_string(outio, result.value, result.bt), mod_regex => "")
++        str  = replace(str, mod_regex_nodot => "Main")
++
++        str, head = filter_doctests((str, head), doc, meta)
++        # Since checking for the prefix of an error won't catch the empty case we need
++        # to check that manually with `isempty`.
++        if isempty(head) || !startswith(str, head)
++            if doc.user.doctest === :fix
++                fix_doctest(result, str, doc)
++            else
++                report(result, str, doc)
++            end
++        end
++    else
++        value = result.hide ? nothing : result.value # `;` hides output.
++        output = replace(rstrip(sanitise(IOBuffer(result.output))), mod_regex => "")
++        str = replace(result_to_string(outio, value), mod_regex => "")
++        # Replace a standalone module name with `Main`.
++        str = rstrip(replace(str, mod_regex_nodot => "Main"))
++        filteredstr, filteredoutput = filter_doctests((str, output), doc, meta)
++        if filteredstr != filteredoutput
++            if doc.user.doctest === :fix
++                fix_doctest(result, str, doc)
++            else
++                report(result, str, doc)
++            end
++        end
++    end
++    return nothing
++end
++
++# Display doctesting results.
++
++function result_to_string(buf, value)
++    dis = text_display(buf)
++    value === nothing || disable_color() do
++        Core.eval(Main, Expr(:call, display, dis, QuoteNode(value)))
++    end
++    sanitise(buf)
++end
++
++text_display(buf) = TextDisplay(IOContext(buf, :limit => true))
++
++funcsym() = CAN_INLINE[] ? :disable_color : :eval
++
++function error_to_string(buf, er, bt)
++    fs = funcsym()
++    # Remove unimportant backtrace info.
++    index = findlast(ptr -> Base.ip_matches_func(ptr, fs), bt)
++    # Print a REPL-like error message.
++    disable_color() do
++        print(buf, "ERROR: ")
++        Base.invokelatest(showerror, buf, er, index === nothing ? bt : bt[1:(index - 1)])
++    end
++    sanitise(buf)
++end
++
++# Strip trailing whitespace and remove terminal colors.
++function sanitise(buffer)
++    out = IOBuffer()
++    for line in eachline(seekstart(Base.unwrapcontext(buffer)[1]))
++        println(out, rstrip(line))
++    end
++    remove_term_colors(rstrip(String(take!(out)), '\n'))
++end
++
++import .Utilities.TextDiff
++
++function report(result::Result, str, doc::Documents.Document)
++    iob = IOBuffer()
++    ioc = IOContext(iob, :color => Base.have_color)
++    println(ioc, "=====[Test Error]", "="^30)
++    println(ioc)
++    printstyled(ioc, "> Location: ", result.file, color=:cyan)
++    printstyled(ioc, find_codeblock_in_file(result.block.code, result.file), color=:cyan)
++    printstyled(ioc, "\n\n> Code block:\n", color=:cyan)
++    println(ioc, "\n```$(result.block.language)")
++    println(ioc, result.block.code)
++    println(ioc, "```")
++    if !isempty(result.input)
++        printstyled(ioc, "\n> Subexpression:\n", color=:cyan)
++        print_indented(ioc, result.input; indent = 4)
++    end
++    warning = Base.have_color ? "" : " (REQUIRES COLOR)"
++    printstyled(ioc, "\n> Output Diff", warning, ":\n\n", color=:cyan)
++    diff = TextDiff.Diff{TextDiff.Words}(result.output, rstrip(str))
++    Utilities.TextDiff.showdiff(ioc, diff)
++    println(ioc, "\n\n", "=====[End Error]=", "="^30)
++    push!(doc.internal.errors, :doctest)
++    printstyled(String(take!(iob)), color=:normal)
++end
++
++function print_indented(buffer::IO, str::AbstractString; indent = 4)
++    println(buffer)
++    for line in split(str, '\n')
++        println(buffer, " "^indent, line)
++    end
++end
++
++function fix_doctest(result::Result, str, doc::Documents.Document)
++    code = result.block.code
++    filename = Base.find_source_file(result.file)
++    # read the file containing the code block
++    content = read(filename, String)
++    # output stream
++    io = IOBuffer(sizehint = sizeof(content))
++    # first look for the entire code block
++    # make a regex of the code that matches leading whitespace
++    rcode = "(\\h*)" * replace(regex_escape(code), "\\n" => "\\n\\h*")
++    r = Regex(rcode)
++    codeidx = findfirst(r, content)
++    if codeidx === nothing
++        Utilities.warn("Could not find code block in source file")
++        return
++    end
++    # use the capture group to identify indentation
++    indent = match(r, content).captures[1]
++    # write everything up until the code block
++    write(io, content[1:prevind(content, first(codeidx))])
++    # next look for the particular input string in the given code block
++    # make a regex of the input that matches leading whitespace (for multiline input)
++    rinput = "\\h*" * replace(regex_escape(result.input), "\\n" => "\\n\\h*")
++    r = Regex(rinput)
++    inputidx = findfirst(r, code)
++    if inputidx === nothing
++        Utilities.warn("Could not find input line in code block")
++        return
++    end
++    # construct the new code-snippet (without indent)
++    # first part: everything up until the last index of the input string
++    newcode = code[1:last(inputidx)]
++    isempty(result.output) && (newcode *= '\n') # issue #772
++    # second part: the rest, with the old output replaced with the new one
++    newcode *= replace(code[nextind(code, last(inputidx)):end], result.output => str, count = 1)
++    # replace internal code block with the non-indented new code, needed if we come back
++    # looking to replace output in the same code block later
++    result.block.code = newcode
++    # write the new code snippet to the stream, with indent
++    newcode = replace(newcode, r"^(.+)$"m => Base.SubstitutionString(indent * "\\1"))
++    write(io, newcode)
++    # write rest of the file
++    write(io, content[nextind(content, last(codeidx)):end])
++    # write to file
++    write(filename, seekstart(io))
++    return
++end
++
++# Remove terminal colors.
++
++const TERM_COLOR_REGEX = r"\e\[[0-9;]*m"
++remove_term_colors(s) = replace(s, TERM_COLOR_REGEX => "")
++
++# REPL doctest splitter.
++
++const PROMPT_REGEX = r"^julia> (.*)$"
++const SOURCE_REGEX = r"^       (.*)$"
++const ANON_FUNC_DECLARATION = r"#[0-9]+ \(generic function with [0-9]+ method(s)?\)"
++
++function repl_splitter(code)
++    lines  = split(string(code, "\n"), '\n')
++    input  = String[]
++    output = String[]
++    buffer = IOBuffer()
++    while !isempty(lines)
++        line = popfirst!(lines)
++        # REPL code blocks may contain leading lines with comments. Drop them.
++        # TODO: handle multiline comments?
++        # ANON_FUNC_DECLARATION deals with `x->x` -> `#1 (generic function ....)` on 0.7
++        # TODO: Remove this special case and just disallow lines with comments?
++        startswith(line, '#') && !occursin(ANON_FUNC_DECLARATION, line) && continue
++        prompt = match(PROMPT_REGEX, line)
++        if prompt === nothing
++            source = match(SOURCE_REGEX, line)
++            if source === nothing
++                savebuffer!(input, buffer)
++                println(buffer, line)
++                takeuntil!(PROMPT_REGEX, buffer, lines)
++            else
++                println(buffer, source[1])
++            end
++        else
++            savebuffer!(output, buffer)
++            println(buffer, prompt[1])
++        end
++    end
++    savebuffer!(output, buffer)
++    zip(input, output)
++end
++
++function savebuffer!(out, buf)
++    n = bytesavailable(seekstart(buf))
++    n > 0 ? push!(out, rstrip(String(take!(buf)))) : out
++end
++
++function takeuntil!(r, buf, lines)
++    while !isempty(lines)
++        line = lines[1]
++        if !occursin(r, line)
++            println(buf, popfirst!(lines))
++        else
++            break
++        end
++    end
++end
++
++function disable_color(func)
++    color = Base.have_color
++    try
++        @eval Base have_color = false
++        func()
++    finally
++        @eval Base have_color = $color
++    end
++end
++
++const CAN_INLINE = Ref(true)
++function __init__()
++    CAN_INLINE[] = Base.JLOptions().can_inline == 0 ? false : true
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..39cdde2aad525a26451d5a571495ac52b6998718
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,642 @@@
++"""
++Main module for `Documenter.jl` -- a documentation generation package for Julia.
++
++Two functions are exported from this module for public use:
++
++- [`makedocs`](@ref). Generates documentation from docstrings and templated markdown files.
++- [`deploydocs`](@ref). Deploys generated documentation from *Travis-CI* to *GitHub Pages*.
++
++# Exports
++
++$(EXPORTS)
++
++"""
++module Documenter
++
++using DocStringExtensions
++import Base64: base64decode
++import Pkg
++
++# Submodules
++# ----------
++
++include("Utilities/Utilities.jl")
++include("DocSystem.jl")
++include("Formats.jl")
++include("Anchors.jl")
++include("Documents.jl")
++include("Builder.jl")
++include("Expanders.jl")
++include("CrossReferences.jl")
++include("DocTests.jl")
++include("DocChecks.jl")
++include("Writers/Writers.jl")
++include("Deps.jl")
++
++import .Utilities: Selectors
++
++
++# User Interface.
++# ---------------
++
++export Deps, makedocs, deploydocs, hide
++
++"""
++    makedocs(
++        root    = "<current-directory>",
++        source  = "src",
++        build   = "build",
++        clean   = true,
++        doctest = true,
++        modules = Module[],
++        repo    = "",
++    )
++
++Combines markdown files and inline docstrings into an interlinked document.
++In most cases [`makedocs`](@ref) should be run from a `make.jl` file:
++
++```julia
++using Documenter
++makedocs(
++    # keywords...
++)
++```
++
++which is then run from the command line with:
++
++```sh
++\$ julia make.jl
++```
++
++The folder structure that [`makedocs`](@ref) expects looks like:
++
++    docs/
++        build/
++        src/
++        make.jl
++
++# Keywords
++
++**`root`** is the directory from which `makedocs` should run. When run from a `make.jl` file
++this keyword does not need to be set. It is, for the most part, needed when repeatedly
++running `makedocs` from the Julia REPL like so:
++
++    julia> makedocs(root = Pkg.dir("MyPackage", "docs"))
++
++**`source`** is the directory, relative to `root`, where the markdown source files are read
++from. By convention this folder is called `src`. Note that any non-markdown files stored
++in `source` are copied over to the build directory when [`makedocs`](@ref) is run.
++
++**`build`** is the directory, relative to `root`, into which generated files and folders are
++written when [`makedocs`](@ref) is run. The name of the build directory is, by convention,
++called `build`, though, like with `source`, users are free to change this to anything else
++to better suit their project needs.
++
++**`clean`** tells [`makedocs`](@ref) whether to remove all the content from the `build`
++folder prior to generating new content from `source`. By default this is set to `true`.
++
++**`doctest`** instructs [`makedocs`](@ref) on whether to try to test Julia code blocks
++that are encountered in the generated document. By default this keyword is set to `true`.
++Doctesting should only ever be disabled when initially setting up a newly developed package
++where the developer is just trying to get their package and documentation structure correct.
++After that, it's encouraged to always make sure that documentation examples are runnable and
++produce the expected results. See the [Doctests](@ref) manual section for details about
++running doctests.
++
++**`modules`** specifies a vector of modules that should be documented in `source`. If any
++inline docstrings from those modules are seen to be missing from the generated content then
++a warning will be printed during execution of [`makedocs`](@ref). By default no modules are
++passed to `modules` and so no warnings will appear. This setting can be used as an indicator
++of the "coverage" of the generated documentation.
++For example Documenter's `make.jl` file contains:
++
++```julia
++makedocs(
++    modules = [Documenter],
++    # ...
++)
++```
++
++and so any docstring from the module `Documenter` that is not spliced into the generated
++documentation in `build` will raise a warning.
++
++**`repo`** specifies a template for the "link to source" feature. If you are
++using GitHub, this is automatically generated from the remote. If you are using
++a different host, you can use this option to tell Documenter how URLs should be
++generated. The following placeholders will be replaced with the respective
++value of the generated link:
++
++  - `{commit}` Git branch or tag name, or commit hash
++  - `{path}` Path to the file in the repository
++  - `{line}` Line (or range of lines) in the source file
++
++For example if you are using GitLab.com, you could use
++
++```julia
++makedocs(repo = \"https://gitlab.com/user/project/blob/{commit}{path}#{line}\")
++```
++
++# Experimental keywords
++
++In addition to standard arguments there is a set of non-finalized experimental keyword
++arguments. The behaviour of these may change or they may be removed without deprecation
++when a minor version changes (i.e. except in patch releases).
++
++**`checkdocs`** instructs [`makedocs`](@ref) to check whether all names within the modules
++defined in the `modules` keyword that have a docstring attached have the docstring also
++listed in the manual (e.g. there's a `@docs` blocks with that docstring). Possible values
++are `:all` (check all names) and `:exports` (check only exported names). The default value
++is `:none`, in which case no checks are performed. If `strict` is also enabled then the
++build will fail if any missing docstrings are encountered.
++
++**`linkcheck`** -- if set to `true` [`makedocs`](@ref) uses `curl` to check the status codes
++of external-pointing links, to make sure that they are up-to-date. The links and their
++status codes are printed to the standard output. If `strict` is also enabled then the build
++will fail if there are any broken (400+ status code) links. Default: `false`.
++
++**`linkcheck_ignore`** allows certain URLs to be ignored in `linkcheck`. The values should
++be a list of strings (which get matched exactly) or `Regex` objects. By default nothing is
++ignored.
++
++**`strict`** -- [`makedocs`](@ref) fails the build right before rendering if it encountered
++any errors with the document in the previous build phases.
++
++## Output formats
++
++**`format`** allows the output format to be specified. Possible values are `:html` (default),
++`:latex` and `:markdown`.
++
++Documenter is designed to support multiple output formats. By default it is creates a set of
++HTML files, but the output format can be controlled with the `format` keyword. The different
++output formats may require additional keywords to be specified. The keywords for the default
++HTML output are documented at the [`Writers.HTMLWriter`](@ref) module.
++
++Documenter also has (experimental) support for Markdown and LaTeX / PDF outputs. See the
++[Other Output Formats](@ref) for more information.
++
++!!! warning
++
++    The Markdown and LaTeX output formats will be moved to a separate package in future
++    versions of Documenter. Automatic documentation deployments should not rely on it unless
++    they fix Documenter to a minor version.
++
++# See Also
++
++A guide detailing how to document a package using Documenter's [`makedocs`](@ref) is provided
++in the [setup guide in the manual](@ref Package-Guide).
++"""
++function makedocs(; debug = false, args...)
++    document = Documents.Document(; args...)
++    cd(document.user.root) do
++        Selectors.dispatch(Builder.DocumentPipeline, document)
++    end
++    debug ? document : nothing
++end
++
++"""
++$(SIGNATURES)
++
++Allows a page to be hidden in the navigation menu. It will only show up if it happens to be
++the current page. The hidden page will still be present in the linear page list that can be
++accessed via the previous and next page links. The title of the hidden page can be overriden
++using the `=>` operator as usual.
++
++# Usage
++
++```julia
++makedocs(
++    ...,
++    pages = [
++        ...,
++        hide("page1.md"),
++        hide("Title" => "page2.md")
++    ]
++)
++```
++"""
++hide(page::Pair) = (false, page.first, page.second, [])
++hide(page::AbstractString) = (false, nothing, page, [])
++
++"""
++$(SIGNATURES)
++
++Allows a subsection of pages to be hidden from the navigation menu. `root` will be linked
++to in the navigation menu, with the title determined as usual. `children` should be a list
++of pages (note that it **can not** be hierarchical).
++
++# Usage
++
++```julia
++makedocs(
++    ...,
++    pages = [
++        ...,
++        hide("Hidden section" => "hidden_index.md", [
++            "hidden1.md",
++            "Hidden 2" => "hidden2.md"
++        ]),
++        hide("hidden_index.md", [...])
++    ]
++)
++```
++"""
++hide(root::Pair, children) = (true, root.first, root.second, map(hide, children))
++hide(root::AbstractString, children) = (true, nothing, root, map(hide, children))
++
++"""
++    deploydocs(
++        root   = "<current-directory>",
++        target = "build",
++        repo   = "<required>",
++        branch = "gh-pages",
++        deps   = nothing | <Function>,
++        make   = nothing | <Function>,
++        devbranch = "master",
++        devurl = "dev",
++        versions = ["stable" => "v^", "v#.#", devurl => devurl]
++    )
++
++Converts markdown files generated by [`makedocs`](@ref) to HTML and pushes them to `repo`.
++This function should be called from within a package's `docs/make.jl` file after the call to
++[`makedocs`](@ref), like so
++
++```julia
++using Documenter, PACKAGE_NAME
++makedocs(
++    # options...
++)
++deploydocs(
++    repo = "github.com/..."
++)
++```
++
++When building the docs for a tag (i.e. a release) the documentation is deployed to
++a directory with the tag name (i.e. `vX.Y.Z`) and to the `stable` directory.
++Otherwise the docs are deployed to the directory determined by the `devurl` argument.
++
++# Required keyword arguments
++
++**`repo`** is the remote repository where generated HTML content should be pushed to. Do not
++specify any protocol - "https://" or "git@" should not be present. This keyword *must*
++be set and will throw an error when left undefined. For example this package uses the
++following `repo` value:
++
++```julia
++repo = "github.com/JuliaDocs/Documenter.jl.git"
++```
++
++# Optional keyword arguments
++
++**`root`** has the same purpose as the `root` keyword for [`makedocs`](@ref).
++
++**`target`** is the directory, relative to `root`, where generated content that should be
++deployed to `gh-pages` is written to. written to. It should generally be the same as
++[`makedocs`](@ref)'s `build` and defaults to `"build"`.
++
++**`branch`** is the branch where the generated documentation is pushed. If the branch does
++not exist, a new orphaned branch is created automatically. It defaults to `"gh-pages"`.
++
++**`deps`** is the function used to install any additional dependencies needed to build the
++documentation. By default nothing is installed.
++
++It can be used e.g. for a Markdown build. The following example installed the `pygments` and
++`mkdocs` Python packages using the [`Deps.pip`](@ref) function:
++
++```julia
++deps = Deps.pip("pygments", "mkdocs")
++```
++
++**`make`** is the function used to specify an additonal build phase. By default, nothing gets
++executed.
++
++**`devbranch`** is the branch that "tracks" the in-development version of the  generated
++documentation. By default this value is set to `"master"`.
++
++**`devurl`** the folder that in-development version of the docs will be deployed.
++Defaults to `"dev"`.
++
++**`versions`** determines content and order of the resulting version selector in
++the generated html. The following entries are valied in the `versions` vector:
++ - `"v#"`: includes links to the latest documentation for each major release cycle
++   (i.e. `v2.0`, `v1.1`).
++ - `"v#.#"`: includes links to the latest documentation for each minor release cycle
++   (i.e. `v2.0`, `v1.1`, `v1.0`, `v0.1`).
++ - `"v#.#.#"`: includes links to all released versions.
++ - `"v^"`: includes a link to the docs for the maximum version
++   (i.e. a link `vX.Y` pointing to `vX.Y.Z` for highest `X`, `Y`, `Z`, respectively).
++ - A pair, e.g. `"first" => "second"`, which will put `"first"` in the selector,
++   and generate a url from which `"second"` can be accessed.
++   The second argument can be `"v^"`, to point to the maximum version docs
++   (as in e.g. `"stable" => "v^"`).
++
++# See Also
++
++The [Hosting Documentation](@ref) section of the manual provides a step-by-step guide to
++using the [`deploydocs`](@ref) function to automatically generate docs and push them to
++GitHub.
++"""
++function deploydocs(;
++        root   = Utilities.currentdir(),
++        target = "build",
++        dirname = "",
++
++        repo   = error("no 'repo' keyword provided."),
++        branch = "gh-pages",
++        latest::Union{String,Nothing} = nothing, # deprecated
++
++        osname::Union{String,Nothing} = nothing, # deprecated
++        julia::Union{String,Nothing} = nothing, # deprecated
++
++        deps   = nothing,
++        make   = nothing,
++
++        devbranch = "master",
++        devurl = "dev",
++        versions = ["stable" => "v^", "v#.#", devurl => devurl]
++    )
++    # deprecation of latest kwarg (renamed to devbranch)
++    if latest !== nothing
++        Base.depwarn("The `latest` keyword argument has been renamed to `devbranch`.", :deploydocs)
++        devbranch = latest
++        @info("setting `devbranch` to `$(devbranch)`.")
++    end
++    # deprecation/removal of `julia` and `osname` kwargs
++    if julia !== nothing
++        Base.depwarn("the `julia` keyword argument to `Documenter.deploydocs` is " *
++            "removed. Use Travis Build Stages for determining from where to deploy instead. " *
++            "See the section about Hosting in the Documenter manual for more details.", :deploydocs)
++        @info("skipping docs deployment.")
++        return
++    end
++    if osname !== nothing
++        Base.depwarn("the `osname` keyword argument to `Documenter.deploydocs` is " *
++            "removed. Use Travis Build Stages for determining from where to deploy instead. " *
++            "See the section about Hosting in the Documenter manual for more details.", :deploydocs)
++        @info("skipping docs deployment.")
++        return
++    end
++
++    # Get environment variables.
++    documenter_key      = get(ENV, "DOCUMENTER_KEY",       "")
++    travis_branch       = get(ENV, "TRAVIS_BRANCH",        "")
++    travis_pull_request = get(ENV, "TRAVIS_PULL_REQUEST",  "")
++    travis_repo_slug    = get(ENV, "TRAVIS_REPO_SLUG",     "")
++    travis_tag          = get(ENV, "TRAVIS_TAG",           "")
++
++
++    # Other variables.
++    sha = cd(root) do
++        # We'll make sure we run the git commands in the source directory (root), in case
++        # the working directory has been changed (e.g. if the makedocs' build argument is
++        # outside root).
++        try
++            readchomp(`git rev-parse --short HEAD`)
++        catch
++            # git rev-parse will throw an error and return code 128 if it is not being
++            # run in a git repository, which will make run/readchomp throw an exception.
++            # We'll assume that if readchomp fails it is due to this and set the sha
++            # variable accordingly.
++            "(not-git-repo)"
++        end
++    end
++
++    # Sanity checks
++    if !isempty(travis_repo_slug) && !occursin(travis_repo_slug, repo)
++        @warn("repo $repo does not match $travis_repo_slug")
++    end
++
++    # When should a deploy be attempted?
++    should_deploy =
++        occursin(travis_repo_slug, repo) &&
++        travis_pull_request == "false"   &&
++        (
++            travis_branch == devbranch ||
++            travis_tag    != ""
++        )
++
++    # check that the tag is valid
++    if should_deploy && !isempty(travis_tag) && !occursin(Base.VERSION_REGEX, travis_tag)
++        @warn("tag `$(travis_tag)` is not a valid VersionNumber")
++        should_deploy = false
++    end
++
++    # check DOCUMENTER_KEY only if the branch, Julia version etc. check out
++    if should_deploy && isempty(documenter_key)
++        @warn("""
++            DOCUMENTER_KEY environment variable missing, unable to deploy.
++              Note that in Documenter v0.9.0 old deprecated authentication methods were removed.
++              DOCUMENTER_KEY is now the only option. See the documentation for more information.""")
++        should_deploy = false
++    end
++
++    if get(ENV, "DOCUMENTER_DEBUG", "") == "true"
++        Utilities.debug("TRAVIS_REPO_SLUG       = \"$travis_repo_slug\"")
++        Utilities.debug("  should occur in \"$repo\" (kwarg: repo)")
++        Utilities.debug("TRAVIS_PULL_REQUEST    = \"$travis_pull_request\"")
++        Utilities.debug("  deploying if equal to \"false\"")
++        Utilities.debug("TRAVIS_BRANCH          = \"$travis_branch\"")
++        Utilities.debug("TRAVIS_TAG             = \"$travis_tag\"")
++        Utilities.debug("  deploying if branch equal to \"$devbranch\" (kwarg: devbranch) or tag is set")
++        Utilities.debug("git commit SHA         = $sha")
++        Utilities.debug("DOCUMENTER_KEY exists  = $(!isempty(documenter_key))")
++        Utilities.debug("should_deploy          = $should_deploy")
++    end
++
++    if should_deploy
++        # Add local bin path if needed.
++        Deps.updatepath!()
++        # Install dependencies when applicable.
++        if deps !== nothing
++            Utilities.log("installing dependencies.")
++            deps()
++        end
++        # Change to the root directory and try to deploy the docs.
++        cd(root) do
++            Utilities.log("setting up target directory.")
++            isdir(target) || mkpath(target)
++            # Run extra build steps defined in `make` if required.
++            if make !== nothing
++                Utilities.log("running extra build steps.")
++                make()
++            end
++            Utilities.log("pushing new documentation to remote: $repo:$branch.")
++            mktempdir() do temp
++                git_push(
++                    root, temp, repo;
++                    branch=branch, dirname=dirname, target=target,
++                    tag=travis_tag, key=documenter_key, sha=sha,
++                    devurl = devurl, versions = versions,
++                )
++            end
++        end
++    else
++        Utilities.log("skipping docs deployment.")
++        if get(ENV, "DOCUMENTER_DEBUG", "") != "true"
++              Utilities.log("You can set DOCUMENTER_DEBUG to \"true\" in Travis to see more information.")
++        end
++    end
++end
++
++"""
++    git_push(
++        root, tmp, repo;
++        branch="gh-pages", dirname="", target="site", tag="", key="", sha="", devurl="dev"
++    )
++
++Handles pushing changes to the remote documentation branch.
++When `tag` is empty the docs are deployed to the `devurl` directory,
++and when building docs for a tag they are deployed to a `vX.Y.Z` directory.
++"""
++function git_push(
++        root, temp, repo;
++        branch="gh-pages", dirname="", target="site", tag="", key="", sha="", devurl="dev",
++        versions
++    )
++    dirname = isempty(dirname) ? temp : joinpath(temp, dirname)
++    isdir(dirname) || mkpath(dirname)
++
++    keyfile = abspath(joinpath(root, ".documenter"))
++    target_dir = abspath(target)
++
++    # The upstream URL to which we push new content and the ssh decryption commands.
++    upstream = "git@$(replace(repo, "github.com/" => "github.com:"))"
++
++    write(keyfile, String(base64decode(key)))
++    chmod(keyfile, 0o600)
++
++    try
++        # Use a custom SSH config file to avoid overwriting the default user config.
++        withfile(joinpath(homedir(), ".ssh", "config"),
++            """
++            Host github.com
++                StrictHostKeyChecking no
++                HostName github.com
++                IdentityFile $keyfile
++            """
++        ) do
++            cd(temp) do
++                # Setup git.
++                run(`git init`)
++                run(`git config user.name "autodocs"`)
++                run(`git config user.email "autodocs"`)
++
++                # Fetch from remote and checkout the branch.
++                run(`git remote add upstream $upstream`)
++                run(`git fetch upstream`)
++
++                try
++                    run(`git checkout -b $branch upstream/$branch`)
++                catch e
++                    Utilities.log("Checking out $branch failed with error: $e")
++                    Utilities.log("Creating a new local $branch branch.")
++                    run(`git checkout --orphan $branch`)
++                    run(`git commit --allow-empty -m "Initial empty commit for docs"`)
++                end
++
++                # Copy docs to `devurl`, or `stable`, `<release>`, and `<version>` directories.
++                if isempty(tag)
++                    devurl_dir = joinpath(dirname, devurl)
++                    gitrm_copy(target_dir, devurl_dir)
++                    Writers.HTMLWriter.generate_siteinfo_file(devurl_dir, devurl)
++                    # symlink "latest" to devurl to preserve links (remove in some future release)
++                    if devurl != "latest"
++                        rm(joinpath(dirname, "latest"); recursive = true, force = true)
++                        @warn(string("creating symlink from `latest` to `$(devurl)` for backwards ",
++                            "compatibility with old links. In future Documenter versions this symlink ",
++                            "will not be created. Please update any links that point to `latest`."))
++                        cd(dirname) do; rm_and_add_symlink(devurl, "latest"); end
++                    end
++                else
++                    tagged_dir = joinpath(dirname, tag)
++                    gitrm_copy(target_dir, tagged_dir)
++                    Writers.HTMLWriter.generate_siteinfo_file(tagged_dir, tag)
++                end
++
++                # Expand the users `versions` vector
++                entries, symlinks = Writers.HTMLWriter.expand_versions(dirname, versions)
++
++                # Create the versions.js file containing a list of `entries`.
++                # This must always happen after the folder copying.
++                Writers.HTMLWriter.generate_version_file(joinpath(dirname, "versions.js"), entries)
++
++                # generate the symlinks, make sure we don't overwrite devurl
++                cd(dirname) do
++                    for kv in symlinks
++                        i = findfirst(x -> x.first == devurl, symlinks)
++                        if i === nothing
++                            rm_and_add_symlink(kv.second, kv.first)
++                        else
++                            throw(ArgumentError(string("link `$(kv)` cannot overwrite ",
++                                "`devurl = $(devurl)` with the same name.")))
++                        end
++                    end
++                end
++
++                # Add, commit, and push the docs to the remote.
++                run(`git add -A .`)
++                if !success(`git diff --cached --exit-code`)
++                    run(`git commit -m "build based on $sha"`)
++                    run(`git push -q upstream HEAD:$branch`)
++                else
++                    Utilities.log("New docs identical to the old -- not committing nor pushing.")
++                end
++            end
++        end
++    finally
++        # Remove the unencrypted private key.
++        isfile(keyfile) && rm(keyfile)
++    end
++end
++
++function rm_and_add_symlink(target, link)
++    if ispath(link)
++        @warn "removing `$(link)` and linking `$(link)` to `$(target)`."
++        rm(link; force = true, recursive = true)
++    end
++    symlink(target, link)
++end
++
++"""
++    gitrm_copy(src, dst)
++
++Uses `git rm -r` to remove `dst` and then copies `src` to `dst`. Assumes that the working
++directory is within the git repository of `dst` is when the function is called.
++
++This is to get around [#507](https://github.com/JuliaDocs/Documenter.jl/issues/507) on
++filesystems that are case-insensitive (e.g. on OS X, Windows). Without doing a `git rm`
++first, `git add -A` will not detect case changes in filenames.
++"""
++function gitrm_copy(src, dst)
++    # --ignore-unmatch so that we wouldn't get errors if dst does not exist
++    run(`git rm -rf --ignore-unmatch $(dst)`)
++    cp(src, dst; force=true)
++end
++
++function withfile(func, file::AbstractString, contents::AbstractString)
++    hasfile = isfile(file)
++    original = hasfile ? read(file, String) : ""
++    open(file, "w") do stream
++        print(stream, contents)
++        flush(stream) # Make sure file is written before continuing.
++    end
++    try
++        func()
++    finally
++        if hasfile
++            open(file, "w") do stream
++                print(stream, original)
++            end
++        else
++            rm(file)
++        end
++    end
++end
++
++function getenv(regex::Regex)
++    for (key, value) in ENV
++        occursin(regex, key) && return value
++    end
++    error("could not find key/iv pair.")
++end
++
++end # module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a5e44486d06721bd17de2fc044eae45ec5ff9482
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,489 @@@
++"""
++Defines [`Document`](@ref) and its supporting types
++
++- [`Page`](@ref)
++- [`User`](@ref)
++- [`Internal`](@ref)
++- [`Globals`](@ref)
++
++"""
++module Documents
++
++import ..Documenter:
++    Anchors,
++    Formats,
++    Utilities
++
++using DocStringExtensions
++import Markdown
++using Unicode
++
++# Pages.
++# ------
++
++"""
++[`Page`](@ref)-local values such as current module that are shared between nodes in a page.
++"""
++mutable struct Globals
++    mod  :: Module
++    meta :: Dict{Symbol, Any}
++end
++Globals() = Globals(Main, Dict())
++
++"""
++Represents a single markdown file.
++"""
++struct Page
++    source   :: String
++    build    :: String
++    """
++    Ordered list of raw toplevel markdown nodes from the parsed page contents. This vector
++    should be considered immutable.
++    """
++    elements :: Vector
++    """
++    Each element in `.elements` maps to an "expanded" element. This may be itself if the
++    element does not need expanding or some other object, such as a `DocsNode` in the case
++    of `@docs` code blocks.
++    """
++    mapping  :: IdDict{Any,Any}
++    globals  :: Globals
++end
++function Page(source::AbstractString, build::AbstractString)
++    elements = Markdown.parse(read(source, String)).content
++    Page(source, build, elements, IdDict{Any,Any}(), Globals())
++end
++
++# Document Nodes.
++# ---------------
++
++## IndexNode.
++
++struct IndexNode
++    pages    :: Vector{String} # Which pages to include in the index? Set by user.
++    modules  :: Vector{Module} # Which modules to include? Set by user.
++    order    :: Vector{Symbol} # What order should docs be listed in? Set by user.
++    build    :: String         # Path to the file where this index will appear.
++    source   :: String         # Path to the file where this index was written.
++    elements :: Vector         # (object, doc, page, mod, cat)-tuple for constructing links.
++
++    function IndexNode(;
++            # TODO: Fix difference between uppercase and lowercase naming of keys.
++            #       Perhaps deprecate the uppercase versions? Same with `ContentsNode`.
++            Pages   = [],
++            Modules = [],
++            Order   = [:module, :constant, :type, :function, :macro],
++            build   = error("missing value for `build` in `IndexNode`."),
++            source  = error("missing value for `source` in `IndexNode`."),
++            others...
++        )
++        new(Pages, Modules, Order, build, source, [])
++    end
++end
++
++## ContentsNode.
++
++struct ContentsNode
++    pages    :: Vector{String} # Which pages should be included in contents? Set by user.
++    depth    :: Int            # Down to which level should headers be displayed? Set by user.
++    build    :: String         # Same as for `IndexNode`s.
++    source   :: String         # Same as for `IndexNode`s.
++    elements :: Vector         # (order, page, anchor)-tuple for constructing links.
++
++    function ContentsNode(;
++            Pages  = [],
++            Depth  = 2,
++            build  = error("missing value for `build` in `ContentsNode`."),
++            source = error("missing value for `source` in `ContentsNode`."),
++            others...
++        )
++        new(Pages, Depth, build, source, [])
++    end
++end
++
++## Other nodes
++
++struct MetaNode
++    dict :: Dict{Symbol, Any}
++end
++
++struct MethodNode
++    method  :: Method
++    visible :: Bool
++end
++
++struct DocsNode
++    docstr  :: Any
++    anchor  :: Anchors.Anchor
++    object  :: Utilities.Object
++    page    :: Documents.Page
++end
++
++struct DocsNodes
++    nodes :: Vector{DocsNode}
++end
++
++struct EvalNode
++    code   :: Markdown.Code
++    result :: Any
++end
++
++struct RawHTML
++    code::String
++end
++
++struct RawNode
++    name::Symbol
++    text::String
++end
++
++# Navigation
++# ----------------------
++
++"""
++Element in the navigation tree of a document, containing navigation references
++to other page, reference to the [`Page`](@ref) object etc.
++"""
++mutable struct NavNode
++    """
++    `nothing` if the `NavNode` is a non-page node of the navigation tree, otherwise
++    the string should be a valid key in `doc.internal.pages`
++    """
++    page           :: Union{String, Nothing}
++    """
++    If not `nothing`, specifies the text that should be displayed in navigation
++    links etc. instead of the automatically determined text.
++    """
++    title_override :: Union{String, Nothing}
++    parent         :: Union{NavNode, Nothing}
++    children       :: Vector{NavNode}
++    visible        :: Bool
++    prev           :: Union{NavNode, Nothing}
++    next           :: Union{NavNode, Nothing}
++end
++NavNode(page, title_override, parent) = NavNode(page, title_override, parent, [], true, nothing, nothing)
++
++"""
++Constructs a list of the ancestors of the `navnode` (inclding the `navnode` itself),
++ordered so that the root of the navigation tree is the first and `navnode` itself
++is the last item.
++"""
++navpath(navnode::NavNode) = navnode.parent === nothing ? [navnode] :
++    push!(navpath(navnode.parent), navnode)
++
++
++# Inner Document Fields.
++# ----------------------
++
++"""
++User-specified values used to control the generation process.
++"""
++struct User
++    root    :: String  # An absolute path to the root directory of the document.
++    source  :: String  # Parent directory is `.root`. Where files are read from.
++    build   :: String  # Parent directory is also `.root`. Where files are written to.
++    format  :: Vector{Symbol} # What format to render the final document with?
++    clean   :: Bool           # Empty the `build` directory before starting a new build?
++    doctest :: Union{Bool,Symbol} # Run doctests?
++    linkcheck::Bool           # Check external links..
++    linkcheck_ignore::Vector{Union{String,Regex}}  # ..and then ignore (some of) them.
++    checkdocs::Symbol         # Check objects missing from `@docs` blocks. `:none`, `:exports`, or `:all`.
++    doctestfilters::Vector{Regex} # Filtering for doctests
++    strict::Bool              # Throw an exception when any warnings are encountered.
++    modules :: Set{Module}    # Which modules to check for missing docs?
++    pages   :: Vector{Any}    # Ordering of document pages specified by the user.
++    assets  :: Vector{String}
++    repo    :: String  # Template for URL to source code repo
++    sitename:: String
++    authors :: String
++    analytics::String
++    version :: String # version string used in the version selector by default
++    html_prettyurls :: Bool # Use pretty URLs in the HTML build?
++    html_disable_git :: Bool # Don't call git when exporting HTML
++    html_edit_branch :: Union{String, Nothing} # Change how the "Edit on GitHub" links are handled
++    html_canonical   :: Union{String, Nothing} # Set a canonical url, if desired (https://en.wikipedia.org/wiki/Canonical_link_element)
++end
++
++"""
++Private state used to control the generation process.
++"""
++struct Internal
++    assets  :: String             # Path where asset files will be copied to.
++    remote  :: String             # The remote repo on github where this package is hosted.
++    pages   :: Dict{String, Page} # Markdown files only.
++    navtree :: Vector{NavNode}           # A vector of top-level navigation items.
++    navlist :: Vector{NavNode}           # An ordered list of `NavNode`s that point to actual pages
++    headers :: Anchors.AnchorMap         # See `modules/Anchors.jl`. Tracks `Markdown.Header` objects.
++    docs    :: Anchors.AnchorMap         # See `modules/Anchors.jl`. Tracks `@docs` docstrings.
++    bindings:: IdDict{Any,Any}           # Tracks insertion order of object per-binding.
++    objects :: IdDict{Any,Any}           # Tracks which `Utilities.Objects` are included in the `Document`.
++    contentsnodes :: Vector{ContentsNode}
++    indexnodes    :: Vector{IndexNode}
++    locallinks :: Dict{Markdown.Link, String}
++    errors::Set{Symbol}
++end
++
++# Document.
++# ---------
++
++"""
++Represents an entire document.
++"""
++struct Document
++    user     :: User     # Set by the user via `makedocs`.
++    internal :: Internal # Computed values.
++end
++
++function Document(;
++        root     :: AbstractString   = Utilities.currentdir(),
++        source   :: AbstractString   = "src",
++        build    :: AbstractString   = "build",
++        format   :: Any              = :html,
++        clean    :: Bool             = true,
++        doctest  :: Union{Bool,Symbol} = true,
++        linkcheck:: Bool             = false,
++        linkcheck_ignore :: Vector   = [],
++        checkdocs::Symbol            = :all,
++        doctestfilters::Vector{Regex}= Regex[],
++        strict::Bool                 = false,
++        modules  :: Utilities.ModVec = Module[],
++        pages    :: Vector           = Any[],
++        assets   :: Vector           = String[],
++        repo     :: AbstractString   = "",
++        sitename :: AbstractString   = "",
++        authors  :: AbstractString   = "",
++        analytics :: AbstractString  = "",
++        version :: AbstractString    = "",
++        html_prettyurls  :: Bool     = true,
++        html_disable_git :: Bool     = false,
++        html_edit_branch :: Union{String, Nothing} = "master",
++        html_canonical   :: Union{String, Nothing} = nothing,
++        others...
++    )
++    Utilities.check_kwargs(others)
++
++    fmt = Formats.fmt(format)
++    @assert !isempty(fmt) "No formats provided."
++
++    if version == "git-commit"
++        version = "git:$(Utilities.get_commit_short(root))"
++    end
++
++    user = User(
++        root,
++        source,
++        build,
++        fmt,
++        clean,
++        doctest,
++        linkcheck,
++        linkcheck_ignore,
++        checkdocs,
++        doctestfilters,
++        strict,
++        Utilities.submodules(modules),
++        pages,
++        assets,
++        repo,
++        sitename,
++        authors,
++        analytics,
++        version,
++        html_prettyurls,
++        html_disable_git,
++        html_edit_branch,
++        html_canonical,
++    )
++    internal = Internal(
++        Utilities.assetsdir(),
++        Utilities.getremote(root),
++        Dict{String, Page}(),
++        [],
++        [],
++        Anchors.AnchorMap(),
++        Anchors.AnchorMap(),
++        IdDict{Any,Any}(),
++        IdDict{Any,Any}(),
++        [],
++        [],
++        Dict{Markdown.Link, String}(),
++        Set{Symbol}(),
++    )
++    Document(user, internal)
++end
++
++## Methods
++
++function addpage!(doc::Document, src::AbstractString, dst::AbstractString)
++    page = Page(src, dst)
++    # page's identifier is the path relative to the `doc.user.source` directory
++    name = normpath(relpath(src, doc.user.source))
++    doc.internal.pages[name] = page
++end
++
++"""
++$(SIGNATURES)
++
++Populates the `ContentsNode`s and `IndexNode`s of the `document` with links.
++
++This can only be done after all the blocks have been expanded (and nodes constructed),
++because the items have to exist before we can gather the links to those items.
++"""
++function populate!(document::Document)
++    for node in document.internal.contentsnodes
++        populate!(node, document)
++    end
++    for node in document.internal.indexnodes
++        populate!(node, document)
++    end
++end
++
++function populate!(index::IndexNode, document::Document)
++    # Filtering valid index links.
++    for (object, doc) in document.internal.objects
++        page = relpath(doc.page.build, dirname(index.build))
++        mod  = object.binding.mod
++        # Include *all* signatures, whether they are `Union{}` or not.
++        cat  = Symbol(lowercase(Utilities.doccat(object.binding, Union{})))
++        if _isvalid(page, index.pages) && _isvalid(mod, index.modules) && _isvalid(cat, index.order)
++            push!(index.elements, (object, doc, page, mod, cat))
++        end
++    end
++    # Sorting index links.
++    pagesmap   = precedence(index.pages)
++    modulesmap = precedence(index.modules)
++    ordermap   = precedence(index.order)
++    comparison = function(a, b)
++        (x = _compare(pagesmap,   3, a, b)) == 0 || return x < 0 # page
++        (x = _compare(modulesmap, 4, a, b)) == 0 || return x < 0 # module
++        (x = _compare(ordermap,   5, a, b)) == 0 || return x < 0 # category
++        string(a[1].binding) < string(b[1].binding)              # object name
++    end
++    sort!(index.elements, lt = comparison)
++    return index
++end
++
++function populate!(contents::ContentsNode, document::Document)
++    # Filtering valid contents links.
++    for (id, filedict) in document.internal.headers.map
++        for (file, anchors) in filedict
++            for anchor in anchors
++                page = relpath(anchor.file, dirname(contents.build))
++                if _isvalid(page, contents.pages) && Utilities.header_level(anchor.object) ≤ contents.depth
++                    push!(contents.elements, (anchor.order, page, anchor))
++                end
++            end
++        end
++    end
++    # Sorting contents links.
++    pagesmap   = precedence(contents.pages)
++    comparison = function(a, b)
++        (x = _compare(pagesmap, 2, a, b)) == 0 || return x < 0 # page
++        a[1] < b[1]                                            # anchor order
++    end
++    sort!(contents.elements, lt = comparison)
++    return contents
++end
++
++# some replacements for jldoctest blocks
++function doctest_replace!(doc::Documents.Document)
++    for (src, page) in doc.internal.pages
++        empty!(page.globals.meta)
++        for element in page.elements
++            page.globals.meta[:CurrentFile] = page.source
++            walk(page.globals.meta, page.mapping[element]) do block
++                doctest_replace!(block)
++            end
++        end
++    end
++end
++function doctest_replace!(block::Markdown.Code)
++    startswith(block.language, "jldoctest") || return false
++    # suppress output for `#output`-style doctests with `output=false` kwarg
++    if occursin(r"^# output$"m, block.code) && occursin(r";.*output\h*=\h*false", block.language)
++        input = first(split(block.code, "# output\n", limit = 2))
++        block.code = rstrip(input)
++    end
++    # correct the language field
++    block.language = occursin(r"^julia> "m, block.code) ? "julia-repl" : "julia"
++    return false
++end
++doctest_replace!(block) = true
++
++## Utilities.
++
++function buildnode(T::Type, block, doc, page)
++    mod  = get(page.globals.meta, :CurrentModule, Main)
++    dict = Dict{Symbol, Any}(:source => page.source, :build => page.build)
++    for (ex, str) in Utilities.parseblock(block.code, doc, page)
++        if Utilities.isassign(ex)
++            cd(dirname(page.source)) do
++                dict[ex.args[1]] = Core.eval(mod, ex.args[2])
++            end
++        end
++    end
++    T(; dict...)
++end
++
++function _compare(col, ind, a, b)
++    x, y = a[ind], b[ind]
++    haskey(col, x) && haskey(col, y) ? _compare(col[x], col[y]) : 0
++end
++_compare(a, b)  = a < b ? -1 : a == b ? 0 : 1
++_isvalid(x, xs) = isempty(xs) || x in xs
++precedence(vec) = Dict(zip(vec, 1:length(vec)))
++
++##############################################
++# walk (previously in the Walkers submodule) #
++##############################################
++"""
++$(SIGNATURES)
++
++Calls `f` on `element` and any of its child elements. `meta` is a `Dict` containing metadata
++such as current module.
++"""
++walk(f, meta, element) = (f(element); nothing)
++
++# Change to the docstring's defining module if it has one. Change back afterwards.
++function walk(f, meta, block::Markdown.MD)
++    tmp = get(meta, :CurrentModule, nothing)
++    mod = get(block.meta, :module, nothing)
++    mod ≡ nothing || (meta[:CurrentModule] = mod)
++    f(block) && walk(f, meta, block.content)
++    tmp ≡ nothing ? delete!(meta, :CurrentModule) : (meta[:CurrentModule] = tmp)
++    nothing
++end
++
++function walk(f, meta, block::Vector)
++    for each in block
++        walk(f, meta, each)
++    end
++end
++
++const MDContentElements = Union{
++    Markdown.BlockQuote,
++    Markdown.Paragraph,
++    Markdown.MD,
++}
++walk(f, meta, block::MDContentElements) = f(block) ? walk(f, meta, block.content) : nothing
++
++const MDTextElements = Union{
++    Markdown.Bold,
++    Markdown.Header,
++    Markdown.Italic,
++}
++walk(f, meta, block::MDTextElements)      = f(block) ? walk(f, meta, block.text)    : nothing
++walk(f, meta, block::Markdown.Footnote)   = f(block) ? walk(f, meta, block.text)    : nothing
++walk(f, meta, block::Markdown.Admonition) = f(block) ? walk(f, meta, block.content) : nothing
++walk(f, meta, block::Markdown.Image)      = f(block) ? walk(f, meta, block.alt)     : nothing
++walk(f, meta, block::Markdown.Table)      = f(block) ? walk(f, meta, block.rows)    : nothing
++walk(f, meta, block::Markdown.List)       = f(block) ? walk(f, meta, block.items)   : nothing
++walk(f, meta, block::Markdown.Link)       = f(block) ? walk(f, meta, block.text)    : nothing
++walk(f, meta, block::RawHTML) = nothing
++walk(f, meta, block::DocsNodes) = walk(f, meta, block.nodes)
++walk(f, meta, block::DocsNode)  = walk(f, meta, block.docstr)
++walk(f, meta, block::EvalNode)  = walk(f, meta, block.result)
++walk(f, meta, block::MetaNode)  = (merge!(meta, block.dict); nothing)
++walk(f, meta, block::Anchors.Anchor) = walk(f, meta, block.object)
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..81e0abb869dd954eaf77d050aa333297ec577773
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,645 @@@
++"""
++Defines node "expanders" that transform nodes from the parsed markdown files.
++"""
++module Expanders
++
++import ..Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Formats,
++    Documenter,
++    Utilities
++
++import .Documents:
++    MethodNode,
++    DocsNode,
++    DocsNodes,
++    EvalNode,
++    MetaNode
++
++import .Utilities: Selectors
++
++import Markdown, REPL
++import Base64: stringmime
++
++
++function expand(doc::Documents.Document)
++    for (src, page) in doc.internal.pages
++        empty!(page.globals.meta)
++        for element in page.elements
++            Selectors.dispatch(ExpanderPipeline, element, page, doc)
++        end
++        pagecheck(page)
++    end
++end
++
++# run some checks after expanding the page
++function pagecheck(page)
++    # make sure there is no "continued code" lingering around
++    if haskey(page.globals.meta, :ContinuedCode) && !isempty(page.globals.meta[:ContinuedCode])
++        Utilities.warn(page.source, "Code from a continued @example block unused.")
++    end
++end
++
++
++# Expander Pipeline.
++# ------------------
++
++"""
++The default node expander "pipeline", which consists of the following expanders:
++
++- [`TrackHeaders`](@ref)
++- [`MetaBlocks`](@ref)
++- [`DocsBlocks`](@ref)
++- [`AutoDocsBlocks`](@ref)
++- [`EvalBlocks`](@ref)
++- [`IndexBlocks`](@ref)
++- [`ContentsBlocks`](@ref)
++- [`ExampleBlocks`](@ref)
++- [`SetupBlocks`](@ref)
++- [`REPLBlocks`](@ref)
++
++"""
++abstract type ExpanderPipeline <: Selectors.AbstractSelector end
++
++"""
++Tracks all `Markdown.Header` nodes found in the parsed markdown files and stores an
++[`Anchors.Anchor`](@ref) object for each one.
++"""
++abstract type TrackHeaders <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@meta` and evaluates the key/value pairs found
++within the block, i.e.
++
++````markdown
++```@meta
++CurrentModule = Documenter
++DocTestSetup  = quote
++    using Documenter
++end
++```
++````
++"""
++abstract type MetaBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@docs` and evaluates the expressions found
++within the block. Replaces the block with the docstrings associated with each expression.
++
++````markdown
++```@docs
++Documenter
++makedocs
++deploydocs
++```
++````
++"""
++abstract type DocsBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@autodocs` and replaces it with all the
++docstrings that match the provided key/value pairs `Modules = ...` and `Order = ...`.
++
++````markdown
++```@autodocs
++Modules = [Foo, Bar]
++Order   = [:function, :type]
++```
++````
++"""
++abstract type AutoDocsBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@eval` and evaluates it's content. Replaces
++the block with the value resulting from the evaluation. This can be useful for inserting
++generated content into a document such as plots.
++
++````markdown
++```@eval
++using PyPlot
++x = linspace(-π, π)
++y = sin(x)
++plot(x, y, color = "red")
++savefig("plot.svg")
++Markdown.parse("![Plot](plot.svg)")
++```
++````
++"""
++abstract type EvalBlocks <: ExpanderPipeline end
++
++abstract type RawBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@index` and replaces it with an index of all
++docstrings spliced into the document. The pages that are included can be set using a
++key/value pair `Pages = [...]` such as
++
++````markdown
++```@index
++Pages = ["foo.md", "bar.md"]
++```
++````
++"""
++abstract type IndexBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@contents` and replaces it with a nested list
++of all `Header` nodes in the generated document. The pages and depth of the list can be set
++using `Pages = [...]` and `Depth = N` where `N` is and integer.
++
++````markdown
++```@contents
++Pages = ["foo.md", "bar.md"]
++Depth = 1
++```
++````
++The default `Depth` value is `2`.
++"""
++abstract type ContentsBlocks <: ExpanderPipeline end
++
++"""
++Parses each code block where the language is `@example` and evaluates the parsed Julia code
++found within. The resulting value is then inserted into the final document after the source
++code.
++
++````markdown
++```@example
++a = 1
++b = 2
++a + b
++```
++````
++"""
++abstract type ExampleBlocks <: ExpanderPipeline end
++
++"""
++Similar to the [`ExampleBlocks`](@ref) expander, but inserts a Julia REPL prompt before each
++toplevel expression in the final document.
++"""
++abstract type REPLBlocks <: ExpanderPipeline end
++
++"""
++Similar to the [`ExampleBlocks`](@ref) expander, but hides all output in the final document.
++"""
++abstract type SetupBlocks <: ExpanderPipeline end
++
++Selectors.order(::Type{TrackHeaders})   = 1.0
++Selectors.order(::Type{MetaBlocks})     = 2.0
++Selectors.order(::Type{DocsBlocks})     = 3.0
++Selectors.order(::Type{AutoDocsBlocks}) = 4.0
++Selectors.order(::Type{EvalBlocks})     = 5.0
++Selectors.order(::Type{IndexBlocks})    = 6.0
++Selectors.order(::Type{ContentsBlocks}) = 7.0
++Selectors.order(::Type{ExampleBlocks})  = 8.0
++Selectors.order(::Type{REPLBlocks})     = 9.0
++Selectors.order(::Type{SetupBlocks})    = 10.0
++Selectors.order(::Type{RawBlocks})      = 11.0
++
++Selectors.matcher(::Type{TrackHeaders},   node, page, doc) = isa(node, Markdown.Header)
++Selectors.matcher(::Type{MetaBlocks},     node, page, doc) = iscode(node, "@meta")
++Selectors.matcher(::Type{DocsBlocks},     node, page, doc) = iscode(node, "@docs")
++Selectors.matcher(::Type{AutoDocsBlocks}, node, page, doc) = iscode(node, "@autodocs")
++Selectors.matcher(::Type{EvalBlocks},     node, page, doc) = iscode(node, "@eval")
++Selectors.matcher(::Type{IndexBlocks},    node, page, doc) = iscode(node, "@index")
++Selectors.matcher(::Type{ContentsBlocks}, node, page, doc) = iscode(node, "@contents")
++Selectors.matcher(::Type{ExampleBlocks},  node, page, doc) = iscode(node, r"^@example")
++Selectors.matcher(::Type{REPLBlocks},     node, page, doc) = iscode(node, r"^@repl")
++Selectors.matcher(::Type{SetupBlocks},    node, page, doc) = iscode(node, r"^@setup")
++Selectors.matcher(::Type{RawBlocks},      node, page, doc) = iscode(node, r"^@raw")
++
++# Default Expander.
++
++Selectors.runner(::Type{ExpanderPipeline}, x, page, doc) = page.mapping[x] = x
++
++# Track Headers.
++# --------------
++
++function Selectors.runner(::Type{TrackHeaders}, header, page, doc)
++    # Get the header slug.
++    text =
++        if namedheader(header)
++            url = header.text[1].url
++            header.text = header.text[1].text
++            match(NAMEDHEADER_REGEX, url)[1]
++        else
++            sprint(Markdown.plain, Markdown.Paragraph(header.text))
++        end
++    slug = Utilities.slugify(text)
++    # Add the header to the document's header map.
++    anchor = Anchors.add!(doc.internal.headers, header, slug, page.build)
++    # Map the header element to the generated anchor and the current anchor count.
++    page.mapping[header] = anchor
++end
++
++# @meta
++# -----
++
++function Selectors.runner(::Type{MetaBlocks}, x, page, doc)
++    meta = page.globals.meta
++    for (ex, str) in Utilities.parseblock(x.code, doc, page)
++        if Utilities.isassign(ex)
++            try
++                meta[ex.args[1]] = Core.eval(Main, ex.args[2])
++            catch err
++                push!(doc.internal.errors, :meta_block)
++                Utilities.warn(doc, page, "Failed to evaluate `$(strip(str))` in `@meta` block.", err)
++            end
++        end
++    end
++    page.mapping[x] = MetaNode(copy(meta))
++end
++
++# @docs
++# -----
++
++function Selectors.runner(::Type{DocsBlocks}, x, page, doc)
++    failed = false
++    nodes  = DocsNode[]
++    curmod = get(page.globals.meta, :CurrentModule, Main)
++    for (ex, str) in Utilities.parseblock(x.code, doc, page)
++        binding = try
++            Documenter.DocSystem.binding(curmod, ex)
++        catch err
++            push!(doc.internal.errors, :docs_block)
++            Utilities.warn(page.source, "Unable to get the binding for '$(strip(str))'.", err, ex, curmod)
++            failed = true
++            continue
++        end
++        # Undefined `Bindings` get discarded.
++        if !Documenter.DocSystem.iskeyword(binding) && !Documenter.DocSystem.defined(binding)
++            push!(doc.internal.errors, :docs_block)
++            Utilities.warn(page.source, "Undefined binding '$(binding)'.")
++            failed = true
++            continue
++        end
++        typesig = Core.eval(curmod, Documenter.DocSystem.signature(ex, str))
++
++        object = Utilities.Object(binding, typesig)
++        # We can't include the same object more than once in a document.
++        if haskey(doc.internal.objects, object)
++            push!(doc.internal.errors, :docs_block)
++            Utilities.warn(page.source, "Duplicate docs found for '$(strip(str))'.")
++            failed = true
++            continue
++        end
++
++        # Find the docs matching `binding` and `typesig`. Only search within the provided modules.
++        docs = Documenter.DocSystem.getdocs(binding, typesig; modules = doc.user.modules)
++
++        # Include only docstrings from user-provided modules if provided.
++        if !isempty(doc.user.modules)
++            filter!(d -> d.data[:module] in doc.user.modules, docs)
++        end
++
++        # Check that we aren't printing an empty docs list. Skip block when empty.
++        if isempty(docs)
++            push!(doc.internal.errors, :docs_block)
++            Utilities.warn(page.source, "No docs found for '$(strip(str))'.")
++            failed = true
++            continue
++        end
++
++        # Concatenate found docstrings into a single `MD` object.
++        docstr = Markdown.MD(map(Documenter.DocSystem.parsedoc, docs))
++        docstr.meta[:results] = docs
++
++        # Generate a unique name to be used in anchors and links for the docstring.
++        slug = Utilities.slugify(object)
++        anchor = Anchors.add!(doc.internal.docs, object, slug, page.build)
++        docsnode = DocsNode(docstr, anchor, object, page)
++
++        # Track the order of insertion of objects per-binding.
++        push!(get!(doc.internal.bindings, binding, Utilities.Object[]), object)
++
++        doc.internal.objects[object] = docsnode
++        push!(nodes, docsnode)
++    end
++    # When a `@docs` block fails we need to remove the `.language` since some markdown
++    # parsers have trouble rendering it correctly.
++    page.mapping[x] = failed ? (x.language = ""; x) : DocsNodes(nodes)
++end
++
++# @autodocs
++# ---------
++
++const AUTODOCS_DEFAULT_ORDER = [:module, :constant, :type, :function, :macro]
++
++function Selectors.runner(::Type{AutoDocsBlocks}, x, page, doc)
++    curmod = get(page.globals.meta, :CurrentModule, Main)
++    fields = Dict{Symbol, Any}()
++    for (ex, str) in Utilities.parseblock(x.code, doc, page)
++        if Utilities.isassign(ex)
++            try
++                fields[ex.args[1]] = Core.eval(curmod, ex.args[2])
++            catch err
++                push!(doc.internal.errors, :autodocs_block)
++                Utilities.warn(doc, page, "Failed to evaluate `$(strip(str))` in `@autodocs` block.", err)
++            end
++        end
++    end
++    if haskey(fields, :Modules)
++        # Gather and filter docstrings.
++        modules = fields[:Modules]
++        order = get(fields, :Order, AUTODOCS_DEFAULT_ORDER)
++        pages = map(normpath, get(fields, :Pages, []))
++        public = get(fields, :Public, true)
++        private = get(fields, :Private, true)
++        results = []
++        for mod in modules
++            for (binding, multidoc) in Documenter.DocSystem.getmeta(mod)
++                # Which bindings should be included?
++                isexported = Base.isexported(mod, binding.var)
++                included = (isexported && public) || (!isexported && private)
++                # What category does the binding belong to?
++                category = Documenter.DocSystem.category(binding)
++                if category in order && included
++                    for (typesig, docstr) in multidoc.docs
++                        path = normpath(docstr.data[:path])
++                        object = Utilities.Object(binding, typesig)
++                        if isempty(pages)
++                            push!(results, (mod, path, category, object, isexported, docstr))
++                        else
++                            for p in pages
++                                if endswith(path, p)
++                                    push!(results, (mod, p, category, object, isexported, docstr))
++                                    break
++                                end
++                            end
++                        end
++                    end
++                end
++            end
++        end
++
++        # Sort docstrings.
++        modulemap = Documents.precedence(modules)
++        pagesmap = Documents.precedence(pages)
++        ordermap = Documents.precedence(order)
++        comparison = function (a, b)
++            local t
++            (t = Documents._compare(modulemap, 1, a, b)) == 0 || return t < 0 # module
++            a[5] == b[5] || return a[5] > b[5] # exported bindings before unexported ones.
++            (t = Documents._compare(pagesmap,  2, a, b)) == 0 || return t < 0 # page
++            (t = Documents._compare(ordermap,  3, a, b)) == 0 || return t < 0 # category
++            string(a[4]) < string(b[4])                                       # name
++        end
++        sort!(results; lt = comparison)
++
++        # Finalise docstrings.
++        nodes = DocsNode[]
++        for (mod, path, category, object, isexported, docstr) in results
++            if haskey(doc.internal.objects, object)
++                push!(doc.internal.errors, :autodocs_block)
++                Utilities.warn(page.source, "Duplicate docs found for '$(object.binding)'.")
++                continue
++            end
++            markdown = Markdown.MD(Documenter.DocSystem.parsedoc(docstr))
++            markdown.meta[:results] = [docstr]
++            slug = Utilities.slugify(object)
++            anchor = Anchors.add!(doc.internal.docs, object, slug, page.build)
++            docsnode = DocsNode(markdown, anchor, object, page)
++
++            # Track the order of insertion of objects per-binding.
++            push!(get!(doc.internal.bindings, object.binding, Utilities.Object[]), object)
++
++            doc.internal.objects[object] = docsnode
++            push!(nodes, docsnode)
++        end
++        page.mapping[x] = DocsNodes(nodes)
++    else
++        push!(doc.internal.errors, :autodocs_block)
++        Utilities.warn(page.source, "'@autodocs' missing 'Modules = ...'.")
++        page.mapping[x] = x
++    end
++end
++
++# @eval
++# -----
++
++function Selectors.runner(::Type{EvalBlocks}, x, page, doc)
++    sandbox = Module(:EvalBlockSandbox)
++    cd(dirname(page.build)) do
++        result = nothing
++        for (ex, str) in Utilities.parseblock(x.code, doc, page)
++            try
++                result = Core.eval(sandbox, ex)
++            catch err
++                push!(doc.internal.errors, :eval_block)
++                Utilities.warn(doc, page, "Failed to evaluate `@eval` block.", err)
++            end
++        end
++        page.mapping[x] = EvalNode(x, result)
++    end
++end
++
++# @index
++# ------
++
++function Selectors.runner(::Type{IndexBlocks}, x, page, doc)
++    node = Documents.buildnode(Documents.IndexNode, x, doc, page)
++    push!(doc.internal.indexnodes, node)
++    page.mapping[x] = node
++end
++
++# @contents
++# ---------
++
++function Selectors.runner(::Type{ContentsBlocks}, x, page, doc)
++    node = Documents.buildnode(Documents.ContentsNode, x, doc, page)
++    push!(doc.internal.contentsnodes, node)
++    page.mapping[x] = node
++end
++
++# @example
++# --------
++
++function Selectors.runner(::Type{ExampleBlocks}, x, page, doc)
++    # The sandboxed module -- either a new one or a cached one from this page.
++    name = match(r"^@example[ ]?(.*)$", first(split(x.language, ';', limit = 2)))[1]
++    sym  = isempty(name) ? gensym("ex-") : Symbol("ex-", name)
++    mod  = get!(() -> get_new_sandbox(sym), page.globals.meta, sym)
++
++    # "parse" keyword arguments to example (we only need to look for continued = true)
++    continued = occursin(r"continued\s*=\s*true", x.language)
++
++    # Evaluate the code block. We redirect stdout/stderr to `buffer`.
++    result, buffer = nothing, IOBuffer()
++    if !continued # run the code
++        # check if there is any code wating
++        if haskey(page.globals.meta, :ContinuedCode) && haskey(page.globals.meta[:ContinuedCode], sym)
++            code = page.globals.meta[:ContinuedCode][sym] * '\n' * x.code
++            delete!(page.globals.meta[:ContinuedCode], sym)
++        else
++            code = x.code
++        end
++        for (ex, str) in Utilities.parseblock(code, doc, page)
++            (value, success, backtrace, text) = Utilities.withoutput() do
++                cd(dirname(page.build)) do
++                    Core.eval(mod, Expr(:(=), :ans, ex))
++                end
++            end
++            result = value
++            print(buffer, text)
++            if !success
++                push!(doc.internal.errors, :example_block)
++                Utilities.warn(page.source, "failed to run code block.\n\n$(value)")
++                page.mapping[x] = x
++                return
++            end
++        end
++    else # store the continued code
++        CC = get!(page.globals.meta, :ContinuedCode, Dict())
++        CC[sym] = get(CC, sym, "") * '\n' * x.code
++    end
++    # Splice the input and output into the document.
++    content = []
++    input   = droplines(x.code)
++
++    # Special-case support for displaying SVG and PNG graphics. TODO: make this more general.
++    output = if showable(MIME"text/html"(), result)
++        Documents.RawHTML(Base.invokelatest(stringmime, MIME"text/html"(), result))
++    elseif showable(MIME"image/svg+xml"(), result)
++        Documents.RawHTML(Base.invokelatest(stringmime, MIME"image/svg+xml"(), result))
++    elseif showable(MIME"image/png"(), result)
++        Documents.RawHTML(string("<img src=\"data:image/png;base64,", Base.invokelatest(stringmime, MIME"image/png"(), result), "\" />"))
++    elseif showable(MIME"image/webp"(), result)
++        Documents.RawHTML(string("<img src=\"data:image/webp;base64,", Base.invokelatest(stringmime, MIME"image/webp"(), result), "\" />"))
++    elseif showable(MIME"image/gif"(), result)
++        Documents.RawHTML(string("<img src=\"data:image/gif;base64,", Base.invokelatest(stringmime, MIME"image/gif"(), result), "\" />"))
++    elseif showable(MIME"image/jpeg"(), result)
++        Documents.RawHTML(string("<img src=\"data:image/jpeg;base64,", Base.invokelatest(stringmime, MIME"image/jpeg"(), result), "\" />"))
++    else
++        Markdown.Code(Documenter.DocTests.result_to_string(buffer, result))
++    end
++
++    # Only add content when there's actually something to add.
++    isempty(input)  || push!(content, Markdown.Code("julia", input))
++    isempty(output.code) || push!(content, output)
++    # ... and finally map the original code block to the newly generated ones.
++    page.mapping[x] = Markdown.MD(content)
++end
++
++# @repl
++# -----
++
++function Selectors.runner(::Type{REPLBlocks}, x, page, doc)
++    matched = match(r"^@repl[ ]?(.*)$", x.language)
++    matched === nothing && error("invalid '@repl' syntax: $(x.language)")
++    name = matched[1]
++    sym  = isempty(name) ? gensym("ex-") : Symbol("ex-", name)
++    mod  = get!(() -> get_new_sandbox(sym), page.globals.meta, sym)
++    code = split(x.code, '\n'; limit = 2)[end]
++    result, out = nothing, IOBuffer()
++    for (ex, str) in Utilities.parseblock(x.code, doc, page)
++        buffer = IOBuffer()
++        input  = droplines(str)
++        (value, success, backtrace, text) = Utilities.withoutput() do
++            cd(dirname(page.build)) do
++                Core.eval(mod, :(ans = $(Core.eval(mod, ex))))
++            end
++        end
++        result = value
++        output = if success
++            hide = REPL.ends_with_semicolon(input)
++            Documenter.DocTests.result_to_string(buffer, hide ? nothing : value)
++        else
++            Documenter.DocTests.error_to_string(buffer, value, [])
++        end
++        isempty(input) || println(out, prepend_prompt(input))
++        print(out, text)
++        if isempty(input) || isempty(output)
++            println(out)
++        else
++            println(out, output, "\n")
++        end
++    end
++    page.mapping[x] = Markdown.Code("julia-repl", rstrip(String(take!(out))))
++end
++
++# @setup
++# ------
++
++function Selectors.runner(::Type{SetupBlocks}, x, page, doc)
++    matched = match(r"^@setup[ ](.+)$", x.language)
++    matched === nothing && error("invalid '@setup <name>' syntax: $(x.language)")
++    # The sandboxed module -- either a new one or a cached one from this page.
++    name = matched[1]
++    sym  = isempty(name) ? gensym("ex-") : Symbol("ex-", name)
++    mod  = get!(page.globals.meta, sym, Module(sym))::Module
++
++    # Evaluate whole @setup block at once instead of piecewise
++    page.mapping[x] =
++    try
++        cd(dirname(page.build)) do
++            include_string(mod, x.code)
++        end
++        Markdown.MD([])
++    catch err
++        push!(doc.internal.errors, :setup_block)
++        Utilities.warn(page.source, "failed to run `@setup` block.\n\n$(err)")
++        x
++    end
++    # ... and finally map the original code block to the newly generated ones.
++    page.mapping[x] = Markdown.MD([])
++end
++
++# @raw
++# ----
++
++function Selectors.runner(::Type{RawBlocks}, x, page, doc)
++    m = match(r"@raw[ ](.+)$", x.language)
++    m === nothing && error("invalid '@raw <name>' syntax: $(x.language)")
++    page.mapping[x] = Documents.RawNode(Symbol(m[1]), x.code)
++end
++
++# Utilities.
++# ----------
++
++iscode(x::Markdown.Code, r::Regex) = occursin(r, x.language)
++iscode(x::Markdown.Code, lang)     = x.language == lang
++iscode(x, lang)                    = false
++
++const NAMEDHEADER_REGEX = r"^@id (.+)$"
++
++function namedheader(h::Markdown.Header)
++    if isa(h.text, Vector) && length(h.text) === 1 && isa(h.text[1], Markdown.Link)
++        url = h.text[1].url
++        occursin(NAMEDHEADER_REGEX, url)
++    else
++        false
++    end
++end
++
++# Remove any `# hide` lines, leading/trailing blank lines, and trailing whitespace.
++function droplines(code; skip = 0)
++    buffer = IOBuffer()
++    for line in split(code, '\n')[(skip + 1):end]
++        occursin(r"^(.*)#\s*hide$", line) && continue
++        println(buffer, rstrip(line))
++    end
++    strip(String(take!(buffer)), '\n')
++end
++
++function prepend_prompt(input)
++    prompt  = "julia> "
++    padding = " "^length(prompt)
++    out = IOBuffer()
++    for (n, line) in enumerate(split(input, '\n'))
++        line = rstrip(line)
++        println(out, n == 1 ? prompt : padding, line)
++    end
++    rstrip(String(take!(out)))
++end
++
++function get_new_sandbox(name::Symbol)
++    m = Module(name)
++    # eval(expr) is available in the REPL (i.e. Main) so we emulate that for the sandbox
++    Core.eval(m, :(eval(x) = Core.eval($m, x)))
++    # modules created with Module() does not have include defined
++    Core.eval(m, :(include(x) = Base.include($m, x)))
++    return m
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2de63fd90c0e7ee938d15ef42eee5caf7ef408db
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++"""
++Filetypes used to decide which rendering methods in [`Documenter.Writers`](@ref) are called.
++
++The only supported format is currently `Markdown`.
++"""
++module Formats
++
++import ..Documenter
++
++using DocStringExtensions
++
++"""
++Represents the output format. Possible values are `Markdown`, `LaTeX`, and `HTML`.
++"""
++@enum(
++    Format,
++    Markdown,
++    LaTeX,
++    HTML,
++)
++
++"""
++$(SIGNATURES)
++
++Converts a [`Format`](@ref) value to a `MIME` type.
++"""
++function mimetype(f::Symbol)
++    f ≡ :markdown ? MIME"text/plain"() :
++    f ≡ :latex    ? MIME"text/latex"() :
++    f ≡ :html     ? MIME"text/html"()  :
++        error("unexpected format.")
++end
++
++function extension(f::Symbol, file)
++    path, _ = splitext(file)
++    string(path, extension(f))
++end
++
++function extension(f::Symbol)
++    f ≡ :markdown ? ".md"   :
++    f ≡ :latex    ? ".tex"  :
++    f ≡ :html     ? ".html" :
++        error("unexpected format.")
++end
++
++# `fmt` -- convert a format spec to a vector of symbols.
++const DEPRECATION_MAPPING = Dict(
++    Markdown => :markdown,
++    LaTeX    => :latex,
++    HTML     => :html,
++)
++function _fmt(f::Format)
++    s = DEPRECATION_MAPPING[f]
++    Base.depwarn("`$(f)` is deprecated use `:$(s)` for `format = ...`.", :fmt)
++    return s
++end
++fmt(f::Format) = [_fmt(f)]
++fmt(v::Vector{Format}) = map(_fmt, v)
++fmt(s::Symbol) = [s]
++fmt(v::Vector{Symbol}) = v
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d26cfd10cf161f5cc76141709794f2db6e5ed677
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,315 @@@
++"""
++Provides a domain specific language for representing HTML documents.
++
++# Examples
++
++```julia
++using Documenter.Utilities.DOM
++
++# `DOM` does not export any HTML tags. Define the ones we actually need.
++@tags div p em strong ul li
++
++div(
++    p("This ", em("is"), " a ", strong("paragraph."),
++    p("And this is ", strong("another"), " one"),
++    ul(
++        li("and"),
++        li("an"),
++        li("unordered"),
++        li("list")
++    )
++)
++```
++
++*Notes*
++
++All the arguments passed to a node are flattened into a single vector rather
++than preserving any nested structure. This means that passing two vectors of
++nodes to a `div` will result in a `div` node with a single vector of children
++(the concatenation of the two vectors) rather than two vector children. The
++only arguments that are not flattened are nested nodes.
++
++String arguments are automatically converted into text nodes. Text nodes do not
++have any children or attributes and when displayed the string is escaped using
++[`escapehtml`](@ref).
++
++# Attributes
++
++As well as plain nodes shown in the previous example, nodes can have attributes
++added to them using the following syntax.
++
++```julia
++div[".my-class"](
++    img[:src => "foo.jpg"],
++    input[\"#my-id\", :disabled]
++)
++```
++
++In the above example we add a `class = "my-class"` attribute to the `div` node,
++a `src = "foo.jpg"` to the `img`, and `id = "my-id" disabled` attributes to the
++`input` node.
++
++The following syntax is supported within `[...]`:
++
++```julia
++tag[\"#id\"]
++tag[".class"]
++tag[\".class#id\"]
++tag[:disabled]
++tag[:src => "foo.jpg"]
++# ... or any combination of the above arguments.
++```
++
++# Internal Representation
++
++The [`@tags`](@ref) macro defines named [`Tag`](@ref) objects as follows
++
++```julia
++@tags div p em strong
++```
++
++expands to
++
++```julia
++const div, p, em, strong = Tag(:div), Tag(:p), Tag(:em), Tag(:strong)
++```
++
++These [`Tag`](@ref) objects are lightweight representations of empty HTML
++elements without any attributes and cannot be used to represent a complete
++document. To create an actual tree of HTML elements that can be rendered we
++need to add some attributes and/or child elements using `getindex` or `call`
++syntax. Applying either to a [`Tag`](@ref) object will construct a new
++[`Node`](@ref) object.
++
++```julia
++tag(...)      # No attributes.
++tag[...]      # No children.
++tag[...](...) # Has both attributes and children.
++```
++
++All three of the above syntaxes return a new [`Node`](@ref) object. Printing of
++`Node` objects is defined using the standard Julia display functions, so only
++needs a call to `print` to print out a valid HTML document with all nessesary
++text escaped.
++"""
++module DOM
++
++import ..Utilities
++
++tostr(p::Pair) = p
++
++export @tags
++
++#
++# The following sets are based on:
++#
++# - https://developer.mozilla.org/en/docs/Web/HTML/Block-level_elements
++# - https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
++# - https://developer.mozilla.org/en-US/docs/Glossary/empty_element
++#
++const BLOCK_ELEMENTS = Set([
++    :address, :article, :aside, :blockquote, :canvas, :dd, :div, :dl,
++    :fieldset, :figcaption, :figure, :footer, :form, :h1, :h2, :h3, :h4, :h5,
++    :h6, :header, :hgroup, :hr, :li, :main, :nav, :noscript, :ol, :output, :p,
++    :pre, :section, :table, :tfoot, :ul, :video,
++])
++const INLINE_ELEMENTS = Set([
++    :a, :abbr, :acronym, :b, :bdo, :big, :br, :button, :cite, :code, :dfn, :em,
++    :i, :img, :input, :kbd, :label, :map, :object, :q, :samp, :script, :select,
++    :small, :span, :strong, :sub, :sup, :textarea, :time, :tt, :var,
++])
++const VOID_ELEMENTS = Set([
++    :area, :base, :br, :col, :command, :embed, :hr, :img, :input, :keygen,
++    :link, :meta, :param, :source, :track, :wbr,
++])
++const ALL_ELEMENTS = union(BLOCK_ELEMENTS, INLINE_ELEMENTS, VOID_ELEMENTS)
++
++#
++# Empty string as a constant to make equality checks slightly cheaper.
++#
++const EMPTY_STRING = ""
++const TEXT = Symbol(EMPTY_STRING)
++
++"""
++Represents a empty and attribute-less HTML element.
++
++Use [`@tags`](@ref) to define instances of this type rather than manually
++creating them via `Tag(:tagname)`.
++"""
++struct Tag
++    name :: Symbol
++end
++
++Base.show(io::IO, t::Tag) = print(io, "<", t.name, ">")
++
++"""
++Define a collection of [`Tag`](@ref) objects and bind them to constants
++with the same names.
++
++# Examples
++
++Defined globally within a module:
++
++```julia
++@tags div ul li
++```
++
++Defined within the scope of a function to avoid cluttering the global namespace:
++
++```julia
++function template(args...)
++    @tags div ul li
++    # ...
++end
++```
++"""
++macro tags(args...) esc(tags(args)) end
++tags(s) = :(($(s...),) = $(map(Tag, s)))
++
++const Attributes = Vector{Pair{Symbol, String}}
++
++"""
++Represents an element within an HTML document including any textual content,
++children `Node`s, and attributes.
++
++This type should not be constructed directly, but instead via `(...)` and
++`[...]` applied to a [`Tag`](@ref) or another [`Node`](@ref) object.
++"""
++struct Node
++    name :: Symbol
++    text :: String
++    attributes :: Attributes
++    nodes :: Vector{Node}
++
++    Node(name::Symbol, attr::Attributes, data::Vector{Node}) = new(name, EMPTY_STRING, attr, data)
++    Node(text::AbstractString) = new(TEXT, text)
++end
++
++#
++# Syntax for defining `Node` objects from `Tag`s and other `Node` objects.
++#
++(t::Tag)(args...) = Node(t.name, Attributes(), data(args))
++(n::Node)(args...) = Node(n.name, n.attributes, data(args))
++Base.getindex(t::Tag, args...) = Node(t.name, attr(args), Node[])
++Base.getindex(n::Node, args...) = Node(n.name, attr(args), n.nodes)
++
++#
++# Helper methods for the above `Node` "pseudo-constructors".
++#
++data(args) = flatten!(nodes!, Node[], args)
++attr(args) = flatten!(attributes!, Attributes(), args)
++
++#
++# Types that must not be flattened when constructing a `Node`'s child vector.
++#
++const Atom = Union{AbstractString, Node, Pair, Symbol}
++
++"""
++# Signatures
++
++```julia
++flatten!(f!, out, x::Atom)
++flatten!(f!, out, xs)
++```
++
++Flatten the contents the third argument into the second after applying the
++function `f!` to the element.
++"""
++flatten!(f!, out, x::Atom) = f!(out, x)
++flatten!(f!, out, xs)      = (for x in xs; flatten!(f!, out, x); end; out)
++
++#
++# Helper methods for handling flattening children elements in `Node` construction.
++#
++nodes!(out, s::AbstractString) = push!(out, Node(s))
++nodes!(out, n::Node)           = push!(out, n)
++
++#
++# Helper methods for handling flattening in construction of attribute vectors.
++#
++function attributes!(out, s::AbstractString)
++    class, id = IOBuffer(), IOBuffer()
++    for x in eachmatch(r"[#|\.]([\w\-]+)", s)
++        print(startswith(x.match, '.') ? class : id, x.captures[1], ' ')
++    end
++    position(class) === 0 || push!(out, tostr(:class => rstrip(String(take!(class)))))
++    position(id)    === 0 || push!(out, tostr(:id    => rstrip(String(take!(id)))))
++    return out
++end
++attributes!(out, s::Symbol) = push!(out, tostr(s => ""))
++attributes!(out, p::Pair)   = push!(out, tostr(p))
++
++function Base.show(io::IO, n::Node)
++    if n.name === Symbol("#RAW#")
++        print(io, n.nodes[1].text)
++    elseif n.name === TEXT
++        print(io, escapehtml(n.text))
++    else
++        print(io, '<', n.name)
++        for (name, value) in n.attributes
++            print(io, ' ', name)
++            isempty(value) || print(io, '=', repr(escapehtml(value)))
++        end
++        if n.name in VOID_ELEMENTS
++            print(io, "/>")
++        else
++            print(io, '>')
++            if n.name === :script || n.name === :style
++                isempty(n.nodes) || print(io, n.nodes[1].text)
++            else
++                for each in n.nodes
++                    show(io, each)
++                end
++            end
++            print(io, "</", n.name, '>')
++        end
++    end
++end
++
++Base.show(io::IO, ::MIME"text/html", n::Node) = print(io, n)
++
++"""
++Escape characters in the provided string. This converts the following characters:
++
++- `<` to `&lt;`
++- `>` to `&gt;`
++- `&` to `&amp;`
++- `'` to `&#39;`
++- `\"` to `&quot;`
++
++When no escaping is needed then the same object is returned, otherwise a new
++string is constructed with the characters escaped. The returned object should
++always be treated as an immutable copy and compared using `==` rather than `===`.
++"""
++function escapehtml(text::AbstractString)
++    if occursin(r"[<>&'\"]", text)
++        buffer = IOBuffer()
++        for char in text
++            char === '<'  ? write(buffer, "&lt;")   :
++            char === '>'  ? write(buffer, "&gt;")   :
++            char === '&'  ? write(buffer, "&amp;")  :
++            char === '\'' ? write(buffer, "&#39;")  :
++            char === '"'  ? write(buffer, "&quot;") : write(buffer, char)
++        end
++        String(take!(buffer))
++    else
++        text
++    end
++end
++
++"""
++A HTML node that wraps around the root node of the document and adds a DOCTYPE
++to it.
++"""
++mutable struct HTMLDocument
++    doctype :: String
++    root    :: Node
++end
++HTMLDocument(root) = HTMLDocument("html", root)
++
++function Base.show(io::IO, doc::HTMLDocument)
++    println(io, "<!DOCTYPE $(doc.doctype)>")
++    println(io, doc.root)
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..33cfb13de682ce5103a162d8546bb8e442a20bff
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,94 @@@
++"""
++Provides the [`mdflatten`](@ref) function that can "flatten" Markdown objects into
++a string, with formatting etc. stripped.
++
++Note that the tests in `test/mdflatten.jl` should be considered to be the spec
++for the output (number of newlines, indents, formatting, etc.).
++"""
++module MDFlatten
++
++export mdflatten
++
++import ..Utilities
++
++import Markdown:
++    MD, BlockQuote, Bold, Code, Header, HorizontalRule,
++    Image, Italic, LaTeX, LineBreak, Link, List, Paragraph, Table,
++    Footnote, Admonition
++
++"""
++Convert a Markdown object to a `String` of only text (i.e. not formatting info).
++
++It drop most of the extra information (e.g. language of a code block, URLs)
++and formatting (e.g. emphasis, headers). This "flattened" representation can
++then be used as input for search engines.
++"""
++function mdflatten(md)
++    io = IOBuffer()
++    mdflatten(io, md)
++    String(take!(io))
++end
++
++mdflatten(io, md) = mdflatten(io, md, md)
++mdflatten(io, md::MD, parent) = mdflatten(io, md.content, md)
++mdflatten(io, vec::Vector, parent) = map(x -> mdflatten(io, x, parent), vec)
++function mdflatten(io, vec::Vector, parent::MD)
++    # this special case separates top level blocks with newlines
++    for md in vec
++        mdflatten(io, md, parent)
++        print(io, "\n\n")
++    end
++end
++
++# Block level MD nodes
++mdflatten(io, h::Header{N}, parent) where {N} = mdflatten(io, h.text, h)
++mdflatten(io, p::Paragraph, parent) = mdflatten(io, p.content, p)
++mdflatten(io, bq::BlockQuote, parent) = mdflatten(io, bq.content, bq)
++mdflatten(io, ::HorizontalRule, parent) = nothing
++function mdflatten(io, list::List, parent)
++    for (idx, li) in enumerate(list.items)
++        for (jdx, x) in enumerate(li)
++            mdflatten(io, x, list)
++            jdx == length(li) || print(io, '\n')
++        end
++        idx == length(list.items) || print(io, '\n')
++    end
++end
++function mdflatten(io, t::Table, parent)
++    for (idx, row) = enumerate(t.rows)
++        for (jdx, x) in enumerate(row)
++            mdflatten(io, x, t)
++            jdx == length(row) || print(io, ' ')
++        end
++        idx == length(t.rows) || print(io, '\n')
++    end
++end
++
++# Inline nodes
++mdflatten(io, text::AbstractString, parent) = print(io, text)
++mdflatten(io, link::Link, parent) = mdflatten(io, link.text, link)
++mdflatten(io, b::Bold, parent) = mdflatten(io, b.text, b)
++mdflatten(io, i::Italic, parent) = mdflatten(io, i.text, i)
++mdflatten(io, i::Image, parent) = print(io, "(Image: $(i.alt))")
++mdflatten(io, m::LaTeX, parent) = print(io, replace(m.formula, r"[^()+\-*^=\w\s]" => ""))
++mdflatten(io, ::LineBreak, parent) = print(io, '\n')
++
++# Is both inline and block
++mdflatten(io, c::Code, parent) = print(io, c.code)
++
++# Special (inline) "node" -- due to JuliaMark's interpolations
++mdflatten(io, expr::Union{Symbol,Expr}, parent) = print(io, expr)
++
++mdflatten(io, f::Footnote, parent) = footnote(io, f.id, f.text, f)
++footnote(io, id, text::Nothing, parent) = print(io, "[$id]")
++function footnote(io, id, text, parent)
++    print(io, "[$id]: ")
++    mdflatten(io, text, parent)
++end
++
++function mdflatten(io, a::Admonition, parent)
++    println(io, "$(a.category): $(a.title)")
++    mdflatten(io, a.content, a)
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ac79bf056268773b57c7a14a35fea7a94174d21
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,174 @@@
++"""
++An extensible code selection interface.
++
++The `Selectors` module provides an extensible way to write code that has to dispatch on
++different predicates without hardcoding the control flow into a single chain of `if`
++statements.
++
++In the following example a selector for a simple condition is implemented and the generated
++selector code is described:
++
++```julia
++abstract type MySelector <: Selectors.AbstractSelector end
++
++# The different cases we want to test.
++abstract type One    <: MySelector end
++abstract type NotOne <: MySelector end
++
++# The order in which to test the cases.
++Selectors.order(::Type{One})    = 0.0
++Selectors.order(::Type{NotOne}) = 1.0
++
++# The predicate to test against.
++Selectors.matcher(::Type{One}, x)    = x === 1
++Selectors.matcher(::Type{NotOne}, x) = x !== 1
++
++# What to do when a test is successful.
++Selectors.runner(::Type{One}, x)    = println("found one")
++Selectors.runner(::Type{NotOne}, x) = println("not found")
++
++# Test our selector with some numbers.
++for i in 0:5
++    Selectors.dispatch(MySelector, i)
++end
++```
++
++`Selectors.dispatch(Selector, i)` will behave equivalent to the following:
++
++```julia
++function dispatch(::Type{MySelector}, i::Int)
++    if matcher(One, i)
++        runner(One, i)
++    elseif matcher(NotOne, i)
++        runner(NotOne, i)
++    end
++end
++```
++
++and further to
++
++```julia
++function dispatch(::Type{MySelector}, i::Int)
++    if i === 1
++        println("found one")
++    elseif i !== 1
++        println("not found")
++    end
++end
++```
++
++The module provides the following interface for creating selectors:
++
++- [`order`](@ref)
++- [`matcher`](@ref)
++- [`runner`](@ref)
++- [`strict`](@ref)
++- [`disable`](@ref)
++- [`dispatch`](@ref)
++
++"""
++module Selectors
++
++import InteractiveUtils: subtypes
++
++"""
++Root selector type. Each user-defined selector must subtype from this, i.e.
++
++```julia
++abstract type MySelector <: Selectors.AbstractSelector end
++
++abstract type First  <: MySelector end
++abstract type Second <: MySelector end
++```
++"""
++abstract type AbstractSelector end
++
++"""
++Define the precedence of each case in a selector, i.e.
++
++```julia
++Selectors.order(::Type{First})  = 1.0
++Selectors.order(::Type{Second}) = 2.0
++```
++
++Note that the return type must be `Float64`. Defining multiple case types to have the same
++order will result in undefined behaviour.
++"""
++function order end
++
++"""
++Define the matching test for each case in a selector, i.e.
++
++```julia
++Selectors.matcher(::Type{First}, x)  = x == 1
++Selectors.matcher(::Type{Second}, x) = true
++```
++
++Note that the return type must be `Bool`.
++
++To match against multiple cases use the [`Selectors.strict`](@ref) function.
++"""
++function matcher end
++
++"""
++Define the code that will run when a particular [`Selectors.matcher`](@ref) test returns
++`true`, i.e.
++
++```julia
++Selectors.runner(::Type{First}, x)  = println("`x` is equal to `1`.")
++Selectors.runner(::Type{Second}, x) = println("`x` is not equal to `1`.")
++```
++"""
++function runner end
++
++"""
++Define whether a selector case will "fallthrough" or not when successfully matched against.
++By default matching is strict and does not fallthrough to subsequent selector cases.
++
++```julia
++# Adding a debugging selector case.
++abstract type Debug <: MySelector end
++
++# Insert prior to all other cases.
++Selectors.order(::Type{Debug}) = 0.0
++
++# Fallthrough to the next case on success.
++Selectors.strict(::Type{Debug}) = false
++
++# We always match, regardless of the value of `x`.
++Selectors.matcher(::Type{Debug}, x) = true
++
++# Print some debugging info.
++Selectors.runner(::Type{Debug}, x) = @show x
++```
++"""
++strict(::Type{T}) where {T <: AbstractSelector} = true
++
++"""
++Disable a particular case in a selector so that it is never used.
++
++```julia
++Selectors.disable(::Type{Debug}) = true
++```
++"""
++disable(::Type{T}) where {T <: AbstractSelector} = false
++
++"""
++Call `Selectors.runner(T, args...)` where `T` is a subtype of
++`MySelector` for which `matcher(T, args...)` is `true`.
++
++```julia
++Selectors.dispatch(MySelector, args...)
++```
++"""
++function dispatch(::Type{T}, x...) where T <: AbstractSelector
++    for t in (sort(subtypes(T); by = order))
++        if !disable(t) && matcher(t, x...)
++            runner(t, x...)
++            strict(t) && return
++        end
++    end
++    runner(T, x...)
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..125d4db760e16eff7d1ad9f3e0e559754b6a5851
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,101 @@@
++module TextDiff
++
++using DocStringExtensions
++
++# Utilities.
++
++function lcs(old_tokens::Vector, new_tokens::Vector)
++    m = length(old_tokens)
++    n = length(new_tokens)
++    weights = zeros(Int, m + 1, n + 1)
++    for i = 2:(m + 1), j = 2:(n + 1)
++        weights[i, j] = old_tokens[i - 1] == new_tokens[j - 1] ?
++            weights[i - 1, j - 1] + 1 : max(weights[i, j - 1], weights[i - 1, j])
++    end
++    return weights
++end
++
++function makediff(weights::Matrix, old_tokens::Vector, new_tokens::Vector)
++    m = length(old_tokens)
++    n = length(new_tokens)
++    diff = Vector{Pair{Symbol, SubString{String}}}()
++    makediff!(diff, weights, old_tokens, new_tokens, m + 1, n + 1)
++    return diff
++end
++
++function makediff!(out, weights, X, Y, i, j)
++    if i > 1 && j > 1 && X[i - 1] == Y[j - 1]
++        makediff!(out, weights, X, Y, i - 1, j - 1)
++        push!(out, :normal => X[i - 1])
++    else
++        if j > 1 && (i == 1 || weights[i, j - 1] >= weights[i - 1, j])
++            makediff!(out, weights, X, Y, i, j - 1)
++            push!(out, :green => Y[j - 1])
++        elseif i > 1 && (j == 1 || weights[i, j - 1] < weights[i - 1, j])
++            makediff!(out, weights, X, Y, i - 1, j)
++            push!(out, :red => X[i - 1])
++        end
++    end
++    return out
++end
++
++"""
++$(SIGNATURES)
++
++Splits `text` at `regex` matches, returning an array of substrings. The parts of the string
++that match the regular expression are also included at the ends of the returned strings.
++"""
++function splitby(reg::Regex, text::AbstractString)
++    out = SubString{String}[]
++    token_first = 1
++    for each in eachmatch(reg, text)
++        token_last = each.offset + lastindex(each.match) - 1
++        push!(out, SubString(text, token_first, token_last))
++        token_first = nextind(text, token_last)
++    end
++    laststr = SubString(text, token_first)
++    isempty(laststr) || push!(out, laststr)
++    return out
++end
++
++# Diff Type.
++
++struct Lines end
++struct Words end
++
++splitter(::Type{Lines}) = r"\n"
++splitter(::Type{Words}) = r"\s+"
++
++struct Diff{T}
++    old_tokens::Vector{SubString{String}}
++    new_tokens::Vector{SubString{String}}
++    weights::Matrix{Int}
++    diff::Vector{Pair{Symbol, SubString{String}}}
++
++    function Diff{T}(old_text::AbstractString, new_text::AbstractString) where T
++        reg = splitter(T)
++        old_tokens = splitby(reg, old_text)
++        new_tokens = splitby(reg, new_text)
++        weights = lcs(old_tokens, new_tokens)
++        diff = makediff(weights, old_tokens, new_tokens)
++        return new{T}(old_tokens, new_tokens, weights, diff)
++    end
++end
++
++# Display.
++
++prefix(::Diff{Lines}, s::Symbol) = s === :green ? "+ " : s === :red  ? "- " : "  "
++prefix(::Diff{Words}, ::Symbol) = ""
++
++function showdiff(io::IO, diff::Diff)
++    for (color, text) in diff.diff
++        printstyled(io, prefix(diff, color), text, color=color)
++    end
++end
++
++function Base.show(io::IO, diff::Diff)
++    printstyled(io, color=:normal) # Reset colors.
++    showdiff(io, diff)
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c81bdf9befd83e5215eae22d919681abfafd674a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,633 @@@
++"""
++Provides a collection of utility functions and types that are used in other submodules.
++"""
++module Utilities
++
++using Base.Meta
++import Base: isdeprecated, Docs.Binding
++using DocStringExtensions
++import Markdown, LibGit2
++import Base64: stringmime
++
++# Logging output.
++
++const __log__ = Ref(true)
++"""
++    logging(flag::Bool)
++
++Enable or disable logging output for [`log`](@ref) and [`warn`](@ref).
++"""
++logging(flag::Bool) = __log__[] = flag
++
++"""
++Format and print a message to the user.
++"""
++log(msg) = __log__[] ? printstyled(stdout, "Documenter: ", msg, "\n", color=:magenta) : nothing
++
++# Print logging output to the "real" stdout.
++function log(doc, msg)
++    __log__[] && printstyled(stdout, "Documenter: ", msg, "\n", color=:magenta)
++    return nothing
++end
++
++debug(msg) = printstyled(" ?? ", msg, "\n", color=:green)
++
++"""
++    warn(file, msg)
++    warn(msg)
++
++Format and print a warning message to the user. Passing a `file` will include the filename
++where the warning was raised.
++"""
++function warn(file, msg)
++    if __log__[]
++        msg = string(" !! ", msg, " [", file, "]\n")
++        printstyled(stdout, msg, color=:red)
++    else
++        nothing
++    end
++end
++warn(msg) = __log__[] ? printstyled(stdout, " !! ", msg, "\n", color=:red) : nothing
++
++function warn(file, msg, err, ex, mod)
++    if __log__[]
++        warn(file, msg)
++        printstyled(stdout, "\nERROR: $err\n\nexpression '$(repr(ex))' in module '$mod'\n\n", color=:red)
++    else
++        nothing
++    end
++end
++
++function warn(doc, page, msg, err)
++    file = page.source
++    printstyled(stdout, " !! Warning in $(file):\n\n$(msg)\n\nERROR: $(err)\n\n", color=:red)
++end
++
++# Directory paths.
++
++"""
++Returns the current directory.
++"""
++function currentdir()
++    d = Base.source_dir()
++    d === nothing ? pwd() : d
++end
++
++"""
++Returns the path to the Documenter `assets` directory.
++"""
++assetsdir() = normpath(joinpath(dirname(@__FILE__), "..", "..", "assets"))
++
++cleandir(d::AbstractString) = (isdir(d) && rm(d, recursive = true); mkdir(d))
++
++"""
++Find the path of a file relative to the `source` directory. `root` is the path
++to the directory containing the file `file`.
++
++It is meant to be used with `walkdir(source)`.
++"""
++srcpath(source, root, file) = normpath(joinpath(relpath(root, source), file))
++
++# Slugify text.
++
++"""
++Slugify a string into a suitable URL.
++"""
++function slugify(s::AbstractString)
++    s = replace(s, r"\s+" => "-")
++    s = replace(s, r"^\d+" => "")
++    s = replace(s, r"&" => "-and-")
++    s = replace(s, r"[^\p{L}\p{P}\d\-]+" => "")
++    s = strip(replace(s, r"\-\-+" => "-"), '-')
++end
++slugify(object) = string(object) # Non-string slugifying doesn't do anything.
++
++# Parse code blocks.
++
++"""
++Returns a vector of parsed expressions and their corresponding raw strings.
++
++Returns a `Vector` of tuples `(expr, code)`, where `expr` is the corresponding expression
++(e.g. a `Expr` or `Symbol` object) and `code` is the string of code the expression was
++parsed from.
++
++The keyword argument `skip = N` drops the leading `N` lines from the input string.
++"""
++function parseblock(code::AbstractString, doc, page; skip = 0, keywords = true)
++    # Drop `skip` leading lines from the code block. Needed for deprecated `{docs}` syntax.
++    code = string(code, '\n')
++    code = last(split(code, '\n', limit = skip + 1))
++    endofstr = lastindex(code)
++    results = []
++    cursor = 1
++    while cursor < endofstr
++        # Check for keywords first since they will throw parse errors if we `parse` them.
++        line = match(r"^(.*)\r?\n"m, SubString(code, cursor)).match
++        keyword = Symbol(strip(line))
++        (ex, ncursor) =
++            # TODO: On 0.7 Symbol("") is in Docs.keywords, remove that check when dropping 0.6
++            if keywords && (haskey(Docs.keywords, keyword) || keyword == Symbol(""))
++                (QuoteNode(keyword), cursor + lastindex(line))
++            else
++                try
++                    Meta.parse(code, cursor)
++                catch err
++                    push!(doc.internal.errors, :parse_error)
++                    Utilities.warn(doc, page, "Failed to parse expression.", err)
++                    break
++                end
++            end
++        str = SubString(code, cursor, prevind(code, ncursor))
++        if !isempty(strip(str))
++            push!(results, (ex, str))
++        end
++        cursor = ncursor
++    end
++    results
++end
++isassign(x) = isexpr(x, :(=), 2) && isa(x.args[1], Symbol)
++
++# Checking arguments.
++
++"""
++Prints a formatted warning to the user listing unrecognised keyword arguments.
++"""
++function check_kwargs(kws)
++    isempty(kws) && return
++    out = IOBuffer()
++    println(out, "Unknown keywords:\n")
++    for (k, v) in kws
++        println(out, "  ", k, " = ", v)
++    end
++    warn(String(take!(out)))
++end
++
++# Finding submodules.
++
++const ModVec = Union{Module, Vector{Module}}
++
++"""
++Returns the set of submodules of a given root module/s.
++"""
++function submodules(modules::Vector{Module})
++    out = Set{Module}()
++    for each in modules
++        submodules(each, out)
++    end
++    out
++end
++function submodules(root::Module, seen = Set{Module}())
++    push!(seen, root)
++    for name in names(root, all=true)
++        if Base.isidentifier(name) && isdefined(root, name) && !isdeprecated(root, name)
++            object = getfield(root, name)
++            if isa(object, Module) && !(object in seen) && parentmodule(object::Module) == root
++                submodules(object, seen)
++            end
++        end
++    end
++    return seen
++end
++
++
++
++## objects
++## =======
++
++
++
++"""
++Represents an object stored in the docsystem by its binding and signature.
++"""
++struct Object
++    binding   :: Binding
++    signature :: Type
++
++    function Object(b::Binding, signature::Type)
++        m = nameof(b.mod) === b.var ? parentmodule(b.mod) : b.mod
++        new(Binding(m, b.var), signature)
++    end
++end
++
++function splitexpr(x::Expr)
++    isexpr(x, :macrocall) ? splitexpr(x.args[1]) :
++    isexpr(x, :.)         ? (x.args[1], x.args[2]) :
++    error("Invalid @var syntax `$x`.")
++end
++splitexpr(s::Symbol) = :(Main), quot(s)
++splitexpr(other)     = error("Invalid @var syntax `$other`.")
++
++"""
++    object(ex, str)
++
++Returns a expression that, when evaluated, returns an [`Object`](@ref) representing `ex`.
++"""
++function object(ex::Union{Symbol, Expr}, str::AbstractString)
++    binding   = Expr(:call, Binding, splitexpr(Docs.namify(ex))...)
++    signature = Base.Docs.signature(ex)
++    isexpr(ex, :macrocall, 2) && !endswith(str, "()") && (signature = :(Union{}))
++    Expr(:call, Object, binding, signature)
++end
++
++function object(qn::QuoteNode, str::AbstractString)
++    if haskey(Base.Docs.keywords, qn.value)
++        binding = Expr(:call, Binding, Main, qn)
++        Expr(:call, Object, binding, Union{})
++    else
++        error("'$(qn.value)' is not a documented keyword.")
++    end
++end
++
++function Base.print(io::IO, obj::Object)
++    print(io, obj.binding)
++    print_signature(io, obj.signature)
++end
++print_signature(io::IO, signature::Union{Union, Type{Union{}}}) = nothing
++print_signature(io::IO, signature)        = print(io, '-', signature)
++
++## docs
++## ====
++
++"""
++    docs(ex, str)
++
++Returns an expression that, when evaluated, returns the docstrings associated with `ex`.
++"""
++function docs end
++
++# Macro representation changed between 0.4 and 0.5.
++function docs(ex::Union{Symbol, Expr}, str::AbstractString)
++    isexpr(ex, :macrocall, 2) && !endswith(rstrip(str), "()") && (ex = quot(ex))
++    :(Base.Docs.@doc $ex)
++end
++docs(qn::QuoteNode, str::AbstractString) = :(Base.Docs.@doc $(qn.value))
++
++"""
++Returns the category name of the provided [`Object`](@ref).
++"""
++doccat(obj::Object) = startswith(string(obj.binding.var), '@') ?
++    "Macro" : doccat(obj.binding, obj.signature)
++
++function doccat(b::Binding, ::Union{Union, Type{Union{}}})
++    if b.mod === Main && haskey(Base.Docs.keywords, b.var)
++        "Keyword"
++    elseif startswith(string(b.var), '@')
++        "Macro"
++    else
++        doccat(getfield(b.mod, b.var))
++    end
++end
++
++doccat(b::Binding, ::Type)  = "Method"
++
++doccat(::Function) = "Function"
++doccat(::DataType) = "Type"
++doccat(x::UnionAll) = doccat(Base.unwrap_unionall(x))
++doccat(::Module)   = "Module"
++doccat(::Any)      = "Constant"
++
++"""
++    filterdocs(doc, modules)
++
++Remove docstrings from the markdown object, `doc`, that are not from one of `modules`.
++"""
++function filterdocs(doc::Markdown.MD, modules::Set{Module})
++    if isempty(modules)
++        # When no modules are specified in `makedocs` then don't filter anything.
++        doc
++    else
++        if haskey(doc.meta, :module)
++            doc.meta[:module] ∈ modules ? doc : nothing
++        else
++            if haskey(doc.meta, :results)
++                out = []
++                results = []
++                for (each, result) in zip(doc.content, doc.meta[:results])
++                    r = filterdocs(each, modules)
++                    if r !== nothing
++                        push!(out, r)
++                        push!(results, result)
++                    end
++                end
++                if isempty(out)
++                    nothing
++                else
++                    md = Markdown.MD(out)
++                    md.meta[:results] = results
++                    md
++                end
++            else
++                out = []
++                for each in doc.content
++                    r = filterdocs(each, modules)
++                    r === nothing || push!(out, r)
++                end
++                isempty(out) ? nothing : Markdown.MD(out)
++            end
++        end
++    end
++end
++# Non-markdown docs won't have a `.meta` field so always just accept those.
++filterdocs(other, modules::Set{Module}) = other
++
++"""
++Does the given docstring represent actual documentation or a no docs error message?
++"""
++nodocs(x) = occursin("No documentation found.", stringmime("text/plain", x))
++nodocs(::Nothing) = false
++
++header_level(::Markdown.Header{N}) where {N} = N
++
++"""
++    repo_root(file; dbdir=".git")
++
++Tries to determine the root directory of the repository containing `file`. If the file is
++not in a repository, the function returns `nothing`.
++
++The `dbdir` keyword argument specifies the name of the directory we are searching for to
++determine if this is a repostory or not. If there is a file called `dbdir`, then it's
++contents is checked under the assumption that it is a Git worktree.
++"""
++function repo_root(file; dbdir=".git")
++    parent_dir, parent_dir_last = dirname(abspath(file)), ""
++    while parent_dir != parent_dir_last
++        dbdir_path = joinpath(parent_dir, dbdir)
++        isdir(dbdir_path) && return parent_dir
++        # Let's see if this is a worktree checkout
++        if isfile(dbdir_path)
++            contents = chomp(read(dbdir_path, String))
++            if startswith(contents, "gitdir: ")
++                if isdir(contents[9:end])
++                    return parent_dir
++                end
++            end
++        end
++        parent_dir, parent_dir_last = dirname(parent_dir), parent_dir
++    end
++    return nothing
++end
++
++"""
++    $(SIGNATURES)
++
++Returns the path of `file`, relative to the root of the Git repository, or `nothing` if the
++file is not in a Git repository.
++"""
++function relpath_from_repo_root(file)
++    cd(dirname(file)) do
++        root = repo_root(file)
++        root !== nothing && startswith(file, root) ? relpath(file, root) : nothing
++    end
++end
++
++function repo_commit(file)
++    cd(dirname(file)) do
++        readchomp(`git rev-parse HEAD`)
++    end
++end
++
++function url(repo, file; commit=nothing)
++    file = realpath(abspath(file))
++    remote = getremote(dirname(file))
++    isempty(repo) && (repo = "https://github.com/$remote/blob/{commit}{path}")
++    path = relpath_from_repo_root(file)
++    if path === nothing
++        nothing
++    else
++        repo = replace(repo, "{commit}" => commit === nothing ? repo_commit(file) : commit)
++        # Note: replacing any backslashes in path (e.g. if building the docs on Windows)
++        repo = replace(repo, "{path}" => string("/", replace(path, '\\' => '/')))
++        repo = replace(repo, "{line}" => "")
++        repo
++    end
++end
++
++url(remote, repo, doc) = url(remote, repo, doc.data[:module], doc.data[:path], linerange(doc))
++
++function url(remote, repo, mod, file, linerange)
++    file === nothing && return nothing # needed on julia v0.6, see #689
++    remote = getremote(dirname(file))
++    isabspath(file) && isempty(remote) && isempty(repo) && return nothing
++
++    # make sure we get the true path, as otherwise we will get different paths when we compute `root` below
++    if isfile(file)
++        file = realpath(abspath(file))
++    end
++
++    # Format the line range.
++    line = format_line(linerange, LineRangeFormatting(repo_host_from_url(repo)))
++    # Macro-generated methods such as those produced by `@deprecate` list their file as
++    # `deprecated.jl` since that is where the macro is defined. Use that to help
++    # determine the correct URL.
++    if inbase(mod) || !isabspath(file)
++        file = replace(file, '\\' => '/')
++        base = "https://github.com/JuliaLang/julia/blob"
++        dest = "base/$file#$line"
++        if isempty(Base.GIT_VERSION_INFO.commit)
++            "$base/v$VERSION/$dest"
++        else
++            commit = Base.GIT_VERSION_INFO.commit
++            "$base/$commit/$dest"
++        end
++    else
++        path = relpath_from_repo_root(file)
++        if isempty(repo)
++            repo = "https://github.com/$remote/blob/{commit}{path}#{line}"
++        end
++        if path === nothing
++            nothing
++        else
++            repo = replace(repo, "{commit}" => repo_commit(file))
++            # Note: replacing any backslashes in path (e.g. if building the docs on Windows)
++            repo = replace(repo, "{path}" => string("/", replace(path, '\\' => '/')))
++            repo = replace(repo, "{line}" => line)
++            repo
++        end
++    end
++end
++
++function getremote(dir::AbstractString)
++    remote =
++        try
++            cd(() -> readchomp(`git config --get remote.origin.url`), dir)
++        catch err
++            ""
++        end
++    m = match(LibGit2.GITHUB_REGEX, remote)
++    if m === nothing
++        travis = get(ENV, "TRAVIS_REPO_SLUG", "")
++        isempty(travis) ? "" : travis
++    else
++        m[1]
++    end
++end
++
++"""
++$(SIGNATURES)
++
++Returns the first 5 characters of the current git commit hash of the directory `dir`.
++"""
++function get_commit_short(dir)
++    commit = cd(dir) do
++        readchomp(`git rev-parse HEAD`)
++    end
++    (length(commit) > 5) ? commit[1:5] : commit
++end
++
++function inbase(m::Module)
++    if m ≡ Base
++        true
++    else
++        parent = parentmodule(m)
++        parent ≡ m ? false : inbase(parent)
++    end
++end
++
++# Repository hosts
++#   RepoUnknown denotes that the repository type could not be determined automatically
++@enum RepoHost RepoGithub RepoBitbucket RepoGitlab RepoUnknown
++
++# Repository host from repository url
++# i.e. "https://github.com/something" => RepoGithub
++#      "https://bitbucket.org/xxx" => RepoBitbucket
++# If no match, returns RepoUnknown
++function repo_host_from_url(repoURL::String)
++    if occursin("bitbucket", repoURL)
++        return RepoBitbucket
++    elseif occursin("github", repoURL) || isempty(repoURL)
++        return RepoGithub
++    elseif occursin("gitlab", repoURL)
++        return RepoGitlab
++    else
++        return RepoUnknown
++    end
++end
++
++# Find line numbers.
++# ------------------
++
++linerange(doc) = linerange(doc.text, doc.data[:linenumber])
++
++function linerange(text, from)
++    lines = sum([isodd(n) ? newlines(s) : 0 for (n, s) in enumerate(text)])
++    return lines > 0 ? (from:(from + lines + 1)) : (from:from)
++end
++
++struct LineRangeFormatting
++    prefix::String
++    separator::String
++
++    function LineRangeFormatting(host::RepoHost)
++        if host == RepoBitbucket
++            new("", ":")
++        elseif host == RepoGitlab
++            new("L", "-")
++        else
++            # default is github-style
++            new("L", "-L")
++        end
++    end
++end
++
++function format_line(range::AbstractRange, format::LineRangeFormatting)
++    if length(range) <= 1
++        string(format.prefix, first(range))
++    else
++        string(format.prefix, first(range), format.separator, last(range))
++    end
++end
++
++newlines(s::AbstractString) = count(c -> c === '\n', s)
++newlines(other) = 0
++
++
++# Output redirection.
++# -------------------
++using Logging
++
++"""
++Call a function and capture all `stdout` and `stderr` output.
++
++    withoutput(f) --> (result, success, backtrace, output)
++
++where
++
++  * `result` is the value returned from calling function `f`.
++  * `success` signals whether `f` has thrown an error, in which case `result` stores the
++    `Exception` that was raised.
++  * `backtrace` a `Vector{Ptr{Cvoid}}` produced by `catch_backtrace()` if an error is thrown.
++  * `output` is the combined output of `stdout` and `stderr` during execution of `f`.
++
++"""
++function withoutput(f)
++    # Save the default output streams.
++    default_stdout = stdout
++    default_stderr = stderr
++
++    # Redirect both the `stdout` and `stderr` streams to a single `Pipe` object.
++    pipe = Pipe()
++    Base.link_pipe!(pipe; reader_supports_async = true, writer_supports_async = true)
++    redirect_stdout(pipe.in)
++    redirect_stderr(pipe.in)
++    # Also redirect logging stream to the same pipe
++    logger = ConsoleLogger(pipe.in)
++
++    # Bytes written to the `pipe` are captured in `output` and converted to a `String`.
++    output = UInt8[]
++
++    # Run the function `f`, capturing all output that it might have generated.
++    # Success signals whether the function `f` did or did not throw an exception.
++    result, success, backtrace = with_logger(logger) do
++        try
++            f(), true, Vector{Ptr{Cvoid}}()
++        catch err
++            # InterruptException should never happen during normal doc-testing
++            # and not being able to abort the doc-build is annoying (#687).
++            isa(err, InterruptException) && rethrow(err)
++
++            err, false, catch_backtrace()
++        finally
++            # Force at least a single write to `pipe`, otherwise `readavailable` blocks.
++            println()
++            # Restore the original output streams.
++            redirect_stdout(default_stdout)
++            redirect_stderr(default_stderr)
++            # NOTE: `close` must always be called *after* `readavailable`.
++            append!(output, readavailable(pipe))
++            close(pipe)
++        end
++    end
++    return result, success, backtrace, chomp(String(output))
++end
++
++
++"""
++    issubmodule(sub, mod)
++
++Checks whether `sub` is a submodule of `mod`. A module is also considered to be
++its own submodule.
++
++E.g. `A.B.C` is a submodule of `A`, `A.B` and `A.B.C`, but it is not a submodule
++of `D`, `A.D` nor `A.B.C.D`.
++"""
++function issubmodule(sub, mod)
++    if (sub === Main) && (mod !== Main)
++        return false
++    end
++    (sub === mod) || issubmodule(parentmodule(sub), mod)
++end
++
++"""
++    isabsurl(url)
++
++Checks whether `url` is an absolute URL (as opposed to a relative one).
++"""
++isabsurl(url) = occursin(ABSURL_REGEX, url)
++const ABSURL_REGEX = r"^[[:alpha:]+-.]+://"
++
++include("DOM.jl")
++include("MDFlatten.jl")
++include("TextDiff.jl")
++include("Selectors.jl")
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d87aeacc8da802e889625c85387bbe86d20f2f61
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1143 @@@
++"""
++A module for rendering `Document` objects to HTML.
++
++# Keywords
++
++[`HTMLWriter`](@ref) uses the following additional keyword arguments that can be passed to
++[`Documenter.makedocs`](@ref): `assets`, `sitename`, `analytics`, `authors`, `pages`,
++`version`, `html_prettyurls`, `html_disable_git`.
++
++**`sitename`** is the site's title displayed in the title bar and at the top of the
++*navigation menu. This argument is mandatory for [`HTMLWriter`](@ref).
++
++**`pages`** defines the hierarchy of the navigation menu.
++
++**`assets`** can be used to include additional assets (JS, CSS, ICO etc. files). See below
++for more information.
++
++# Experimental keywords
++
++**`analytics`** can be used specify the Google Analytics tracking ID.
++
++**`version`** specifies the version string of the current version which will be the
++selected option in the version selector. If this is left empty (default) the version
++selector will be hidden. The special value `git-commit` sets the value in the output to
++`git:{commit}`, where `{commit}` is the first few characters of the current commit hash.
++
++**`html_prettyurls`** (default `true`) -- allows disabling the pretty URLs feature, which
++generates an output directory structre that hides the `.html` suffixes from the URLs (e.g.
++by default `src/foo.md` becomes `src/foo/index.html`). This does not work when browsing
++documentation in local files since browsers do not resolve `foo/` to `foo/index.html`
++for local files. If `html_prettyurls = false`, then Documenter generate `src/foo.html`
++instead and sets up the internal links accordingly, suitable for local documentation builds.
++
++**`html_disable_git`** can be used to disable calls to `git` when the document is not
++in a Git-controlled repository. Without setting this to `true`, Documenter will throw
++an error and exit if any of the Git commands fail. The calls to Git are mainly used to
++gather information about the current commit hash and file paths, necessary for constructing
++the links to the remote repository.
++
++**`html_edit_branch`** specifies which branch, tag or commit the "Edit on GitHub" links
++point to. It defaults to `master`. If it set to `nothing`, the current commit will be used.
++
++**`html_canonical`** specifies the canonical URL for your documentation. We recommend
++you set this to the base url of your stable documentation, e.g. `https://juliadocs.github.io/Documenter.jl/stable`.
++This allows search engines to know which version to send their users to. [See
++wikipedia for more information](https://en.wikipedia.org/wiki/Canonical_link_element).
++Default is `nothing`, in which case no canonical link is set.
++
++# Page outline
++
++The [`HTMLWriter`](@ref) makes use of the page outline that is determined by the
++headings. It is assumed that if the very first block of a page is a level 1 heading,
++then it is intended as the page title. This has two consequences:
++
++1. It is then used to automatically determine the page title in the navigation menu
++   and in the `<title>` tag, unless specified in the `.pages` option.
++2. If the first heading is interpreted as being the page title, it is not displayed
++   in the navigation sidebar.
++
++# Default and custom assets
++
++Documenter copies all files under the source directory (e.g. `/docs/src/`) over
++to the compiled site. It also copies a set of default assets from `/assets/html/`
++to the site's `assets/` directory, unless the user already had a file with the
++same name, in which case the user's files overrides the Documenter's file.
++This could, in principle, be used for customizing the site's style and scripting.
++
++The HTML output also links certain custom assets to the generated HTML documents,
++specfically a logo and additional javascript files.
++The asset files that should be linked must be placed in `assets/`, under the source
++directory (e.g `/docs/src/assets`) and must be on the top level (i.e. files in
++the subdirectories of `assets/` are not linked).
++
++For the **logo**, Documenter checks for the existence of `assets/logo.png`.
++If that's present, it gets displayed in the navigation bar.
++
++Additional JS, ICO, and CSS assets can be included in the generated pages using the
++`assets` keyword for `makedocs`. `assets` must be a `Vector{String}` and will include
++each listed asset in the `<head>` of every page in the order in which they are listed.
++The type of the asset (i.e. whether it is going to be included with a `<script>` or a
++`<link>` tag) is determined by the file's extension -- either `.js`, `.ico`, or `.css`.
++Adding an ICO asset is primarilly useful for setting a custom `favicon`.
++"""
++module HTMLWriter
++
++import Markdown
++
++import ...Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Expanders,
++    Formats,
++    Documenter,
++    Utilities,
++    Writers
++
++import ...Utilities.DOM: DOM, Tag, @tags
++using ...Utilities.MDFlatten
++
++const requirejs_cdn = "file:///usr/share/javascript/requirejs/require.min.js"
++const normalize_css = "file:///usr/share/javascript/normalize.css/normalize.min.css"
++const google_fonts = "file:///usr/share/doc/julia-doc/fontface.css"
++const fontawesome_css = "file:///usr/share/fonts-font-awesome/css/font-awesome.min.css"
++const highlightjs_css = "file:///usr/share/javascript/highlight.js/styles/default.css"
++
++
++"""
++[`HTMLWriter`](@ref)-specific globals that are passed to [`domify`](@ref) and
++other recursive functions.
++"""
++mutable struct HTMLContext
++    doc :: Documents.Document
++    logo :: String
++    scripts :: Vector{String}
++    documenter_js :: String
++    search_js :: String
++    search_index :: IOBuffer
++    search_index_js :: String
++    search_navnode :: Documents.NavNode
++    local_assets :: Vector{String}
++end
++HTMLContext(doc) = HTMLContext(doc, "", [], "", "", IOBuffer(), "", Documents.NavNode("search", "Search", nothing), [])
++
++"""
++Returns a page (as a [`Documents.Page`](@ref) object) using the [`HTMLContext`](@ref).
++"""
++getpage(ctx, path) = ctx.doc.internal.pages[path]
++getpage(ctx, navnode::Documents.NavNode) = getpage(ctx, navnode.page)
++
++
++function render(doc::Documents.Document)
++    !isempty(doc.user.sitename) || error("HTML output requires `sitename`.")
++
++    ctx = HTMLContext(doc)
++    ctx.search_index_js = "search_index.js"
++
++    copy_asset("arrow.svg", doc)
++
++    let logo = joinpath("assets", "logo.png")
++        if isfile(joinpath(doc.user.build, logo))
++            ctx.logo = logo
++        end
++    end
++
++    ctx.documenter_js = copy_asset("documenter.js", doc)
++    ctx.search_js = copy_asset("search.js", doc)
++
++    push!(ctx.local_assets, copy_asset("documenter.css", doc))
++    append!(ctx.local_assets, doc.user.assets)
++
++    for navnode in doc.internal.navlist
++        render_page(ctx, navnode)
++    end
++
++    render_search(ctx)
++
++    open(joinpath(doc.user.build, ctx.search_index_js), "w") do io
++        println(io, "var documenterSearchIndex = {\"docs\": [\n")
++        write(io, String(take!(ctx.search_index)))
++        println(io, "]}")
++    end
++end
++
++"""
++Copies an asset from Documenters `assets/html/` directory to `doc.user.build`.
++Returns the path of the copied asset relative to `.build`.
++"""
++function copy_asset(file, doc)
++    src = joinpath(Utilities.assetsdir(), "html", file)
++    alt_src = joinpath(doc.user.source, "assets", file)
++    dst = joinpath(doc.user.build, "assets", file)
++    isfile(src) || error("Asset '$file' not found at $(abspath(src))")
++
++    # Since user's alternative assets are already copied over in a previous build
++    # step and they should override documenter's original assets, we only actually
++    # perform the copy if <source>/assets/<file> does not exist. Note that checking
++    # the existence of <build>/assets/<file> is not sufficient since the <build>
++    # directory might be dirty from a previous build.
++    if isfile(alt_src)
++        Utilities.warn("Not copying '$src', provided by the user.")
++    else
++        ispath(dirname(dst)) || mkpath(dirname(dst))
++        ispath(dst) && Utilities.warn("Overwriting '$dst'.")
++        cp(src, dst, force=true)
++    end
++    assetpath = normpath(joinpath("assets", file))
++    # Replace any backslashes in links, if building the docs on Windows
++    return replace(assetpath, '\\' => '/')
++end
++
++# Page
++# ------------------------------------------------------------------------------
++
++"""
++Constructs and writes the page referred to by the `navnode` to `.build`.
++"""
++function render_page(ctx, navnode)
++    @tags html body
++
++    page = getpage(ctx, navnode)
++
++    head = render_head(ctx, navnode)
++    navmenu = render_navmenu(ctx, navnode)
++    article = render_article(ctx, navnode)
++
++    htmldoc = DOM.HTMLDocument(
++        html[:lang=>"en"](
++            head,
++            body(navmenu, article)
++        )
++    )
++
++    open_output(ctx, navnode) do io
++        print(io, htmldoc)
++    end
++end
++
++function render_head(ctx, navnode)
++    @tags head meta link script title
++    src = get_url(ctx, navnode)
++
++    page_title = "$(mdflatten(pagetitle(ctx, navnode))) · $(ctx.doc.user.sitename)"
++    css_links = [
++        normalize_css,
++        google_fonts,
++        fontawesome_css,
++        highlightjs_css,
++    ]
++    head(
++        meta[:charset=>"UTF-8"],
++        meta[:name => "viewport", :content => "width=device-width, initial-scale=1.0"],
++        title(page_title),
++
++        analytics_script(ctx.doc.user.analytics),
++
++        canonical_link_element(ctx.doc.user.html_canonical, src),
++
++        # Stylesheets.
++        map(css_links) do each
++            link[:href => each, :rel => "stylesheet", :type => "text/css"]
++        end,
++
++        script("documenterBaseURL=\"$(relhref(src, "."))\""),
++        script[
++            :src => requirejs_cdn,
++            Symbol("data-main") => relhref(src, ctx.documenter_js)
++        ],
++
++        script[:src => relhref(src, "siteinfo.js")],
++        script[:src => relhref(src, "../versions.js")],
++
++        # Custom user-provided assets.
++        asset_links(src, ctx.local_assets)
++    )
++end
++
++function asset_links(src::AbstractString, assets::Vector)
++    @tags link script
++    links = DOM.Node[]
++    for each in assets
++        ext = splitext(each)[end]
++        url = relhref(src, each)
++        node =
++            ext == ".ico" ? link[:href  => url, :rel => "icon", :type => "image/x-icon"] :
++            ext == ".css" ? link[:href  => url, :rel => "stylesheet", :type => "text/css"] :
++            ext == ".js"  ? script[:src => url] : continue # Skip non-js/css files.
++        push!(links, node)
++    end
++    return links
++end
++
++analytics_script(tracking_id::AbstractString) =
++    isempty(tracking_id) ? Tag(Symbol("#RAW#"))("") : Tag(:script)(
++        """
++        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
++        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
++        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
++        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
++
++        ga('create', '$(tracking_id)', 'auto');
++        ga('send', 'pageview');
++        """
++    )
++
++function canonical_link_element(canonical_link, src)
++   @tags link
++   if canonical_link === nothing
++      return Tag(Symbol("#RAW#"))("")
++   else
++      canonical_link_stripped = rstrip(canonical_link, '/')
++      href = "$canonical_link_stripped/$src"
++      return link[:rel => "canonical", :href => href]
++   end
++end
++
++## Search page
++# ------------
++
++function render_search(ctx)
++    @tags article body h1 header hr html li nav p span ul script
++
++    src = get_url(ctx, ctx.search_navnode)
++
++    head = render_head(ctx, ctx.search_navnode)
++    navmenu = render_navmenu(ctx, ctx.search_navnode)
++    article = article(
++        header(
++            nav(ul(li("Search"))),
++            hr(),
++            render_topbar(ctx, ctx.search_navnode),
++        ),
++        h1("Search"),
++        p["#search-info"]("Number of results: ", span["#search-results-number"]("loading...")),
++        ul["#search-results"]
++    )
++
++    htmldoc = DOM.HTMLDocument(
++        html[:lang=>"en"](
++            head,
++            body(navmenu, article),
++            script[:src => relhref(src, ctx.search_index_js)],
++            script[:src => relhref(src, ctx.search_js)],
++        )
++    )
++    open_output(ctx, ctx.search_navnode) do io
++        print(io, htmldoc)
++    end
++end
++
++# Navigation menu
++# ------------------------------------------------------------------------------
++
++function render_navmenu(ctx, navnode)
++    @tags a form h1 img input nav div select option
++
++    src = get_url(ctx, navnode)
++
++    navmenu = nav[".toc"]
++    if !isempty(ctx.logo)
++        push!(navmenu.nodes,
++            a[:href => relhref(src, "index.html")](
++                img[
++                    ".logo",
++                    :src => relhref(src, ctx.logo),
++                    :alt => "$(ctx.doc.user.sitename) logo"
++                ]
++            )
++        )
++    end
++    push!(navmenu.nodes, h1(ctx.doc.user.sitename))
++    let version_selector = select["#version-selector", :onChange => "window.location.href=this.value"]()
++        if isempty(ctx.doc.user.version)
++            push!(version_selector.attributes, :style => "visibility: hidden")
++        else
++            push!(version_selector.nodes,
++                option[
++                    :value => "#",
++                    :selected => "selected",
++                ](ctx.doc.user.version)
++            )
++        end
++        push!(navmenu.nodes, version_selector)
++    end
++    push!(navmenu.nodes,
++        form[".search#search-form", :action => navhref(ctx, ctx.search_navnode, navnode)](
++            input[
++                "#search-query",
++                :name => "q",
++                :type => "text",
++                :placeholder => "Search docs",
++            ],
++        )
++    )
++    push!(navmenu.nodes, navitem(ctx, navnode))
++    navmenu
++end
++
++"""
++[`navitem`](@ref) returns the lists and list items of the navigation menu.
++It gets called recursively to construct the whole tree.
++
++It always returns a [`DOM.Node`](@ref). If there's nothing to display (e.g. the node is set
++to be invisible), it returns an empty text node (`DOM.Node("")`).
++"""
++navitem(ctx, current) = navitem(ctx, current, ctx.doc.internal.navtree)
++function navitem(ctx, current, nns::Vector)
++    nodes = map(nn -> navitem(ctx, current, nn), nns)
++    filter!(node -> node.name !== DOM.TEXT, nodes)
++    isempty(nodes) ? DOM.Node("") : DOM.Tag(:ul)(nodes)
++end
++function navitem(ctx, current, nn::Documents.NavNode)
++    @tags ul li span a
++
++    # We'll do the children first, primarily to determine if this node has any that are
++    # visible. If it does not and it itself is not visible (including current), then
++    # we'll hide this one as well, returning an empty string Node.
++    children = navitem(ctx, current, nn.children)
++    if nn !== current && !nn.visible && children.name === DOM.TEXT
++        return DOM.Node("")
++    end
++
++    # construct this item
++    title = mdconvert(pagetitle(ctx, nn); droplinks=true)
++    link = if nn.page === nothing
++        span[".toctext"](title)
++    else
++        a[".toctext", :href => navhref(ctx, nn, current)](title)
++    end
++    item = (nn === current) ? li[".current"](link) : li(link)
++
++    # add the subsections (2nd level headings) from the page
++    if (nn === current) && current.page !== nothing
++        subs = collect_subsections(ctx.doc.internal.pages[current.page])
++        internal_links = map(subs) do s
++            istoplevel, anchor, text = s
++            _li = istoplevel ? li[".toplevel"] : li[]
++            _li(a[".toctext", :href => anchor](mdconvert(text; droplinks=true)))
++        end
++        push!(item.nodes, ul[".internal"](internal_links))
++    end
++
++    # add the visible subsections, if any, as a single list
++    (children.name === DOM.TEXT) || push!(item.nodes, children)
++
++    item
++end
++
++
++# Article (page contents)
++# ------------------------------------------------------------------------------
++
++function render_article(ctx, navnode)
++    @tags article header footer nav ul li hr span a
++
++    header_links = map(Documents.navpath(navnode)) do nn
++        title = mdconvert(pagetitle(ctx, nn); droplinks=true)
++        nn.page === nothing ? li(title) : li(a[:href => navhref(ctx, nn, navnode)](title))
++    end
++
++    topnav = nav(ul(header_links))
++
++    # Set the logo and name for the "Edit on.." button.
++    host_type = Utilities.repo_host_from_url(ctx.doc.user.repo)
++    if host_type == Utilities.RepoGitlab
++        host = "GitLab"
++        logo = "\uf296"
++    elseif host_type == Utilities.RepoGithub
++        host = "GitHub"
++        logo = "\uf09b"
++    elseif host_type == Utilities.RepoBitbucket
++        host = "BitBucket"
++        logo = "\uf171"
++    else
++        host = ""
++        logo = "\uf15c"
++    end
++    hoststring = isempty(host) ? " source" : " on $(host)"
++
++    if !ctx.doc.user.html_disable_git
++        pageurl = get(getpage(ctx, navnode).globals.meta, :EditURL, getpage(ctx, navnode).source)
++        if Utilities.isabsurl(pageurl)
++            url = pageurl
++        else
++            if !(pageurl == getpage(ctx, navnode).source)
++                # need to set users path relative the page itself
++                pageurl = joinpath(first(splitdir(getpage(ctx, navnode).source)), pageurl)
++            end
++            url = Utilities.url(ctx.doc.user.repo, pageurl, commit=ctx.doc.user.html_edit_branch)
++        end
++        if url !== nothing
++            edit_verb = (ctx.doc.user.html_edit_branch === nothing) ? "View" : "Edit"
++            push!(topnav.nodes, a[".edit-page", :href => url](span[".fa"](logo), " $(edit_verb)$hoststring"))
++        end
++    end
++    art_header = header(topnav, hr(), render_topbar(ctx, navnode))
++
++    # build the footer with nav links
++    art_footer = footer(hr())
++    if navnode.prev !== nothing
++        direction = span[".direction"]("Previous")
++        title = span[".title"](mdconvert(pagetitle(ctx, navnode.prev); droplinks=true))
++        link = a[".previous", :href => navhref(ctx, navnode.prev, navnode)](direction, title)
++        push!(art_footer.nodes, link)
++    end
++
++    if navnode.next !== nothing
++        direction = span[".direction"]("Next")
++        title = span[".title"](mdconvert(pagetitle(ctx, navnode.next); droplinks=true))
++        link = a[".next", :href => navhref(ctx, navnode.next, navnode)](direction, title)
++        push!(art_footer.nodes, link)
++    end
++
++    pagenodes = domify(ctx, navnode)
++    article["#docs"](art_header, pagenodes, art_footer)
++end
++
++function render_topbar(ctx, navnode)
++    @tags a div span
++    page_title = string(mdflatten(pagetitle(ctx, navnode)))
++    return div["#topbar"](span(page_title), a[".fa .fa-bars", :href => "#"])
++end
++
++# expand the versions argument from the user
++# and return entries and needed symlinks
++function expand_versions(dir, versions)
++    # output: entries and symlinks
++    entries = String[]
++    symlinks = Pair{String,String}[]
++
++    # read folders and filter out symlinks
++    available_folders = readdir(dir)
++    cd(() -> filter!(!islink, available_folders), dir)
++
++    # filter and sort release folders
++    vnum(x) = VersionNumber(x)
++    version_folders = [x for x in available_folders if occursin(Base.VERSION_REGEX, x)]
++    sort!(version_folders, lt = (x, y) -> vnum(x) < vnum(y), rev = true)
++    release_folders = filter(x -> (v = vnum(x); v.prerelease == () && v.build == ()), version_folders)
++    # pre_release_folders = filter(x -> (v = vnum(x); v.prerelease != () || v.build != ()), version_folders)
++    major_folders = filter!(x -> (v = vnum(x); v.major != 0),
++                            unique(x -> (v = vnum(x); v.major), release_folders))
++    minor_folders = filter!(x -> (v = vnum(x); !(v.major == 0 && v.minor == 0)),
++                            unique(x -> (v = vnum(x); (v.major, v.minor)), release_folders))
++    patch_folders = unique(x -> (v = vnum(x); (v.major, v.minor, v.patch)), release_folders)
++
++    filter!(x -> vnum(x) !== 0, major_folders)
++
++    # populate output
++    for entry in versions
++        if entry == "v#" # one doc per major release
++            for x in major_folders
++                vstr = "v$(vnum(x).major).$(vnum(x).minor)"
++                push!(entries, vstr)
++                push!(symlinks, vstr => x)
++            end
++        elseif entry == "v#.#" # one doc per minor release
++            for x in minor_folders
++                vstr = "v$(vnum(x).major).$(vnum(x).minor)"
++                push!(entries, vstr)
++                push!(symlinks, vstr => x)
++            end
++        elseif entry == "v#.#.#" # one doc per patch release
++            for x in patch_folders
++                vstr = "v$(vnum(x).major).$(vnum(x).minor).$(vnum(x).patch)"
++                push!(entries, vstr)
++                push!(symlinks, vstr => x)
++            end
++        elseif entry == "v^" || (entry isa Pair && entry.second == "v^")
++            if !isempty(release_folders)
++                x = first(release_folders)
++                vstr = isa(entry, Pair) ? entry.first : "v$(vnum(x).major).$(vnum(x).minor)"
++                push!(entries, vstr)
++                push!(symlinks, vstr => x)
++            end
++        elseif entry isa Pair
++            k, v = entry
++            i = findfirst(==(v), available_folders)
++            if i === nothing
++                @info("no match for `versions` entry `$(repr(entry))`")
++            else
++                push!(entries, k)
++                push!(symlinks, k => v)
++            end
++        else
++            @info("no match for `versions` entry `$(repr(entry))`")
++        end
++    end
++    unique!(entries) # remove any duplicates
++
++    # generate remaining symlinks
++    foreach(x -> push!(symlinks, "v$(vnum(x).major)" => x), major_folders)
++    foreach(x -> push!(symlinks, "v$(vnum(x).major).$(vnum(x).minor)" => x), minor_folders)
++    foreach(x -> push!(symlinks, "v$(vnum(x).major).$(vnum(x).minor).$(vnum(x).patch)" => x), patch_folders)
++    filter!(x -> x.first != x.second, unique!(symlinks))
++
++    # assert that none of the links point to another link
++    for link in symlinks
++        i = findfirst(x -> link.first == x.second, symlinks)
++        if i !== nothing
++            throw(ArgumentError("link `$(link)` incompatible with link `$(symlinks[i])`."))
++        end
++    end
++
++    return entries, symlinks
++end
++
++# write version file
++function generate_version_file(versionfile::AbstractString, entries)
++    open(versionfile, "w") do buf
++        println(buf, "var DOC_VERSIONS = [")
++        for folder in entries
++            println(buf, "  \"", folder, "\",")
++        end
++        println(buf, "];")
++    end
++end
++
++function generate_siteinfo_file(dir::AbstractString, version::AbstractString)
++    open(joinpath(dir, "siteinfo.js"), "w") do buf
++        println(buf, "var DOCUMENTER_CURRENT_VERSION = \"$(version)\";")
++    end
++end
++
++## domify(...)
++# ------------
++
++"""
++Converts recursively a [`Documents.Page`](@ref), `Markdown` or Documenter
++`*Node` objects into HTML DOM.
++"""
++function domify(ctx, navnode)
++    page = getpage(ctx, navnode)
++    sib = SearchIndexBuffer(ctx, navnode)
++    ret = map(page.elements) do elem
++        search_append(sib, elem)
++        domify(ctx, navnode, page.mapping[elem])
++    end
++    search_flush(sib)
++    ret
++end
++
++mutable struct SearchIndexBuffer
++    ctx :: HTMLContext
++    src :: String
++    page :: Documents.Page
++    loc :: String
++    category :: Symbol
++    title :: String
++    page_title :: String
++    buffer :: IOBuffer
++    function SearchIndexBuffer(ctx, navnode)
++        page_title = mdflatten(pagetitle(ctx, navnode))
++        new(
++            ctx,
++            pretty_url(ctx, get_url(ctx, navnode.page)),
++            getpage(ctx, navnode),
++            "",
++            :page,
++            page_title,
++            page_title,
++            IOBuffer()
++        )
++    end
++end
++
++function search_append(sib, node::Markdown.Header)
++    search_flush(sib)
++    sib.category = :section
++    sib.title = mdflatten(node)
++    a = sib.page.mapping[node]
++    sib.loc = "$(a.id)-$(a.nth)"
++end
++
++search_append(sib, node) = mdflatten(sib.buffer, node)
++
++function search_flush(sib)
++    # Replace any backslashes in links, if building the docs on Windows
++    src = replace(sib.src, '\\' => '/')
++    ref = "$(src)#$(sib.loc)"
++    text = String(take!(sib.buffer))
++    println(sib.ctx.search_index, """
++    {
++        "location": "$(jsescape(ref))",
++        "page": "$(jsescape(sib.page_title))",
++        "title": "$(jsescape(sib.title))",
++        "category": "$(jsescape(lowercase(string(sib.category))))",
++        "text": "$(jsescape(text))"
++    },
++    """)
++end
++
++"""
++Replaces some of the characters in the string with escape sequences so that the strings
++would be valid JS string literals, as per the
++[ECMAScript® 2017 standard](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-literals-string-literals).
++
++Note that it always escapes both potential `"` and `'` closing quotes.
++"""
++function jsescape(s)
++    b = IOBuffer()
++    # From the ECMAScript® 2017 standard:
++    #
++    # > All code points may appear literally in a string literal except for the closing
++    # > quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE RETURN), U+2028 (LINE
++    # > SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A (LINE FEED).
++    #
++    # https://www.ecma-international.org/ecma-262/8.0/index.html#sec-literals-string-literals
++    for c in s
++        if c === '\u000a'     # LINE FEED,       i.e. \n
++            write(b, "\\n")
++        elseif c === '\u000d' # CARRIAGE RETURN, i.e. \r
++            write(b, "\\r")
++        elseif c === '\u005c' # REVERSE SOLIDUS, i.e. \
++            write(b, "\\\\")
++        elseif c === '\u0022' # QUOTATION MARK,  i.e. "
++            write(b, "\\\"")
++        elseif c === '\u0027' # APOSTROPHE,      i.e. '
++            write(b, "\\'")
++        elseif c === '\u2028' # LINE SEPARATOR
++            write(b, "\\u2028")
++        elseif c === '\u2029' # PARAGRAPH SEPARATOR
++            write(b, "\\u2029")
++        else
++            write(b, c)
++        end
++    end
++    String(take!(b))
++end
++
++function domify(ctx, navnode, node)
++    fixlinks!(ctx, navnode, node)
++    mdconvert(node, Markdown.MD())
++end
++
++function domify(ctx, navnode, anchor::Anchors.Anchor)
++    @tags a
++    aid = "$(anchor.id)-$(anchor.nth)"
++    if isa(anchor.object, Markdown.Header)
++        h = anchor.object
++        fixlinks!(ctx, navnode, h)
++        DOM.Tag(Symbol("h$(Utilities.header_level(h))"))(
++            a[".nav-anchor", :id => aid, :href => "#$aid"](mdconvert(h.text, h))
++        )
++    else
++        a[".nav-anchor", :id => aid, :href => "#$aid"](domify(ctx, navnode, anchor.object))
++    end
++end
++
++
++struct ListBuilder
++    es::Vector
++end
++ListBuilder() = ListBuilder([])
++
++import Base: push!
++function push!(lb::ListBuilder, level, node)
++    @assert level >= 1
++    if level == 1
++        push!(lb.es, node)
++    else
++        if isempty(lb.es) || typeof(last(lb.es)) !== ListBuilder
++            push!(lb.es, ListBuilder())
++        end
++        push!(last(lb.es), level-1, node)
++    end
++end
++
++function domify(lb::ListBuilder)
++    @tags ul li
++    ul(map(e -> isa(e, ListBuilder) ? domify(e) : li(e), lb.es))
++end
++
++function domify(ctx, navnode, contents::Documents.ContentsNode)
++    @tags a
++    navnode_dir = dirname(navnode.page)
++    navnode_url = get_url(ctx, navnode)
++    lb = ListBuilder()
++    for (count, path, anchor) in contents.elements
++        path = joinpath(navnode_dir, path) # links in ContentsNodes are relative to current page
++        path = pretty_url(ctx, relhref(navnode_url, get_url(ctx, path)))
++        header = anchor.object
++        url = string(path, '#', anchor.id, '-', anchor.nth)
++        node = a[:href=>url](mdconvert(header.text; droplinks=true))
++        level = Utilities.header_level(header)
++        push!(lb, level, node)
++    end
++    domify(lb)
++end
++
++function domify(ctx, navnode, index::Documents.IndexNode)
++    @tags a code li ul
++    navnode_dir = dirname(navnode.page)
++    navnode_url = get_url(ctx, navnode)
++    lis = map(index.elements) do el
++        object, doc, path, mod, cat = el
++        path = joinpath(navnode_dir, path) # links in IndexNodes are relative to current page
++        path = pretty_url(ctx, relhref(navnode_url, get_url(ctx, path)))
++        url = string(path, "#", Utilities.slugify(object))
++        li(a[:href=>url](code("$(object.binding)")))
++    end
++    ul(lis)
++end
++
++function domify(ctx, navnode, docs::Documents.DocsNodes)
++    [domify(ctx, navnode, node) for node in docs.nodes]
++end
++
++function domify(ctx, navnode, node::Documents.DocsNode)
++    @tags a code div section span
++
++    # push to search index
++    sib = SearchIndexBuffer(ctx, navnode)
++    sib.loc = node.anchor.id
++    sib.title = string(node.object.binding)
++    sib.category = Symbol(Utilities.doccat(node.object))
++    mdflatten(sib.buffer, node.docstr)
++    search_flush(sib)
++
++    section[".docstring"](
++        div[".docstring-header"](
++            a[".docstring-binding", :id=>node.anchor.id, :href=>"#$(node.anchor.id)"](code("$(node.object.binding)")),
++            " — ", # &mdash;
++            span[".docstring-category"]("$(Utilities.doccat(node.object))"),
++            "."
++        ),
++        domify_doc(ctx, navnode, node.docstr)
++    )
++end
++
++function domify_doc(ctx, navnode, md::Markdown.MD)
++    @tags a
++    if haskey(md.meta, :results)
++        # The `:results` field contains a vector of `Docs.DocStr` objects associated with
++        # each markdown object. The `DocStr` contains data such as file and line info that
++        # we need for generating correct source links.
++        map(zip(md.content, md.meta[:results])) do md
++            markdown, result = md
++            ret = Any[domify(ctx, navnode, Writers.MarkdownWriter.dropheaders(markdown))]
++            # When a source link is available then print the link.
++            if !ctx.doc.user.html_disable_git
++                url = Utilities.url(ctx.doc.internal.remote, ctx.doc.user.repo, result)
++                if url !== nothing
++                    push!(ret, a[".source-link", :target=>"_blank", :href=>url]("source"))
++                end
++            end
++            ret
++        end
++    else
++        # Docstrings with no `:results` metadata won't contain source locations so we don't
++        # try to print them out. Just print the basic docstring.
++        domify(ctx, navnode, Writers.MarkdownWriter.dropheaders(md))
++    end
++end
++
++function domify(ctx, navnode, node::Documents.EvalNode)
++    node.result === nothing ? DOM.Node[] : domify(ctx, navnode, node.result)
++end
++
++# nothing to show for MetaNodes, so we just return an empty list
++domify(ctx, navnode, node::Documents.MetaNode) = DOM.Node[]
++
++function domify(ctx, navnode, raw::Documents.RawNode)
++    raw.name === :html ? Tag(Symbol("#RAW#"))(raw.text) : DOM.Node[]
++end
++
++
++# Utilities
++# ------------------------------------------------------------------------------
++
++"""
++Opens the output file of the `navnode` in write node. If necessary, the path to the output
++file is created before opening the file.
++"""
++function open_output(f, ctx, navnode)
++    path = joinpath(ctx.doc.user.build, get_url(ctx, navnode))
++    isdir(dirname(path)) || mkpath(dirname(path))
++    open(f, path, "w")
++end
++
++"""
++Get the relative hyperlink between two [`Documents.NavNode`](@ref)s. Assumes that both
++[`Documents.NavNode`](@ref)s have an associated [`Documents.Page`](@ref) (i.e. `.page`
++is not `nothing`).
++"""
++navhref(ctx, to, from) = pretty_url(ctx, relhref(get_url(ctx, from), get_url(ctx, to)))
++
++"""
++Calculates a relative HTML link from one path to another.
++"""
++function relhref(from, to)
++    pagedir = dirname(from)
++    # The regex separator replacement is necessary since otherwise building the docs on
++    # Windows will result in paths that have `//` separators which break asset inclusion.
++    replace(relpath(to, isempty(pagedir) ? "." : pagedir), r"[/\\]+" => "/")
++end
++
++"""
++Returns the full path corresponding to a path of a `.md` page file. The the input and output
++paths are assumed to be relative to `src/`.
++"""
++function get_url(ctx, path::AbstractString)
++    if ctx.doc.user.html_prettyurls
++        d = if basename(path) == "index.md"
++            dirname(path)
++        else
++            first(splitext(path))
++        end
++        isempty(d) ? "index.html" : "$d/index.html"
++    else
++        Formats.extension(:html, path)
++    end
++end
++
++"""
++Returns the full path of a [`Documents.NavNode`](@ref) relative to `src/`.
++"""
++get_url(ctx, navnode::Documents.NavNode) = get_url(ctx, navnode.page)
++
++"""
++If `html_prettyurls` is enabled, returns a "pretty" version of the `path` which can then be
++used in links in the resulting HTML file.
++"""
++function pretty_url(ctx, path::AbstractString)
++    if ctx.doc.user.html_prettyurls
++        dir, file = splitdir(path)
++        if file == "index.html"
++            return length(dir) == 0 ? "" : "$(dir)/"
++        end
++    end
++    return path
++end
++
++"""
++Tries to guess the page title by looking at the `<h1>` headers and returns the
++header contents of the first `<h1>` on a page (or `nothing` if the algorithm
++was unable to find any `<h1>` headers).
++"""
++function pagetitle(page::Documents.Page)
++    title = nothing
++    for element in page.elements
++        if isa(element, Markdown.Header{1})
++            title = element.text
++            break
++        end
++    end
++    title
++end
++
++function pagetitle(ctx, navnode::Documents.NavNode)
++    if navnode.title_override !== nothing
++        # parse title_override as markdown
++        md = Markdown.parse(navnode.title_override)
++        # Markdown.parse results in a paragraph so we need to strip that
++        if !(length(md.content) === 1 && isa(first(md.content), Markdown.Paragraph))
++            error("Bad Markdown provided for page title: '$(navnode.title_override)'")
++        end
++        return first(md.content).content
++    end
++
++    if navnode.page !== nothing
++        title = pagetitle(getpage(ctx, navnode))
++        title === nothing || return title
++    end
++
++    "-"
++end
++
++"""
++Returns an ordered list of tuples, `(toplevel, anchor, text)`, corresponding to level 1 and 2
++headings on the `page`. Note that if the first header on the `page` is a level 1 header then
++it is not included -- it is assumed to be the page title and so does not need to be included
++in the navigation menu twice.
++"""
++function collect_subsections(page::Documents.Page)
++    sections = []
++    title_found = false
++    for element in page.elements
++        if isa(element, Markdown.Header) && Utilities.header_level(element) < 3
++            toplevel = Utilities.header_level(element) === 1
++            # Don't include the first header if it is `h1`.
++            if toplevel && isempty(sections) && !title_found
++                title_found = true
++                continue
++            end
++            anchor = page.mapping[element]
++            push!(sections, (toplevel, "#$(anchor.id)-$(anchor.nth)", element.text))
++        end
++    end
++    return sections
++end
++
++
++# mdconvert
++# ------------------------------------------------------------------------------
++
++const md_block_nodes = [Markdown.MD, Markdown.BlockQuote]
++push!(md_block_nodes, Markdown.List)
++push!(md_block_nodes, Markdown.Admonition)
++
++"""
++[`MDBlockContext`](@ref) is a union of all the Markdown nodes whose children should
++be blocks. It can be used to dispatch on all the block-context nodes at once.
++"""
++const MDBlockContext = Union{md_block_nodes...}
++
++"""
++Convert a markdown object to a `DOM.Node` object.
++
++The `parent` argument is passed to allow for context-dependant conversions.
++"""
++mdconvert(md; kwargs...) = mdconvert(md, md; kwargs...)
++
++mdconvert(text::AbstractString, parent; kwargs...) = DOM.Node(text)
++
++mdconvert(vec::Vector, parent; kwargs...) = [mdconvert(x, parent; kwargs...) for x in vec]
++
++mdconvert(md::Markdown.MD, parent; kwargs...) = Tag(:div)(mdconvert(md.content, md; kwargs...))
++
++mdconvert(b::Markdown.BlockQuote, parent; kwargs...) = Tag(:blockquote)(mdconvert(b.content, b; kwargs...))
++
++mdconvert(b::Markdown.Bold, parent; kwargs...) = Tag(:strong)(mdconvert(b.text, parent; kwargs...))
++
++function mdconvert(c::Markdown.Code, parent::MDBlockContext; kwargs...)
++    @tags pre code
++    language = isempty(c.language) ? "none" : c.language
++    pre(code[".language-$(language)"](c.code))
++end
++mdconvert(c::Markdown.Code, parent; kwargs...) = Tag(:code)(c.code)
++
++mdconvert(h::Markdown.Header{N}, parent; kwargs...) where {N} = DOM.Tag(Symbol("h$N"))(mdconvert(h.text, h; kwargs...))
++
++mdconvert(::Markdown.HorizontalRule, parent; kwargs...) = Tag(:hr)()
++
++mdconvert(i::Markdown.Image, parent; kwargs...) = Tag(:img)[:src => i.url, :alt => i.alt]
++
++mdconvert(i::Markdown.Italic, parent; kwargs...) = Tag(:em)(mdconvert(i.text, i; kwargs...))
++
++mdconvert(m::Markdown.LaTeX, ::MDBlockContext; kwargs...)   = Tag(:div)(string("\\[", m.formula, "\\]"))
++mdconvert(m::Markdown.LaTeX, parent; kwargs...) = Tag(:span)(string('$', m.formula, '$'))
++
++mdconvert(::Markdown.LineBreak, parent; kwargs...) = Tag(:br)()
++
++function mdconvert(link::Markdown.Link, parent; droplinks=false, kwargs...)
++    link_text = mdconvert(link.text, link; droplinks=droplinks, kwargs...)
++    droplinks ? link_text : Tag(:a)[:href => link.url](link_text)
++end
++
++mdconvert(list::Markdown.List, parent; kwargs...) = (Markdown.isordered(list) ? Tag(:ol) : Tag(:ul))(map(Tag(:li), mdconvert(list.items, list; kwargs...)))
++
++mdconvert(paragraph::Markdown.Paragraph, parent; kwargs...) = Tag(:p)(mdconvert(paragraph.content, paragraph; kwargs...))
++
++# For compatibility with versions before Markdown.List got the `loose field, Julia PR #26598
++const list_has_loose_field = :loose in fieldnames(Markdown.List)
++function mdconvert(paragraph::Markdown.Paragraph, parent::Markdown.List; kwargs...)
++    content = mdconvert(paragraph.content, paragraph; kwargs...)
++    return (list_has_loose_field && !parent.loose) ? content : Tag(:p)(content)
++end
++
++mdconvert(t::Markdown.Table, parent; kwargs...) = Tag(:table)(
++    Tag(:tr)(map(x -> Tag(:th)(mdconvert(x, t; kwargs...)), t.rows[1])),
++    map(x -> Tag(:tr)(map(y -> Tag(:td)(mdconvert(y, x; kwargs...)), x)), t.rows[2:end])
++)
++
++mdconvert(expr::Union{Expr,Symbol}, parent; kwargs...) = string(expr)
++
++mdconvert(f::Markdown.Footnote, parent; kwargs...) = footnote(f.id, f.text, parent; kwargs...)
++footnote(id, text::Nothing, parent; kwargs...) = Tag(:a)[:href => "#footnote-$(id)"]("[$id]")
++function footnote(id, text, parent; kwargs...)
++    Tag(:div)[".footnote#footnote-$(id)"](
++        Tag(:a)[:href => "#footnote-$(id)"](Tag(:strong)("[$id]")),
++        mdconvert(text, parent; kwargs...),
++    )
++end
++
++function mdconvert(a::Markdown.Admonition, parent; kwargs...)
++    @tags div
++    div[".admonition.$(a.category)"](
++        div[".admonition-title"](a.title),
++        div[".admonition-text"](mdconvert(a.content, a; kwargs...))
++    )
++end
++
++mdconvert(html::Documents.RawHTML, parent; kwargs...) = Tag(Symbol("#RAW#"))(html.code)
++
++
++# fixlinks!
++# ------------------------------------------------------------------------------
++
++"""
++Replaces URLs in `Markdown.Link` elements (if they point to a local `.md` page) with the
++actual URLs.
++"""
++function fixlinks!(ctx, navnode, link::Markdown.Link)
++    fixlinks!(ctx, navnode, link.text)
++    Utilities.isabsurl(link.url) && return
++
++    # links starting with a # are references within the same file -- there's nothing to fix
++    # for such links
++    startswith(link.url, '#') && return
++
++    s = split(link.url, "#", limit = 2)
++    if Sys.iswindows() && ':' in first(s)
++        Utilities.warn("Invalid local link: colons not allowed in paths on Windows\n    '$(link.url)' in $(navnode.page)")
++        return
++    end
++    path = normpath(joinpath(dirname(navnode.page), first(s)))
++
++    if endswith(path, ".md") && path in keys(ctx.doc.internal.pages)
++        # make sure that links to different valid pages are correct
++        path = pretty_url(ctx, relhref(get_url(ctx, navnode), get_url(ctx, path)))
++    elseif isfile(joinpath(ctx.doc.user.build, path))
++        # update links to other files that are present in build/ (e.g. either user
++        # provided files or generated by code examples)
++        path = relhref(get_url(ctx, navnode), path)
++    else
++        Utilities.warn("Invalid local link: unresolved path\n    '$(link.url)' in $(navnode.page)")
++    end
++
++    # Replace any backslashes in links, if building the docs on Windows
++    path = replace(path, '\\' => '/')
++    link.url = (length(s) > 1) ? "$path#$(last(s))" : String(path)
++end
++
++function fixlinks!(ctx, navnode, img::Markdown.Image)
++    Utilities.isabsurl(img.url) && return
++
++    if Sys.iswindows() && ':' in img.url
++        Utilities.warn("Invalid local image: colons not allowed in paths on Windows\n    '$(img.url)' in $(navnode.page)")
++        return
++    end
++
++    path = joinpath(dirname(navnode.page), img.url)
++    if isfile(joinpath(ctx.doc.user.build, path))
++        path = relhref(get_url(ctx, navnode), path)
++        # Replace any backslashes in links, if building the docs on Windows
++        img.url = replace(path, '\\' => '/')
++    else
++        Utilities.warn("Invalid local image: unresolved path\n    '$(img.url)' in `$(navnode.page)`")
++    end
++end
++
++fixlinks!(ctx, navnode, md::Markdown.MD) = fixlinks!(ctx, navnode, md.content)
++function fixlinks!(ctx, navnode, a::Markdown.Admonition)
++    fixlinks!(ctx, navnode, a.title)
++    fixlinks!(ctx, navnode, a.content)
++end
++fixlinks!(ctx, navnode, b::Markdown.BlockQuote) = fixlinks!(ctx, navnode, b.content)
++fixlinks!(ctx, navnode, b::Markdown.Bold) = fixlinks!(ctx, navnode, b.text)
++fixlinks!(ctx, navnode, f::Markdown.Footnote) = fixlinks!(ctx, navnode, f.text)
++fixlinks!(ctx, navnode, h::Markdown.Header) = fixlinks!(ctx, navnode, h.text)
++fixlinks!(ctx, navnode, i::Markdown.Italic) = fixlinks!(ctx, navnode, i.text)
++fixlinks!(ctx, navnode, list::Markdown.List) = fixlinks!(ctx, navnode, list.items)
++fixlinks!(ctx, navnode, p::Markdown.Paragraph) = fixlinks!(ctx, navnode, p.content)
++fixlinks!(ctx, navnode, t::Markdown.Table) = fixlinks!(ctx, navnode, t.rows)
++
++fixlinks!(ctx, navnode, mds::Vector) = map(md -> fixlinks!(ctx, navnode, md), mds)
++fixlinks!(ctx, navnode, md) = nothing
++
++# TODO: do some regex-magic in raw HTML blocks? Currently ignored.
++#fixlinks!(ctx, navnode, md::Documents.RawHTML) = ...
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..51ce92e7ccd4afdb847b9c8de30235b0e4a100f7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,540 @@@
++"""
++A module for rendering `Document` objects to LaTeX and PDF.
++
++# Keywords
++
++[`LaTeXWriter`](@ref) uses the following additional keyword arguments that can be passed to
++[`Documenter.makedocs`](@ref): `authors`, `sitename`.
++
++**`sitename`** is the site's title displayed in the title bar and at the top of the
++navigation menu. It goes into the `\\title` LaTeX command.
++
++**`authors`** can be used to specify the authors of. It goes into the `\\author` LaTeX command.
++
++"""
++module LaTeXWriter
++
++import ...Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Expanders,
++    Formats,
++    Documenter,
++    Utilities,
++    Writers
++
++import Markdown
++
++mutable struct Context{I <: IO} <: IO
++    io::I
++    in_header::Bool
++    footnotes::Dict{String, Int}
++    depth::Int
++    filename::String # currently active source file
++end
++Context(io) = Context{typeof(io)}(io, false, Dict(), 1, "")
++
++_print(c::Context, args...) = Base.print(c.io, args...)
++_println(c::Context, args...) = Base.println(c.io, args...)
++
++
++const STYLE = joinpath(dirname(@__FILE__), "..", "..", "assets", "latex", "documenter.sty")
++
++hastex() = (try; success(`latexmk -version`); catch; false; end)
++
++const DOCUMENT_STRUCTURE = (
++    "part",
++    "chapter",
++    "section",
++    "subsection",
++    "subsubsection",
++    "paragraph",
++    "subparagraph",
++)
++
++function render(doc::Documents.Document)
++    mktempdir() do path
++        cp(joinpath(doc.user.root, doc.user.build), joinpath(path, "build"))
++        cd(joinpath(path, "build")) do
++            file = replace("$(doc.user.sitename).tex", " " => "")
++            open(file, "w") do io
++                context = Context(io)
++                writeheader(context, doc)
++                for (title, filename, depth) in files(doc.user.pages)
++                    context.filename = filename
++                    empty!(context.footnotes)
++                    if 1 <= depth <= length(DOCUMENT_STRUCTURE)
++                        header_type = DOCUMENT_STRUCTURE[depth]
++                        header_text = "\n\\$(header_type){$(title)}\n"
++                        if isempty(filename)
++                            _println(context, header_text)
++                        else
++                            path = normpath(filename)
++                            page = doc.internal.pages[path]
++                            if get(page.globals.meta, :IgnorePage, :none) !== :latex
++                                context.depth = depth + (isempty(title) ? 0 : 1)
++                                context.depth > depth && _println(context, header_text)
++                                latex(context, page, doc)
++                            end
++                        end
++                    end
++                end
++                writefooter(context, doc)
++            end
++            cp(STYLE, "documenter.sty")
++            if hastex()
++                outdir = joinpath(doc.user.root, doc.user.build)
++                pdf = replace("$(doc.user.sitename).pdf", " " => "")
++                try
++                    run(`latexmk -silent -f -interaction=nonstopmode -view=none -lualatex -shell-escape $file`)
++                catch err
++                    Utilities.warn("failed to compile. Check generated LaTeX file.")
++                    cp(file, joinpath(outdir, file); force = true)
++                end
++                cp(pdf, joinpath(outdir, pdf); force = true)
++            else
++                Utilities.warn("`latexmk` and `lualatex` required for PDF generation.")
++            end
++        end
++    end
++end
++
++function writeheader(io::IO, doc::Documents.Document)
++    custom = joinpath(doc.user.root, doc.user.source, "assets", "custom.sty")
++    isfile(custom) ? cp(custom, "custom.sty"; force = true) : touch("custom.sty")
++    preamble =
++        """
++        \\documentclass{memoir}
++
++        \\usepackage{./documenter}
++        \\usepackage{./custom}
++
++        \\title{$(doc.user.sitename)}
++        \\author{$(doc.user.authors)}
++
++        \\begin{document}
++
++        \\frontmatter
++        \\maketitle
++        \\tableofcontents
++
++        \\mainmatter
++
++        """
++    _println(io, preamble)
++end
++
++function writefooter(io::IO, doc::Documents.Document)
++    _println(io, "\n\\end{document}")
++end
++
++function latex(io::IO, page::Documents.Page, doc::Documents.Document)
++    for element in page.elements
++        latex(io, page.mapping[element], page, doc)
++    end
++end
++
++function latex(io::IO, vec::Vector, page, doc)
++    for each in vec
++        latex(io, each, page, doc)
++    end
++end
++
++function latex(io::IO, anchor::Anchors.Anchor, page, doc)
++    id = string(hash(string(anchor.id, "-", anchor.nth)))
++    _println(io, "\n\\hypertarget{", id, "}{}\n")
++    latex(io, anchor.object, page, doc)
++end
++
++
++## Documentation Nodes.
++
++function latex(io::IO, node::Documents.DocsNodes, page, doc)
++    for node in node.nodes
++        latex(io, node, page, doc)
++    end
++end
++
++function latex(io::IO, node::Documents.DocsNode, page, doc)
++    id = string(hash(string(node.anchor.id)))
++    # Docstring header based on the name of the binding and it's category.
++    _println(io, "\\hypertarget{", id, "}{} ")
++    _print(io, "\\hyperlink{", id, "}{\\texttt{")
++    latexesc(io, string(node.object.binding))
++    _print(io, "}} ")
++    _println(io, " -- {", Utilities.doccat(node.object), ".}\n")
++    # # Body. May contain several concatenated docstrings.
++    _println(io, "\\begin{adjustwidth}{2em}{0pt}")
++    latexdoc(io, node.docstr, page, doc)
++    _println(io, "\n\\end{adjustwidth}")
++end
++
++function latexdoc(io::IO, md::Markdown.MD, page, doc)
++    if haskey(md.meta, :results)
++        # The `:results` field contains a vector of `Docs.DocStr` objects associated with
++        # each markdown object. The `DocStr` contains data such as file and line info that
++        # we need for generating correct scurce links.
++        for (markdown, result) in zip(md.content, md.meta[:results])
++            latex(io, Writers.MarkdownWriter.dropheaders(markdown), page, doc)
++            # When a source link is available then print the link.
++            url = Utilities.url(doc.internal.remote, doc.user.repo, result)
++            if url !== nothing
++                link = "\\href{$url}{\\texttt{source}}"
++                _println(io, "\n", link, "\n")
++            end
++        end
++    else
++        # Docstrings with no `:results` metadata won't contain source locations so we don't
++        # try to print them out. Just print the basic docstring.
++        render(io, mime, dropheaders(md), page, doc)
++    end
++end
++
++function latexdoc(io::IO, other, page, doc)
++    # TODO: properly support non-markdown docstrings at some point.
++    latex(io, other, page, doc)
++end
++
++
++## Index, Contents, and Eval Nodes.
++
++function latex(io::IO, index::Documents.IndexNode, page, doc)
++    _println(io, "\\begin{itemize}")
++    for (object, _, page, mod, cat) in index.elements
++        id = string(hash(string(Utilities.slugify(object))))
++        text = string(object.binding)
++        _print(io, "\\item \\hyperlink{")
++        _print(io, id, "}{\\texttt{")
++        latexesc(io, text)
++        _println(io, "}}")
++    end
++    _println(io, "\\end{itemize}\n")
++end
++
++function latex(io::IO, contents::Documents.ContentsNode, page, doc)
++    depth = 1
++    needs_end = false
++    _println(io, "\\begin{itemize}")
++    for (count, path, anchor) in contents.elements
++        header = anchor.object
++        level = Utilities.header_level(header)
++        id = string(hash(string(anchor.id, "-", anchor.nth)))
++        level < depth && _println(io, "\\end{itemize}")
++        level > depth && (_println(io, "\\begin{itemize}"); needs_end = true)
++        _print(io, "\\item \\hyperlink{", id, "}{")
++        latexinline(io, header.text)
++        _println(io, "}")
++        depth = level
++    end
++    needs_end && _println(io, "\\end{itemize}")
++    _println(io, "\\end{itemize}")
++    _println(io)
++end
++
++function latex(io::IO, node::Documents.EvalNode, page, doc)
++    node.result === nothing ? nothing : latex(io, node.result, page, doc)
++end
++
++
++## Basic Nodes. AKA: any other content that hasn't been handled yet.
++
++latex(io::IO, str::AbstractString, page, doc) = _print(io, str)
++
++function latex(io::IO, other, page, doc)
++    _println(io)
++    latex(io, other)
++    _println(io)
++end
++
++latex(io::IO, md::Markdown.MD) = latex(io, md.content)
++
++function latex(io::IO, content::Vector)
++    for c in content
++        latex(io, c)
++    end
++end
++
++function latex(io::IO, h::Markdown.Header{N}) where N
++    tag = DOCUMENT_STRUCTURE[min(io.depth + N - 1, length(DOCUMENT_STRUCTURE))]
++    _print(io, "\\", tag, "{")
++    io.in_header = true
++    latexinline(io, h.text)
++    io.in_header = false
++    _println(io, "}\n")
++end
++
++# Whitelisted lexers.
++const LEXER = Set([
++    "julia",
++    "jlcon",
++])
++
++function latex(io::IO, code::Markdown.Code)
++    language = isempty(code.language) ? "none" : code.language
++    # the julia-repl is called "jlcon" in Pygments
++    language = (language == "julia-repl") ? "jlcon" : language
++    if language in LEXER
++        _print(io, "\n\\begin{minted}")
++        _println(io, "{", language, "}")
++        _println(io, code.code)
++        _println(io, "\\end{minted}\n")
++    else
++        _println(io, "\n\\begin{lstlisting}")
++        _println(io, code.code)
++        _println(io, "\\end{lstlisting}\n")
++    end
++end
++
++function latexinline(io::IO, code::Markdown.Code)
++    _print(io, "\\texttt{")
++    latexesc(io, code.code)
++    _print(io, "}")
++end
++
++function latex(io::IO, md::Markdown.Paragraph)
++    for md in md.content
++        latexinline(io, md)
++    end
++    _println(io, "\n")
++end
++
++function latex(io::IO, md::Markdown.BlockQuote)
++    wrapblock(io, "quote") do
++        latex(io, md.content)
++    end
++end
++
++function latex(io::IO, md::Markdown.Admonition)
++    wrapblock(io, "quote") do
++        wrapinline(io, "textbf") do
++            _print(io, md.title)
++        end
++        _println(io, "\n")
++        latex(io, md.content)
++    end
++end
++
++function latex(io::IO, f::Markdown.Footnote)
++    id = get(io.footnotes, f.id, 1)
++    _print(io, "\\footnotetext[", id, "]{")
++    latex(io, f.text)
++    _println(io, "}")
++end
++
++function latex(io::IO, md::Markdown.List)
++    # `\begin{itemize}` is used here for both ordered and unordered lists since providing
++    # custom starting numbers for enumerated lists is simpler to do by manually assigning
++    # each number to `\item` ourselves rather than using `\setcounter{enumi}{<start>}`.
++    #
++    # For an ordered list starting at 5 the following will be generated:
++    #
++    # \begin{itemize}
++    #   \item[5. ] ...
++    #   \item[6. ] ...
++    #   ...
++    # \end{itemize}
++    #
++    pad = ndigits(md.ordered + length(md.items)) + 2
++    fmt = n -> (Markdown.isordered(md) ? "[$(rpad("$(n + md.ordered - 1).", pad))]" : "")
++    wrapblock(io, "itemize") do
++        for (n, item) in enumerate(md.items)
++            _print(io, "\\item$(fmt(n)) ")
++            latex(io, item)
++            n < length(md.items) && _println(io)
++        end
++    end
++end
++
++
++function latex(io::IO, hr::Markdown.HorizontalRule)
++    _println(io, "{\\rule{\\textwidth}{1pt}}")
++end
++
++# This (equation*, split) math env seems to be the only way to correctly
++# render all the equations in the Julia manual.
++function latex(io::IO, math::Markdown.LaTeX)
++    _print(io, "\\begin{equation*}\n\\begin{split}")
++    _print(io, math.formula)
++    _println(io, "\\end{split}\\end{equation*}")
++end
++
++function latex(io::IO, md::Markdown.Table)
++    _println(io, "\n\\begin{table}[h]")
++    _print(io, "\n\\begin{tabulary}{\\linewidth}")
++    _println(io, "{|", uppercase(join(md.align, '|')), "|}")
++    for (i, row) in enumerate(md.rows)
++        i === 1 && _println(io, "\\hline")
++        for (j, cell) in enumerate(row)
++            j === 1 || _print(io, " & ")
++            latexinline(io, cell)
++        end
++        _println(io, " \\\\")
++        _println(io, "\\hline")
++    end
++    _println(io, "\\end{tabulary}\n")
++    _println(io, "\\end{table}\n")
++end
++
++function latex(io::IO, raw::Documents.RawNode)
++    raw.name === :latex ? _println(io, "\n", raw.text, "\n") : nothing
++end
++
++# Inline Elements.
++
++function latexinline(io::IO, md::Vector)
++    for c in md
++        latexinline(io, c)
++    end
++end
++
++function latexinline(io::IO, md::AbstractString)
++    latexesc(io, md)
++end
++
++function latexinline(io::IO, md::Markdown.Bold)
++    wrapinline(io, "textbf") do
++        latexinline(io, md.text)
++    end
++end
++
++function latexinline(io::IO, md::Markdown.Italic)
++    wrapinline(io, "emph") do
++        latexinline(io, md.text)
++    end
++end
++
++function latexinline(io::IO, md::Markdown.Image)
++    wrapblock(io, "figure") do
++        _println(io, "\\centering")
++        url = if Utilities.isabsurl(md.url)
++            Utilities.warn("Images with absolute URLs not supported in LaTeX output.\n     in $(io.filename)\n     url: $(md.url)")
++            # We nevertheless output an \includegraphics with the URL. The LaTeX build will
++            # then give an error, indicating to the user that something wrong. Only the
++            # warning would be drowned by all the output from LaTeX.
++            md.url
++        elseif startswith(md.url, '/')
++            # URLs starting with a / are assumed to be relative to the document's root
++            normpath(lstrip(md.url, '/'))
++        else
++            normpath(joinpath(dirname(io.filename), md.url))
++        end
++        wrapinline(io, "includegraphics") do
++            _print(io, url)
++        end
++        _println(io)
++        wrapinline(io, "caption") do
++            latexinline(io, md.alt)
++        end
++        _println(io)
++    end
++end
++
++function latexinline(io::IO, f::Markdown.Footnote)
++    id = get!(io.footnotes, f.id, length(io.footnotes) + 1)
++    _print(io, "\\footnotemark[", id, "]")
++end
++
++function latexinline(io::IO, md::Markdown.Link)
++    if io.in_header
++        latexinline(io, md.text)
++    else
++        if occursin(".md#", md.url)
++            file, target = split(md.url, ".md#"; limit = 2)
++            id = string(hash(target))
++            wrapinline(io, "hyperlink") do
++                _print(io, id)
++            end
++            _print(io, "{")
++            latexinline(io, md.text)
++            _print(io, "}")
++        else
++            wrapinline(io, "href") do
++                latexesc(io, md.url)
++            end
++            _print(io, "{")
++            latexinline(io, md.text)
++            _print(io, "}")
++        end
++    end
++end
++
++function latexinline(io, math::Markdown.LaTeX)
++    # Handle MathJax and TeX inconsistency since the first wants `\LaTeX` wrapped
++    # in math delims, whereas actual TeX fails when that is done.
++    math.formula == "\\LaTeX" ? _print(io, math.formula) : _print(io, "\\(", math.formula, "\\)")
++end
++
++function latexinline(io, hr::Markdown.HorizontalRule)
++    _println(io, "\\rule{\\textwidth}{1pt}}")
++end
++
++
++# Metadata Nodes get dropped from the final output for every format but are needed throughout
++# rest of the build and so we just leave them in place and print a blank line in their place.
++latex(io::IO, node::Documents.MetaNode, page, doc) = _println(io, "\n")
++
++# Utilities.
++
++const _latexescape_chars = Dict{Char, AbstractString}(
++    '~' => "{\\textasciitilde}",
++    '^' => "{\\textasciicircum}",
++    '\\' => "{\\textbackslash}",
++    '\'' => "{\\textquotesingle}",
++    '"' => "{\\textquotedbl}",
++    '_' => "{\\_}",
++)
++for ch in "&%\$#_{}"
++    _latexescape_chars[ch] = "\\$ch"
++end
++
++function latexesc(io, s::AbstractString)
++    for ch in s
++        _print(io, get(_latexescape_chars, ch, ch))
++    end
++end
++
++latexesc(s) = sprint(latexesc, s)
++
++function wrapblock(f, io, env)
++    _println(io, "\\begin{", env, "}")
++    f()
++    _println(io, "\\end{", env, "}")
++end
++
++function wrapinline(f, io, cmd)
++    _print(io, "\\", cmd, "{")
++    f()
++    _print(io, "}")
++end
++
++
++function files!(out::Vector, v::Vector, depth)
++    for each in v
++        files!(out, each, depth + 1)
++    end
++    return out
++end
++
++# Tuples come from `hide(page)` with either
++# (visible, nothing,    page,         children) or
++# (visible, page.first, pages.second, children)
++function files!(out::Vector, v::Tuple, depth)
++    files!(out, v[2] == nothing ? v[3] : v[2] => v[3], depth)
++    files!(out, v[4], depth)
++end
++
++files!(out, s::AbstractString, depth) = push!(out, ("", s, depth))
++
++function files!(out, p::Pair{S, T}, depth) where {S <: AbstractString, T <: AbstractString}
++    push!(out, (p.first, p.second, depth))
++end
++
++function files!(out, p::Pair{S, V}, depth) where {S <: AbstractString, V}
++    push!(out, (p.first, "", depth))
++    files!(out, p.second, depth)
++end
++
++files(v::Vector) = files!(Tuple{String, String, Int}[], v, 0)
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..054fc98e2594e2a00841101fcd92ecc764fc40cc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,167 @@@
++"""
++A module for rendering `Document` objects to markdown.
++"""
++module MarkdownWriter
++
++import ...Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Expanders,
++    Formats,
++    Documenter,
++    Utilities
++
++import Markdown
++
++function render(doc::Documents.Document)
++    copy_assets(doc)
++    mime = Formats.mimetype(:markdown)
++    for (src, page) in doc.internal.pages
++        open(Formats.extension(:markdown, page.build), "w") do io
++            for elem in page.elements
++                node = page.mapping[elem]
++                render(io, mime, node, page, doc)
++            end
++        end
++    end
++end
++
++function copy_assets(doc::Documents.Document)
++    Utilities.log(doc, "copying assets to build directory.")
++    assets = joinpath(doc.internal.assets, "mkdocs")
++    if isdir(assets)
++        builddir = joinpath(doc.user.build, "assets")
++        isdir(builddir) || mkdir(builddir)
++        for each in readdir(assets)
++            src = joinpath(assets, each)
++            dst = joinpath(builddir, each)
++            ispath(dst) && Utilities.warn("Overwriting '$dst'.")
++            cp(src, dst; force = true)
++        end
++    else
++        error("assets directory '$(abspath(assets))' is missing.")
++    end
++end
++
++function render(io::IO, mime::MIME"text/plain", vec::Vector, page, doc)
++    for each in vec
++        render(io, mime, each, page, doc)
++    end
++end
++
++function render(io::IO, mime::MIME"text/plain", anchor::Anchors.Anchor, page, doc)
++    println(io, "\n<a id='", anchor.id, "-", anchor.nth, "'></a>")
++    render(io, mime, anchor.object, page, doc)
++end
++
++
++## Documentation Nodes.
++
++function render(io::IO, mime::MIME"text/plain", node::Documents.DocsNodes, page, doc)
++    for node in node.nodes
++        render(io, mime, node, page, doc)
++    end
++end
++
++function render(io::IO, mime::MIME"text/plain", node::Documents.DocsNode, page, doc)
++    # Docstring header based on the name of the binding and it's category.
++    anchor = "<a id='$(node.anchor.id)' href='#$(node.anchor.id)'>#</a>"
++    header = "**`$(node.object.binding)`** &mdash; *$(Utilities.doccat(node.object))*."
++    println(io, anchor, "\n", header, "\n\n")
++    # Body. May contain several concatenated docstrings.
++    renderdoc(io, mime, node.docstr, page, doc)
++end
++
++function renderdoc(io::IO, mime::MIME"text/plain", md::Markdown.MD, page, doc)
++    if haskey(md.meta, :results)
++        # The `:results` field contains a vector of `Docs.DocStr` objects associated with
++        # each markdown object. The `DocStr` contains data such as file and line info that
++        # we need for generating correct source links.
++        for (markdown, result) in zip(md.content, md.meta[:results])
++            render(io, mime, dropheaders(markdown), page, doc)
++            # When a source link is available then print the link.
++            url = Utilities.url(doc.internal.remote, doc.user.repo, result)
++            if url !== nothing
++                link = "<a target='_blank' href='$url' class='documenter-source'>source</a><br>"
++                println(io, "\n", link, "\n")
++            end
++        end
++    else
++        # Docstrings with no `:results` metadata won't contain source locations so we don't
++        # try to print them out. Just print the basic docstring.
++        render(io, mime, dropheaders(md), page, doc)
++    end
++end
++
++function renderdoc(io::IO, mime::MIME"text/plain", other, page, doc)
++    # TODO: properly support non-markdown docstrings at some point.
++    render(io, mime, other, page, doc)
++end
++
++
++## Index, Contents, and Eval Nodes.
++
++function render(io::IO, ::MIME"text/plain", index::Documents.IndexNode, page, doc)
++    for (object, _, page, mod, cat) in index.elements
++        page = Formats.extension(:markdown, page)
++        url = string(page, "#", Utilities.slugify(object))
++        println(io, "- [`", object.binding, "`](", url, ")")
++    end
++    println(io)
++end
++
++function render(io::IO, ::MIME"text/plain", contents::Documents.ContentsNode, page, doc)
++    for (count, path, anchor) in contents.elements
++        path = Formats.extension(:markdown, path)
++        header = anchor.object
++        url    = string(path, '#', anchor.id, '-', anchor.nth)
++        link   = Markdown.Link(header.text, url)
++        level  = Utilities.header_level(header)
++        print(io, "    "^(level - 1), "- ")
++        Markdown.plaininline(io, link)
++        println(io)
++    end
++    println(io)
++end
++
++function render(io::IO, mime::MIME"text/plain", node::Documents.EvalNode, page, doc)
++    node.result === nothing ? nothing : render(io, mime, node.result, page, doc)
++end
++
++
++## Basic Nodes. AKA: any other content that hasn't been handled yet.
++
++function render(io::IO, ::MIME"text/plain", other, page, doc)
++    println(io)
++    Markdown.plain(io, other)
++    println(io)
++end
++
++render(io::IO, ::MIME"text/plain", str::AbstractString, page, doc) = print(io, str)
++
++# Metadata Nodes get dropped from the final output for every format but are needed throughout
++# rest of the build and so we just leave them in place and print a blank line in their place.
++render(io::IO, ::MIME"text/plain", node::Documents.MetaNode, page, doc) = println(io, "\n")
++
++function render(io::IO, ::MIME"text/plain", raw::Documents.RawNode, page, doc)
++    raw.name === :html ? println(io, "\n", raw.text, "\n") : nothing
++end
++
++
++## Markdown Utilities.
++
++# Remove all header nodes from a markdown object and replace them with bold font.
++# Only for use in `text/plain` output, since we'll use some css to make these less obtrusive
++# in the HTML rendering instead of using this hack.
++function dropheaders(md::Markdown.MD)
++    out = Markdown.MD()
++    out.meta = md.meta
++    out.content = map(dropheaders, md.content)
++    out
++end
++dropheaders(h::Markdown.Header) = Markdown.Paragraph([Markdown.Bold(h.text)])
++dropheaders(v::Vector) = map(dropheaders, v)
++dropheaders(other) = other
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..37b518c7f35efe3fa64ce25b517a3379f7bb5823
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,132 @@@
++"""
++A module that provides several renderers for `Document` objects. The supported
++formats are currently:
++
++  * `:markdown` -- the default format.
++  * `:html` -- generates a complete HTML site with navigation and search included.
++  * `:latex` -- generates a PDF using LuaLaTeX.
++
++"""
++module Writers
++
++import ..Documenter:
++    Anchors,
++    Builder,
++    Documents,
++    Expanders,
++    Formats,
++    Documenter,
++    Utilities
++
++import .Utilities: Selectors
++
++#
++# Format selector definitions.
++#
++
++abstract type FormatSelector <: Selectors.AbstractSelector end
++
++abstract type MarkdownFormat <: FormatSelector end
++abstract type LaTeXFormat    <: FormatSelector end
++abstract type HTMLFormat     <: FormatSelector end
++
++Selectors.order(::Type{MarkdownFormat}) = 1.0
++Selectors.order(::Type{LaTeXFormat})    = 2.0
++Selectors.order(::Type{HTMLFormat})     = 3.0
++
++Selectors.matcher(::Type{MarkdownFormat}, fmt, _) = fmt === :markdown
++Selectors.matcher(::Type{LaTeXFormat},    fmt, _) = fmt === :latex
++Selectors.matcher(::Type{HTMLFormat},     fmt, _) = fmt === :html
++
++Selectors.runner(::Type{MarkdownFormat}, _, doc) = MarkdownWriter.render(doc)
++Selectors.runner(::Type{LaTeXFormat},    _, doc) = LaTeXWriter.render(doc)
++Selectors.runner(::Type{HTMLFormat},     _, doc) = HTMLWriter.render(doc)
++
++"""
++Writes a [`Documents.Document`](@ref) object to `.user.build` directory in
++the formats specified in the `.user.format` vector.
++
++Adding additional formats requires adding new `Selector` definitions as follows:
++
++```julia
++abstract type CustomFormat <: FormatSelector end
++
++Selectors.order(::Type{CustomFormat}) = 4.0 # or a higher number.
++Selectors.matcher(::Type{CustomFormat}, fmt, _) = fmt === :custom
++Selectors.runner(::Type{CustomFormat}, _, doc) = CustomWriter.render(doc)
++
++# Definition of `CustomWriter` module below...
++```
++"""
++function render(doc::Documents.Document)
++    # Render each format. Additional formats must define an `order`, `matcher`, `runner`, as
++    # well as their own rendering methods in a separate module.
++    for each in doc.user.format
++        if each === :markdown && !backends_enabled[:markdown]
++            @warn """Deprecated format value :markdown
++
++            The Markdown/MkDocs backend must now be imported from a separate package.
++            Add DocumenterMarkdown to your documentation dependencies and add
++
++                using DocumenterMarkdown
++
++            to your make.jl script.
++
++            Built-in support for format=:markdown will be removed completely in a future
++            Documenter version, causing builds to fail completely.
++
++            See the Output Backends section in the manual for more information.
++            """
++        elseif each === :latex && !backends_enabled[:latex]
++            @warn """Deprecated format value :markdown
++
++            The LaTeX/PDF backend must now be imported from a separate package.
++            Add DocumenterLaTeX to your documentation dependencies and add
++
++                using DocumenterLaTeX
++
++            to your make.jl script.
++
++            Built-in support for format=:latex will be removed completely in a future
++            Documenter version, causing builds to fail completely.
++
++            See the Output Backends section in the manual for more information.
++            """
++        end
++        Selectors.dispatch(FormatSelector, each, doc)
++    end
++    # Revert all local links to their original URLs.
++    for (link, url) in doc.internal.locallinks
++        link.url = url
++    end
++end
++
++include("MarkdownWriter.jl")
++include("HTMLWriter.jl")
++include("LaTeXWriter.jl")
++
++# This is hack to enable shell packages that would behave as in the supplementary Writer
++# modules have been moved out of Documenter.
++#
++# External packages DocumenterMarkdown and DocumenterLaTeX can use the enable_backend
++# function to mark that a certain backend is loaded in backends_enabled. That is used to
++# determine whether a deprecation warning should be printed in the render method above.
++#
++# enable_backend() is not part of the API and will be removed as soon as LaTeXWriter and
++# MarkdownWriter are actually moved out into a separate module (TODO).
++backends_enabled = Dict(
++    :markdown => false,
++    :latex => false
++)
++
++function enable_backend(backend::Symbol)
++    global backends_enabled
++    if backend in keys(backends_enabled)
++        backends_enabled[backend] = true
++    else
++        @error "Unknown backend. Expected one of:" keys(backends_enabled)
++        throw(ArgumentError("Unknown backend $backend."))
++    end
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a71ab866708db34aace194f4498669d10304b717
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,80 @@@
++module DocSystemTests
++
++using Test
++
++import Documenter: Documenter, DocSystem
++
++const alias_of_getdocs = DocSystem.getdocs # NOTE: won't get docstrings if in a @testset
++
++@testset "DocSystem" begin
++    ## Bindings.
++    @test_throws ArgumentError DocSystem.binding(9000)
++    let b = Docs.Binding(@__MODULE__, :DocSystem)
++        @test DocSystem.binding(b) == b
++    end
++    let b = DocSystem.binding(Documenter.Documents.Document)
++        @test b.mod === Documenter.Documents
++        @test b.var === :Document
++    end
++    let b = DocSystem.binding(Documenter)
++        @test b.mod === (Documenter)
++        @test b.var === :Documenter
++    end
++    let b = DocSystem.binding(:Main)
++        # @test b.mod === Main
++        @test b.var === :Main
++    end
++    let b = DocSystem.binding(DocSystem.binding)
++        @test b.mod === DocSystem
++        @test b.var === :binding
++    end
++    let b = DocSystem.binding(Documenter, :Documenter)
++        @test b.mod === (Documenter)
++        @test b.var === :Documenter
++    end
++
++    ## `MultiDoc` object.
++    @test isdefined(DocSystem, :MultiDoc)
++    @test (fieldnames(DocSystem.MultiDoc)...,) == (:order, :docs)
++
++    ## `DocStr` object.
++    @test isdefined(DocSystem, :DocStr)
++    @test (fieldnames(DocSystem.DocStr)...,) == (:text, :object, :data)
++    ## `getdocs`.
++    let b   = DocSystem.binding(DocSystem, :getdocs),
++        d_0 = DocSystem.getdocs(b, Tuple{}),
++        d_1 = DocSystem.getdocs(b),
++        d_2 = DocSystem.getdocs(b, Union{Tuple{Any}, Tuple{Any, Type}}; compare = (==)),
++        d_3 = DocSystem.getdocs(b; modules = Module[Main]),
++        d_4 = DocSystem.getdocs(DocSystem.binding(@__MODULE__, :alias_of_getdocs)),
++        d_5 = DocSystem.getdocs(DocSystem.binding(@__MODULE__, :alias_of_getdocs); aliases = false)
++
++        @test length(d_0) == 0
++        @test length(d_1) == 2
++        @test length(d_2) == 1
++        @test length(d_3) == 0
++        @test length(d_4) == 2
++        @test length(d_5) == 0
++
++        @test d_1[1].data[:binding] == b
++        @test d_1[2].data[:binding] == b
++        @test d_1[1].data[:typesig] == Union{Tuple{Docs.Binding}, Tuple{Docs.Binding, Type}}
++        @test d_1[2].data[:typesig] == Union{Tuple{Any}, Tuple{Any, Type}}
++        @test d_1[1].data[:module]  == DocSystem
++        @test d_1[2].data[:module]  == DocSystem
++
++        @test d_2[1].data[:binding] == b
++        @test d_2[1].data[:typesig] == Union{Tuple{Any}, Tuple{Any, Type}}
++        @test d_2[1].data[:module]  == DocSystem
++
++        @test d_1 == d_4
++        @test d_1 != d_5
++    end
++
++    ## `UnionAll`
++    let b = DocSystem.binding(@__MODULE__, Meta.parse("f(x::T) where T"))
++        @test b.var == :f
++    end
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9d4e264da562cba2b25389b659fd3837df47cf3f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,100 @@@
++module Foo
++"""
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> begin
++          Int64[1, 2, 3, 4] * 2
++       end
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++Int64[1, 2, 3, 4] * 2
++
++# output
++
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest; filter = r"foo"
++julia> println("  foobar")
++  foobaz
++```
++```jldoctest
++julia> 1 + 2
++
++julia> 3 + 4
++```
++"""
++foo() = 1
++
++    """
++    ```jldoctest
++    julia> begin
++              Int64[1, 2, 3, 4] * 2
++           end
++    4-element Array{Int64,1}:
++     1
++     2
++     3
++     4
++    ```
++    ```jldoctest
++    julia> println(); println("foo")
++
++    bar
++    ```
++    """
++    foo(x) = 1
++
++end # module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..aa0ee7d0aa7cf6e4a270435a36fa704f9aa9aad0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,79 @@@
++```@docs
++DocTestsTest.Foo.foo
++```
++
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> begin
++          Int64[1, 2, 3, 4] * 2
++       end
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++Int64[1, 2, 3, 4] * 2
++
++# output
++
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest; filter = r"foo"
++julia> println("  foobar")
++  foobaz
++```
++```jldoctest
++julia> 1 + 2
++
++julia> 3 + 4
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..af883e2e84dc2b460668e1032b122c9f15fe363a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++module DocTestsTest
++using Documenter, Test
++
++println("="^50)
++@info("Testing `doctest = :fix`")
++mktempdir(@__DIR__) do dir
++    srcdir = mktempdir(dir)
++    builddir = mktempdir(dir)
++    cp(joinpath(@__DIR__, "broken.md"), joinpath(srcdir, "index.md"))
++    cp(joinpath(@__DIR__, "broken.jl"), joinpath(srcdir, "src.jl"))
++    include(joinpath(srcdir, "src.jl"))
++    @eval using .Foo
++    # fix up
++    makedocs(sitename="-", modules = [Foo], source = srcdir, build = builddir, doctest = :fix)
++    # test that strict = true works
++    makedocs(sitename="-", modules = [Foo], source = srcdir, build = builddir, strict = true)
++    # also test that we obtain the expected output
++    @test read(joinpath(srcdir, "index.md"), String) ==
++          read(joinpath(@__DIR__, "fixed.md"), String)
++    @test read(joinpath(srcdir, "src.jl"), String) ==
++          read(joinpath(@__DIR__, "fixed.jl"), String)
++end
++@info("Done testing `doctest = :fix`")
++println("="^50)
++
++end # module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6852bf8a5cfa1c0d509af7147f691a83aea14e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,102 @@@
++module Foo
++"""
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++julia> begin
++          Int64[1, 2, 3, 4] * 2
++       end
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++Int64[1, 2, 3, 4] * 2
++
++# output
++
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest; filter = r"foo"
++julia> println("  foobar")
++  foobar
++```
++```jldoctest
++julia> 1 + 2
++3
++
++julia> 3 + 4
++7
++```
++"""
++foo() = 1
++
++    """
++    ```jldoctest
++    julia> begin
++              Int64[1, 2, 3, 4] * 2
++           end
++    4-element Array{Int64,1}:
++     2
++     4
++     6
++     8
++    ```
++    ```jldoctest
++    julia> println(); println("foo")
++
++    foo
++    ```
++    """
++    foo(x) = 1
++
++end # module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c7a87e8be51cc073224db068191607b543305dc3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,81 @@@
++```@docs
++DocTestsTest.Foo.foo
++```
++
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4]
++4-element Array{Int64,1}:
++ 1
++ 2
++ 3
++ 4
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++
++julia> Int64[1, 2, 3, 4] * 2
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++julia> begin
++          Int64[1, 2, 3, 4] * 2
++       end
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest
++Int64[1, 2, 3, 4] * 2
++
++# output
++
++4-element Array{Int64,1}:
++ 2
++ 4
++ 6
++ 8
++```
++```jldoctest; filter = r"foo"
++julia> println("  foobar")
++  foobar
++```
++```jldoctest
++julia> 1 + 2
++3
++
++julia> 3 + 4
++7
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c855f4d990da79d00ec3ee8e0bc4c12ba857b46d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,92 @@@
++module DOMTests
++
++using Test
++
++import Documenter.Utilities.DOM: DOM, @tags, HTMLDocument
++
++@tags div ul li p
++
++@testset "DOM" begin
++    for tag in (:div, :ul, :li, :p)
++        TAG = @eval $tag
++        @test isa(TAG, DOM.Tag)
++        @test TAG.name === tag
++    end
++
++    @test div().name === :div
++    @test div().text == ""
++    @test isempty(div().nodes)
++    @test isempty(div().attributes)
++
++    @test div("...").name === :div
++    @test div("...").text == ""
++    @test length(div("...").nodes) === 1
++    @test div("...").nodes[1].text == "..."
++    @test div("...").nodes[1].name === Symbol("")
++    @test isempty(div("...").attributes)
++
++    @test div[".class"]("...").name === :div
++    @test div[".class"]("...").text == ""
++    @test length(div[".class"]("...").nodes) === 1
++    @test div[".class"]("...").nodes[1].text == "..."
++    @test div[".class"]("...").nodes[1].name === Symbol("")
++    @test length(div[".class"]("...").attributes) === 1
++    @test div[".class"]("...").attributes[1] == (:class => "class")
++    @test div[:attribute].attributes[1] == (:attribute => "")
++    @test div[:attribute => "value"].attributes[1] == (:attribute => "value")
++
++    let d = div(ul(map(li, [string(n) for n = 1:10])))
++        @test d.name === :div
++        @test d.text == ""
++        @test isempty(d.attributes)
++        @test length(d.nodes) === 1
++        let u = d.nodes[1]
++            @test u.name === :ul
++            @test u.text == ""
++            @test isempty(u.attributes)
++            @test length(u.nodes) === 10
++            for n = 1:10
++                let v = u.nodes[n]
++                    @test v.name === :li
++                    @test v.text == ""
++                    @test isempty(v.attributes)
++                    @test length(v.nodes) === 1
++                    @test v.nodes[1].name === Symbol("")
++                    @test v.nodes[1].text == string(n)
++                    @test !isdefined(v.nodes[1], :attributes)
++                    @test !isdefined(v.nodes[1], :nodes)
++                end
++            end
++        end
++    end
++
++    @tags script style img
++
++    @test string(div(p("one"), p("two"))) == "<div><p>one</p><p>two</p></div>"
++    @test string(div[:key => "value"])    == "<div key=\"value\"></div>"
++    @test string(p(" < > & ' \" "))       == "<p> &lt; &gt; &amp; &#39; &quot; </p>"
++    @test string(img[:src => "source"])   == "<img src=\"source\"/>"
++    @test string(img[:none])              == "<img none/>"
++    @test string(script(" < > & ' \" "))  == "<script> < > & ' \" </script>"
++    @test string(style(" < > & ' \" "))   == "<style> < > & ' \" </style>"
++    @test string(script)                  == "<script>"
++
++    function locally_defined()
++        @tags button
++        @test try
++            x = button
++            true
++        catch err
++            false
++        end
++    end
++    @test !isdefined(@__MODULE__, :button)
++    locally_defined()
++    @test !isdefined(@__MODULE__, :button)
++
++    # HTMLDocument
++    @test string(HTMLDocument(div())) == "<!DOCTYPE html>\n<div></div>\n"
++    @test string(HTMLDocument("custom doctype", div())) == "<!DOCTYPE custom doctype>\n<div></div>\n"
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..74e8bf9d23281b66325eaf43e7784b63ca440cd8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++module ErrorsModule
++
++"""
++```jldoctest
++julia> a = 1
++2
++
++```
++
++```jldoctest
++```
++"""
++func(x) = x
++
++end
++
++using Documenter
++
++makedocs(sitename="-", modules = [ErrorsModule])
++
++@test_throws ErrorException makedocs(modules = [ErrorsModule], strict = true)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..71fb398ae079f5a9802cab5d224be33ea0a617e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,99 @@@
++
++```@docs
++missing_doc
++```
++
++```@docs
++parse error
++```
++
++```@meta
++CurrentModule = NonExistantModule
++```
++
++```@autodocs
++Modules = [NonExistantModule]
++```
++
++```@eval
++NonExistantModule
++```
++
++```@docs
++# comment in a @docs block
++```
++
++[`foo(x::Foo)`](@ref) creates an [`UndefVarError`](@ref) when `eval`d
++for the type signature, since `Foo` is not defined.
++
++Numeric literals don't have bindings: [`1`](@ref). Nor [`"strings"`](@ref).
++[`:symbols`] do, however.
++
++Some syntax errors in references will fail with an `ParseError`: [`foo+*bar`](@ref).
++Others, like [`foo(x`](@ref) will give an `:incomplete` expression.
++
++This is the footnote [^1]. And [^another] [^another].
++
++[^1]: one
++
++    [^nested]: a nested footnote
++
++[^another_one]:
++
++    Things! [^1]. [^2].
++
++[^nested]
++
++[^nested]:
++
++    Duplicate [^1] nested footnote.
++
++```@docs
++ErrorsModule.func
++```
++
++```jldoctest
++julia> b = 1
++2
++
++julia> x
++
++julia> x
++ERROR: UndefVarError: x not defined
++
++julia> x
++```
++
++```jldoctest; setup
++julia> 1+1
++2
++```
++```jldoctest invalidkwarg1; setup
++julia> 1+1
++2
++```
++```jldoctest; setup == 1
++julia> 1+1
++2
++```
++```jldoctest invalidkwarg2; setup == 1
++julia> 1+1
++2
++```
++
++```jldoctest; output = false
++foo(a, b) = a * b
++foo(2, 3)
++
++# output
++
++1
++```
++```jldoctest; output = true
++foo(a, b) = a * b
++foo(2, 3)
++
++# output
++
++1
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bbf8f6d3713bb8ba535bf13f9ea17782918bb7b1
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8ffac37899b4bd5fc6d41ef103b8d50a6a4b3def
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c0c8a1be405a1b348389887d404f1cf15e10b81
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5bfa5c5efe81155d91e840c49121523de2e92388
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f0616248579680acba1d3dca8316d449021ba7cb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,147 @@@
++# Defines the modules referred to in the example docs (under src/) and then builds them.
++# It can be called separately to build the examples/, or as part of the test suite.
++#
++# It defines a set of variables (`examples_*`) that can be used in the tests.
++# The `examples_root` should be used to check whether this file has already been included
++# or not and should be kept unique.
++isdefined(@__MODULE__, :examples_root) && error("examples_root is already defined\n$(@__FILE__) included multiple times?")
++
++# The `Mod` and `AutoDocs` modules are assumed to exists in the Main module.
++(@__MODULE__) === Main || error("$(@__FILE__) must be included into Main.")
++
++# Modules `Mod` and `AutoDocs`
++module Mod
++    """
++        func(x)
++
++    [`T`](@ref)
++    """
++    func(x) = x
++
++    """
++        T
++
++    [`func(x)`](@ref)
++    """
++    mutable struct T end
++end
++
++"`AutoDocs` module."
++module AutoDocs
++    module Pages
++        include("pages/a.jl")
++        include("pages/b.jl")
++        include("pages/c.jl")
++        include("pages/d.jl")
++        include("pages/e.jl")
++    end
++
++    "Function `f`."
++    f(x) = x
++
++    "Constant `K`."
++    const K = 1
++
++    "Type `T`."
++    mutable struct T end
++
++    "Macro `@m`."
++    macro m() end
++
++    "Module `A`."
++    module A
++        "Function `A.f`."
++        f(x) = x
++
++        "Constant `A.K`."
++        const K = 1
++
++        "Type `B.T`."
++        mutable struct T end
++
++        "Macro `B.@m`."
++        macro m() end
++    end
++
++    "Module `B`."
++    module B
++        "Function `B.f`."
++        f(x) = x
++
++        "Constant `B.K`."
++        const K = 1
++
++        "Type `B.T`."
++        mutable struct T end
++
++        "Macro `B.@m`."
++        macro m() end
++    end
++end
++
++# Build example docs
++using Documenter
++
++const examples_root = dirname(@__FILE__)
++
++@info("Building mock package docs: MarkdownWriter")
++examples_markdown_doc = makedocs(
++    format = :markdown,
++    debug = true,
++    root  = examples_root,
++    build = "builds/markdown",
++    doctest = false,
++)
++
++
++htmlbuild_pages = Any[
++    "**Home**" => "index.md",
++    "Manual" => [
++        "man/tutorial.md",
++    ],
++    hide("hidden.md"),
++    "Library" => [
++        "lib/functions.md",
++        "lib/autodocs.md",
++    ],
++    hide("Hidden Pages" => "hidden/index.md", Any[
++        "Page X" => "hidden/x.md",
++        "hidden/y.md",
++        "hidden/z.md",
++    ])
++]
++
++@info("Building mock package docs: HTMLWriter / local build")
++examples_html_local_doc = makedocs(
++    debug = true,
++    root  = examples_root,
++    build = "builds/html-local",
++    html_prettyurls = false,
++    doctestfilters = [r"Ptr{0x[0-9]+}"],
++    assets = ["assets/custom.css"],
++    sitename = "Documenter example",
++    pages = htmlbuild_pages,
++
++    linkcheck = true,
++    linkcheck_ignore = [r"(x|y).md", "z.md", r":func:.*"],
++
++    html_edit_branch = nothing,
++)
++
++# Build with pretty URLs and canonical links
++@info("Building mock package docs: HTMLWriter / deployment build")
++examples_html_deploy_doc = makedocs(
++    debug = true,
++    root  = examples_root,
++    build = "builds/html-deploy",
++    html_prettyurls = true,
++    html_canonical = "https://example.com/stable",
++    doctestfilters = [r"Ptr{0x[0-9]+}"],
++    assets = [
++        "assets/favicon.ico",
++        "assets/custom.css"
++    ],
++    sitename = "Documenter example",
++    pages = htmlbuild_pages,
++    doctest = false,
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..087f324fc1cfbd040041b54add8c4f271f4fcc76
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++site_name:        Documenter.jl
++repo_url:         https://github.com/JuliaDocs/Documenter.jl
++site_description: Julia package documentation generator.
++site_author:      Michael Hatherly
++
++theme: material
++
++extra:
++  palette:
++    primary: 'indigo'
++    accent:  'blue'
++
++extra_css:
++  - assets/Documenter.css
++
++markdown_extensions:
++  - codehilite
++  - extra
++  - tables
++  - fenced_code
++
++extra_javascript:
++  - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML
++  - assets/mathjaxhelper.js
++
++docs_dir: 'build'
++
++pages:
++- Home: index.md
++- Manual:
++  - Tutorial: man/tutorial.md
++- Library:
++  - Functions: lib/functions.md
++  - AutoDocs: lib/autodocs.md
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4f06c5f336b1c240ac743d3b7a8b3ba570dd5789
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++
++"""
++`f` from page `a.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time(x)`](@ref)
++- [`T(x)`](@ref)
++- [`T(x, y)`](@ref)
++- [`f(::Integer)`](@ref)
++- [`f(::Any)`](@ref)
++- [`f(::Any, ::Any)`](@ref)
++- [`f(x, y, z)`](@ref)
++
++[^footnote]:
++
++    Footnote contents. [^footnote]
++
++"""
++f(x) = x
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fa67e31185980188851a3af8d35bb16d48d44f47
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++
++"""
++`f` from page `b.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time`](@ref)
++- [`T`](@ref)
++- [`f`](@ref)
++- [`f(::Any)`](@ref)
++- [`f(::Any, ::Any)`](@ref)
++- [`f(::Any, ::Any, ::Any)`](@ref)
++
++"""
++f(x, y) = x + y
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8398bd03faee5fe91ca72b87b856094807ed5e02
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++
++"""
++`f` from page `c.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time`](@ref)
++- [`T`](@ref)
++- [`f`](@ref)
++- [`f(::Any)`](@ref)
++- [`f(::Any, ::Any)`](@ref)
++- [`f(::Any, ::Any, ::Any)`](@ref)
++
++"""
++f(x, y, z) = x + y + z
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..626b85d835a71fa078ee99c6405e5f1cb2757cbe
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++
++"""
++`T` from page `d.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time`](@ref)
++- [`T`](@ref)
++- [`f`](@ref)
++- [`f(x)`](@ref)
++- [`f(x, y)`](@ref)
++- [`f(::Any, ::Any, ::Any)`](@ref)
++
++"""
++mutable struct T end
++
++
++"""
++`T` from page `d.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time`](@ref)
++- [`T(x)`](@ref)
++- [`T(x, y)`](@ref)
++- [`T(x, y, z)`](@ref)
++- [`f`](@ref)
++- [`f(x)`](@ref)
++- [`f(x, y)`](@ref)
++- [`f(::Any, ::Any, ::Any)`](@ref)
++
++"""
++T(x) = T()
++
++"""
++`T` from page `d.jl`.
++
++Links:
++
++- [`ccall`](@ref)
++- [`while`](@ref)
++- [`@time`](@ref)
++- [`T()`](@ref)
++- [`T(x)`](@ref)
++- [`T(x, y)`](@ref)
++- [`T(x, y, z)`](@ref)
++- [`f`](@ref)
++- [`f(x)`](@ref)
++- [`f(x, y)`](@ref)
++- [`f(::Any, ::Any, ::Any)`](@ref)
++
++"""
++T(x, y) = T()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f5f0c2c4b9738d27bb89665061beb373c734a30c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++module E
++
++export f_1, f_2, f_3
++
++"f_1"
++f_1(x) = x
++
++"f_2"
++f_2(x) = x
++
++"f_3"
++f_3(x) = x
++
++
++"g_1"
++g_1(x) = x
++
++"g_2"
++g_2(x) = x
++
++"g_3"
++g_3(x) = x
++
++export T_1
++
++"T_1"
++mutable struct T_1 end
++
++"T_2"
++mutable struct T_2 end
++
++"T_3"
++struct T_3{T} end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4502c59dad7ab4de563517e16ea3eb5324e47420
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++/* custom.css */
++
++center.raw-html-block {
++    color: red;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d465f83ed241feb765efaad6b4b84a39ca879c05
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++// custom javascript
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d7931951e12841f34f95a647d7dc5992259fbd5d
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4ef34f3d44d54a852332a37a802ee6dade413932
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++// overrides Documenter's search.js
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1ffb11ce0063caff85faefea76e65047a7d8c126
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++# Hidden (toplevel)
++
++## Section
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ebab4b2c41d77b78f9e9e998360322410d99afc5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++# Hidden pages
++
++Pages can be hidden with the [`hide`](@ref) function.
++
++## List of hidden pages
++
++- [Hidden page 1](x.md)
++- [Hidden page 2](y.md)
++- [Hidden page 3](z.md)
++
++## Docs for `hide`
++
++```@docs
++hide
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8d5e6a6e68faaba49035b341480d6a60583ba1b6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Hidden 1
++
++## First heading
++## Second heading
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..918e723779371a78ff8d49d27f35cfc36bda432b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++# Hidden 2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..922f3d8ad97982f39df30754fd78f8fe58084064
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++# Hidden 3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a944153ec9a52dff5e34622a2be1d92cd8b6a688
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,447 @@@
++# Documentation
++
++## Index Page
++
++```@contents
++Pages = ["index.md"]
++Depth = 5
++```
++
++## Functions Contents
++
++```@contents
++Pages = ["lib/functions.md"]
++Depth = 3
++```
++
++## Tutorial Contents
++
++```@contents
++Pages = ["man/tutorial.md"]
++```
++
++## Index
++
++```@index
++```
++
++### Embedded `@ref` links headers: [`ccall`](@ref)
++
++[#60](@ref) [#61](@ref)
++
++```@repl
++zeros(5, 5)
++zeros(50, 50)
++```
++
++```@meta
++DocTestSetup = quote
++    using Base
++    x = -3:0.01:3
++    y = -4:0.02:5
++    z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
++end
++```
++
++```jldoctest
++julia> [1.0, 2.0, 3.0]
++3-element Array{Float64,1}:
++ 1.0
++ 2.0
++ 3.0
++
++```
++
++```jldoctest
++julia> println(" "^5)
++
++julia> "\nfoo\n\nbar\n\n\nbaz"
++"\nfoo\n\nbar\n\n\nbaz"
++
++julia> println(ans)
++
++foo
++
++bar
++
++
++baz
++```
++
++  * `one` two three
++  * four `five` six
++
++  * ```
++    one
++    ```
++
++## Raw Blocks
++
++```@raw html
++<center class="raw-html-block">
++    <strong>CENTER</strong>
++</center>
++```
++
++```@raw latex
++\begin{verbatim}
++```
++
++```@raw latex
++\end{verbatim}
++```
++
++# Symbols in doctests
++
++```jldoctest
++julia> a = :undefined
++:undefined
++
++julia> a
++:undefined
++```
++
++# Named doctests
++
++```jldoctest test-one
++julia> a = 1
++1
++```
++
++```jldoctest test-one
++julia> a + 1
++2
++```
++
++# Filtered doctests
++
++## Global
++
++```jldoctest
++julia> print("Ptr{0x123456}")
++Ptr{0x654321}
++```
++
++## Local
++```@meta
++DocTestFilters = [r"foo[a-z]+"]
++```
++
++```jldoctest
++julia> print("foobar")
++foobuu
++```
++
++```@meta
++DocTestFilters = [r"foo[a-z]+", r"[0-9]+"]
++```
++
++```jldoctest
++julia> print("foobar123")
++foobuu456
++```
++
++```@meta
++DocTestFilters = r"foo[a-z]+"
++```
++
++```jldoctest
++julia> print("foobar")
++foobuu
++```
++
++```@meta
++DocTestFilters = []
++```
++
++## Errors
++
++```@meta
++DocTestFilters = [r"Stacktrace:\n \[1\][\s\S]+"]
++```
++
++```jldoctest
++julia> error()
++ERROR:
++Stacktrace:
++ [1] error() at ./thisfiledoesnotexist.jl:123456789
++```
++
++
++```jldoctest
++julia> error()
++ERROR:
++Stacktrace:
++[...]
++```
++
++```@meta
++DocTestFilters = []
++```
++
++# Doctest keyword arguments
++
++```jldoctest; setup = :(f(x) = x^2; g(x) = x)
++julia> f(2)
++4
++
++julia> g(2)
++2
++```
++```jldoctest
++julia> f(2)
++ERROR: UndefVarError: f not defined
++```
++
++```jldoctest PR650; setup = :(f(x) = x^2; g(x) = x)
++julia> f(2)
++4
++
++julia> g(2)
++2
++```
++```jldoctest PR650
++julia> f(2)
++4
++
++julia> g(2)
++2
++```
++
++```jldoctest; filter = [r"foo[a-z]+"]
++julia> print("foobar")
++foobuu
++```
++
++```jldoctest; filter = [r"foo[a-z]+", r"[0-9]+"]
++julia> print("foobar123")
++foobuu456
++```
++
++```jldoctest; filter = r"foo[a-z]+"
++julia> print("foobar")
++foobuu
++```
++
++```jldoctest; filter = r"foo[a-z]+", setup = :(f() = print("foobar"))
++julia> f()
++foobuu
++```
++
++```jldoctest; output = false
++foo(a, b) = a * b
++foo(2, 3)
++
++# output
++
++6
++```
++
++
++# Sanitise module names
++
++```jldoctest
++julia> struct T end
++
++julia> t = T()
++T()
++
++julia> fullname(@__MODULE__)
++(:Main,)
++
++julia> fullname(Base.Broadcast)
++(:Base, :Broadcast)
++
++julia> @__MODULE__
++Main
++```
++
++# Issue398
++
++```@meta
++DocTestSetup = quote
++    module Issue398
++
++    struct TestType{T} end
++
++    function _show end
++    Base.show(io::IO, t::TestType) = _show(io, t)
++
++    macro define_show_and_make_object(x, y)
++        z = Expr(:quote, x)
++        esc(quote
++            $(Issue398)._show(io::IO, t::$(Issue398).TestType{$z}) = print(io, $y)
++            const $x = $(Issue398).TestType{$z}()
++        end)
++    end
++
++    export @define_show_and_make_object
++
++    end # module
++
++    using .Issue398
++end
++```
++
++```jldoctest
++julia> @define_show_and_make_object q "abcd"
++abcd
++```
++
++```@meta
++DocTestSetup = nothing
++```
++
++# Issue653
++
++```jldoctest
++julia> struct MyException <: Exception
++           msg::AbstractString
++       end
++
++julia> function Base.showerror(io::IO, err::MyException)
++           print(io, "MyException: ")
++           print(io, err.msg)
++       end
++
++julia> err = MyException("test exception")
++MyException("test exception")
++
++julia> sprint(showerror, err)
++"MyException: test exception"
++
++julia> throw(MyException("test exception"))
++ERROR: MyException: test exception
++```
++
++# Issue418
++
++```jldoctest
++julia> f(x::Float64) = x
++f (generic function with 1 method)
++
++julia> f("")
++ERROR: MethodError: no method matching f(::String)
++Closest candidates are:
++  f(!Matched::Float64) at none:1
++```
++
++
++```jldoctest
++julia> a = 1
++1
++
++julia> b = 2
++2
++
++julia> ex = :(a + b)
++:(a + b)
++
++julia> eval(ex)
++3
++```
++
++```@repl
++ex = :(1 + 5)
++eval(ex)
++```
++
++```@example
++ex = :(1 + 5)
++eval(ex)
++```
++
++# Issue #793
++```jldoctest
++julia> write("issue793.jl", "\"Hello!\"");
++
++julia> include("issue793.jl")
++"Hello!"
++
++julia> rm("issue793.jl");
++```
++```@repl
++write("issue793.jl", "\"Hello!\"")
++include("issue793.jl")
++rm("issue793.jl")
++```
++```@example
++write("issue793.jl", "\"Hello!\"")
++r = include("issue793.jl")
++rm("issue793.jl")
++r
++```
++
++
++```jldoctest
++julia> a = 1
++1
++
++julia> ans
++1
++```
++
++# Issue513
++
++```jldoctest named
++julia> a = 1
++1
++
++julia> ans
++1
++```
++
++# Filtering of `Main.`
++
++```jldoctest
++julia> struct Point end;
++
++julia> println(Point)
++Point
++
++julia> sqrt(100)
++10.0
++
++julia> sqrt = 4
++ERROR: cannot assign variable Base.sqrt from module Main
++```
++
++```jldoctest
++julia> g(x::Float64, y) = 2x + y
++g (generic function with 1 method)
++
++julia> g(x, y::Float64) = x + 2y
++g (generic function with 2 methods)
++
++julia> g(2.0, 3)
++7.0
++
++julia> g(2, 3.0)
++8.0
++
++julia> g(2.0, 3.0)
++ERROR: MethodError: g(::Float64, ::Float64) is ambiguous. Candidates:
++  g(x, y::Float64) in Main at none:1
++  g(x::Float64, y) in Main at none:1
++Possible fix, define
++  g(::Float64, ::Float64)
++```
++
++# Anonymous function declaration
++
++```jldoc
++julia> x->x # ignore error on 0.7
++#1 (generic function with 1 method)
++```
++
++# Assigning symbols example
++
++```@example
++r = :a
++```
++
++# Bad links (Windows)
++
++* [Colons not allowed on Windows -- `some:path`](some:path)
++* [No "drive" -- `:path`](:path)
++* [Absolute Windows paths -- `X:\some\path`](X:\some\path)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..48149dd4f80e39c164aeaee771aeef511f349e36
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,52 @@@
++# `@autodocs` tests
++
++```@meta
++CurrentModule = Main
++```
++
++## Public
++
++Should include docs for
++
++  * [`AutoDocs.Pages.E.f_1`](@ref)
++  * [`AutoDocs.Pages.E.f_2`](@ref)
++  * [`AutoDocs.Pages.E.f_3`](@ref)
++
++in that order.
++
++```@autodocs
++Modules = [AutoDocs.Pages.E]
++Private = false
++Order = [:function]
++```
++
++## Private
++
++Should include docs for
++
++  * [`AutoDocs.Pages.E.g_1`](@ref)
++  * [`AutoDocs.Pages.E.g_2`](@ref)
++  * [`AutoDocs.Pages.E.g_3`](@ref)
++
++in that order.
++
++```@autodocs
++Modules = [AutoDocs.Pages.E]
++Public = false
++Order = [:function]
++```
++
++## Ordering of Public and Private
++
++Should include docs for
++
++  * [`AutoDocs.Pages.E.T_1`](@ref)
++  * [`AutoDocs.Pages.E.T_2`](@ref)
++
++in that order.
++
++```@autodocs
++Modules = [AutoDocs.Pages.E]
++Order = [:type]
++```
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..62cdc0d79be2dba2d7db650357e04eb91a84679e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++!!! warning\r
++\r
++    This file contains windows line endings. Do not edit.\r
++\r
++```jldoctest\r
++a = 1\r
++b = 2\r
++a + b\r
++\r
++# output\r
++\r
++3\r
++```\r
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9f9256a65677f99572dd067bfba6f75602b6ca52
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,209 @@@
++
++```@meta
++CurrentModule = Main.Mod
++```
++
++# Function Index
++
++```@index
++Pages = ["lib/functions.md"]
++```
++
++# Functions
++
++[`ccall`](@ref), [`func(x)`](@ref), [`T`](@ref), [`for`](@ref), and [`while`](@ref).
++
++```@docs
++func(x)
++T
++ccall
++for
++while
++@time
++@assert
++```
++
++# Foo
++
++```@example
++@show pwd()
++a = 1
++```
++
++...
++
++```@example
++@isdefined a
++```
++
++```@example 1
++f(x) = 2x
++g(x) = 3x
++nothing # hide
++```
++
++```@example 2
++x, y = 1, 2
++println(x, y)
++```
++
++```@example 3
++struct T end
++t = T()
++```
++
++```@example hide-all-the-things
++a = 1#hide
++b = 2# hide
++c = 3#  hide
++d = 4 #hide
++e = 5 # hide
++f = 6 #  hide
++a + b + c + d + e + f
++```
++
++## Foo
++
++```@example 3
++@isdefined T
++@show @isdefined t # hide
++@show typeof(T)
++typeof(t) # hide
++```
++
++```@example 2
++x + y
++```
++
++```@example 1
++f(2), g(2)
++```
++
++### Foo
++
++```@example 2
++x - y
++```
++
++```@example 1
++f(1), g(1)
++```
++
++```@example 3
++using InteractiveUtils
++@which T()
++```
++
++```@example continued-code
++A = 1
++```
++```@example continued-code; continued = true
++for i in 1:3
++```
++```@example
++A = 2
++```
++```@example continued-code; continued = true
++    println(A + i)
++```
++```@example continued-code
++end
++```
++```@example continued-code
++A + 1
++```
++
++#### Foo
++
++```@example
++a = 1
++b = ans
++@assert a === b
++```
++
++```@repl
++using Random    # hide
++Random.seed!(1) # hide
++nothing
++rand()
++a = 1
++println(a)
++b = 2
++a + b
++struct T
++    x :: Int
++    y :: Vector
++end
++x = T(1, [1])
++x.y
++x.x
++```
++
++```@repl 1
++d = 1
++```
++
++```@repl 1
++println(d)
++```
++
++Test setup function
++
++```@setup testsetup
++w = 5
++```
++
++```@example testsetup
++@assert w === 5
++```
++
++```@repl testsetup
++@assert w === 5
++```
++
++# Autodocs
++
++```@meta
++CurrentModule = Main
++```
++
++## AutoDocs Module
++
++```@autodocs
++Modules = [AutoDocs]
++```
++
++## Functions, Modules, and Macros
++
++```@autodocs
++Modules = [AutoDocs.A, AutoDocs.B]
++Order   = [:function, :module, :macro]
++```
++
++## Constants and Types
++
++```@autodocs
++Modules = [AutoDocs.A, AutoDocs.B]
++Order   = [:constant, :type]
++```
++
++## Autodocs by Page
++
++```@autodocs
++Modules = [AutoDocs.Pages]
++Pages = ["a.jl", "b.jl"]
++```
++
++```@autodocs
++Modules = [AutoDocs.Pages]
++Pages = ["c.jl", "d.jl"]
++```
++
++A footnote reference [^footnote].
++
++# Named docstring `@ref`s
++
++  * a normal docstring `@ref` link: [`AutoDocs.Pages.f`](@ref);
++  * a named docstring `@ref` link: [`f`](@ref AutoDocs.Pages.f);
++  * and a link with custom text: [`@time 1 + 2`](@ref @time);
++  * some invalid syntax: [`for i = 1:10; ...`](@ref for).
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0584e1d4ad20e4c2cd2da50b027655c08b50dca4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++csv,data,file
++1,2,3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..935ef3043ba10a9cd91708b8a0f2fd7336977534
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,338 @@@
++# Tutorial
++
++[Documentation](@ref)
++
++[Index](@ref)
++
++[Functions](@ref)
++
++[`Main.Mod.func(x)`](@ref)
++
++[`Main.Mod.T`](@ref)
++
++```jldoctest
++julia> using Base.Meta # `nothing` shouldn't be displayed.
++
++julia> Meta
++Base.Meta
++
++julia> a = 1
++1
++
++julia> b = 2;
++
++julia> a + b
++3
++```
++
++```jldoctest
++a = 1
++b = 2
++a + b
++
++# output
++
++3
++```
++
++```@meta
++DocTestSetup =
++    quote
++        using Documenter
++        using Random
++        Random.seed!(1)
++    end
++```
++
++```jldoctest
++a = 1
++b = 2
++a / b
++
++# output
++
++0.5
++```
++
++```jldoctest
++julia> a = 1;
++
++julia> b = 2
++2
++
++julia> a / b
++0.5
++```
++
++```@eval
++import Markdown
++code = string(sprint(Base.banner), "julia>")
++Markdown.Code(code)
++```
++
++```jldoctest
++julia> # First definition.
++       function f(x, y)
++           x + y
++       end
++       #
++       # Second definition.
++       #
++       struct T
++           x
++       end
++
++julia> @isdefined(f), @isdefined(T) # Check for both definitions.
++(true, true)
++
++julia> import Base
++
++julia> using Base.Meta
++
++julia> r = isexpr(:(using Base.Meta), :using); # Discarded result.
++
++julia> !r
++false
++```
++
++```jldoctest
++julia> for i = 1:5
++           println(i)
++       end
++1
++2
++3
++4
++5
++
++julia> println("Printing with semi-comma ending.");
++Printing with semi-comma ending.
++
++julia> div(1, 0)
++ERROR: DivideError: integer division error
++[...]
++
++julia> println("a"); # Semi-colons *not* on the last expression shouldn't suppress output.
++       println(1)    # ...
++       2             # ...
++a
++1
++2
++
++julia> println("a"); # Semi-colons *not* on the last expression shouldn't suppress output.
++       println(1)    # ...
++       2;            # Only those in the last expression.
++a
++1
++```
++
++```jldoctest
++a = 1
++b = 2; # Semi-colons don't affect script doctests.
++
++# output
++
++2
++```
++
++```@repl 1
++f(x) = (sleep(x); x)
++@time f(0.1);
++```
++
++```@repl 1
++f(0.01)
++div(1, 0)
++```
++
++Make sure that stdout is in the right place (#484):
++
++```@repl 1
++println("---") === nothing
++versioninfo()
++```
++
++```@eval
++1 + 2
++nothing
++```
++
++## Including images with `MIME`
++
++If `show(io, ::MIME, x)` is overloaded for a particular type then `@example` blocks can show the SVG, HTML/JS/CSS, PNG, JPEG, GIF or WebP image as appropriate in the output.
++
++Assuming the following type and method live in the `InlineSVG` module
++
++```julia
++struct SVG
++    code :: String
++end
++Base.show(io, ::MIME"image/svg+xml", svg::SVG) = write(io, svg.code)
++```
++
++.. then we we can invoke and show them with an `@example` block:
++
++```@setup inlinesvg
++module InlineSVG
++export SVG
++mutable struct SVG
++    code :: String
++end
++Base.show(io, ::MIME"image/svg+xml", svg::SVG) = write(io, svg.code)
++end # module
++```
++
++```@example inlinesvg
++using .InlineSVG
++SVG("""
++<svg width="82" height="76">
++  <g style="stroke-width: 3">
++    <circle cx="20" cy="56" r="16" style="stroke: #cb3c33; fill: #d5635c" />
++    <circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" />
++    <circle cx="62" cy="56" r="16" style="stroke: #9558b2; fill: #aa79c1" />
++  </g>
++</svg>
++""")
++```
++
++_Note: we can't define the `show` method in the `@example` block due to the world age
++counter in Julia 0.6 (Documenter's `makedocs` is not aware of any of the new method
++definitions happening in `eval`s)._
++
++We can also show SVG images with interactivity via the `text/html` MIME to display output that combines HTML, JS and CSS. Assume the following type and method live in the `InlineHTML` modeul
++
++```julia
++struct HTML
++    code::String
++end
++Base.show(io, ::MIME"text/html", html::HTML) = write(io, read(html.code))
++```
++
++.. then we can invoke and show them with an `@example` block (try mousing over the circles to see the applied style):
++
++```@setup inlinehtml
++module InlineHTML
++mutable struct HTML
++    code::String
++end
++Base.show(io, ::MIME"text/html", html::HTML) = write(io, html.code)
++end # module
++```
++
++```@example inlinehtml
++using .InlineHTML
++InlineHTML.HTML("""
++<script>
++  function showStyle(e) {
++    document.querySelector("#inline-html-style").innerHTML = e.getAttribute('style');
++  }
++</script>
++<svg width="100%" height="76">
++  <g style="stroke-width: 3">
++    <circle cx="20" cy="56" r="16" style="stroke: #cb3c33; fill: #d5635c" onmouseover="showStyle(this)"/>
++    <circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" onmouseover="showStyle(this)"/>
++    <circle cx="62" cy="56" r="16" style="stroke: #9558b2; fill: #aa79c1" onmouseover="showStyle(this)"/>
++    <text id="inline-html-style" x="90", y="20"></text>
++  </g>
++</svg>
++""")
++```
++
++The same mechanism also works for PNG files. Assuming again the following
++type and method live in the `InlinePNG` module
++
++```julia
++struct PNG
++    filename::String
++end
++Base.show(io, ::MIME"image/png", png::PNG) = write(io, read(png.filename))
++```
++
++.. then we can invoke and show them with an `@example` block:
++
++```@setup inlinepng
++module InlinePNG
++export PNG
++mutable struct PNG
++    filename::String
++end
++Base.show(io, ::MIME"image/png", png::PNG) = write(io, read(png.filename))
++end # module
++```
++
++```@example inlinepng
++using Documenter
++using .InlinePNG
++PNG(joinpath(dirname(pathof(Documenter)), "..", "test", "examples", "images", "logo.png"))
++```
++
++
++.. and JPEG, GIF and WebP files:
++
++```@setup inlinewebpgifjpeg
++module InlineWEBPGIFJPEG
++export WEBP, GIF, JPEG
++mutable struct WEBP
++    filename :: String
++end
++Base.show(io, ::MIME"image/webp", image::WEBP) = write(io, read(image.filename))
++mutable struct GIF
++    filename :: String
++end
++Base.show(io, ::MIME"image/gif", image::GIF) = write(io, read(image.filename))
++mutable struct JPEG
++    filename :: String
++end
++Base.show(io, ::MIME"image/jpeg", image::JPEG) = write(io, read(image.filename))
++end # module
++```
++
++```@example inlinewebpgifjpeg
++using Documenter
++using .InlineWEBPGIFJPEG
++WEBP(joinpath(dirname(pathof(Documenter)), "..", "test", "examples", "images", "logo.webp"))
++```
++
++```@example inlinewebpgifjpeg
++GIF(joinpath(dirname(pathof(Documenter)), "..", "test", "examples", "images", "logo.gif"))
++```
++
++```@example inlinewebpgifjpeg
++JPEG(joinpath(dirname(pathof(Documenter)), "..", "test", "examples", "images", "logo.jpg"))
++```
++
++## Interacting with external files
++
++You can also write output files and then refer to them in the document:
++
++```@example
++open("julia.svg", "w") do io
++    write(io, """
++    <svg width="82" height="76" xmlns="http://www.w3.org/2000/svg">
++      <g style="stroke-width: 3">
++        <circle cx="20" cy="56" r="16" style="stroke: #cb3c33; fill: #d5635c" />
++        <circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" />
++        <circle cx="62" cy="56" r="16" style="stroke: #9558b2; fill: #aa79c1" />
++      </g>
++    </svg>
++    """)
++end
++```
++
++![Julia circles](julia.svg)
++
++Dowload [`data.csv`](data.csv).
++
++
++## [Links](../index.md) in headers
++
++... are dropped in the navigation links.
++
++
++## Embedding raw HTML
++
++Below is a nicely rendered version of `^D`:
++
++```@raw html
++<kbd>Ctrl</kbd> + <kbd>D</kbd>
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..446190b7cc4224565e438520f37f1de36f5e0875
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,93 @@@
++using Test
++
++# When the file is run separately we need to include make.jl which actually builds
++# the docs and defines a few modules that are referred to in the docs. The make.jl
++# has to be expected in the context of the Main module.
++if (@__MODULE__) === Main && !@isdefined examples_root
++    include("make.jl")
++elseif (@__MODULE__) !== Main && isdefined(Main, :examples_root)
++    using Documenter
++    const examples_root = Main.examples_root
++elseif (@__MODULE__) !== Main && !isdefined(Main, :examples_root)
++    error("examples/make.jl has not been loaded into Main.")
++end
++
++@testset "Examples" begin
++    @testset "Markdown" begin
++        doc = Main.examples_markdown_doc
++
++        @test isa(doc, Documenter.Documents.Document)
++
++        let build_dir  = joinpath(examples_root, "builds", "markdown"),
++            source_dir = joinpath(examples_root, "src")
++
++            @test isdir(build_dir)
++            @test isdir(joinpath(build_dir, "assets"))
++            @test isdir(joinpath(build_dir, "lib"))
++            @test isdir(joinpath(build_dir, "man"))
++
++            @test isfile(joinpath(build_dir, "index.md"))
++            @test isfile(joinpath(build_dir, "assets", "mathjaxhelper.js"))
++            @test isfile(joinpath(build_dir, "assets", "Documenter.css"))
++            @test isfile(joinpath(build_dir, "assets", "custom.css"))
++            @test isfile(joinpath(build_dir, "assets", "custom.js"))
++            @test isfile(joinpath(build_dir, "lib", "functions.md"))
++            @test isfile(joinpath(build_dir, "man", "tutorial.md"))
++            @test isfile(joinpath(build_dir, "man", "data.csv"))
++            @test isfile(joinpath(build_dir, "man", "julia.svg"))
++
++            @test (==)(
++                read(joinpath(source_dir, "man", "data.csv"), String),
++                read(joinpath(build_dir,  "man", "data.csv"), String),
++            )
++        end
++
++        @test doc.user.root   == examples_root
++        @test doc.user.source == "src"
++        @test doc.user.build  == "builds/markdown"
++        @test doc.user.clean  == true
++        @test doc.user.format == [:markdown]
++
++        @test realpath(doc.internal.assets) == realpath(joinpath(dirname(@__FILE__), "..", "..", "assets"))
++
++        @test length(doc.internal.pages) == 10
++
++        let headers = doc.internal.headers
++            @test Documenter.Anchors.exists(headers, "Documentation")
++            @test Documenter.Anchors.exists(headers, "Documentation")
++            @test Documenter.Anchors.exists(headers, "Index-Page")
++            @test Documenter.Anchors.exists(headers, "Functions-Contents")
++            @test Documenter.Anchors.exists(headers, "Tutorial-Contents")
++            @test Documenter.Anchors.exists(headers, "Index")
++            @test Documenter.Anchors.exists(headers, "Tutorial")
++            @test Documenter.Anchors.exists(headers, "Function-Index")
++            @test Documenter.Anchors.exists(headers, "Functions")
++            @test Documenter.Anchors.isunique(headers, "Functions")
++            @test Documenter.Anchors.isunique(headers, "Functions", joinpath("builds", "markdown", "lib", "functions.md"))
++            let name = "Foo", path = joinpath("builds", "markdown", "lib", "functions.md")
++                @test Documenter.Anchors.exists(headers, name, path)
++                @test !Documenter.Anchors.isunique(headers, name)
++                @test !Documenter.Anchors.isunique(headers, name, path)
++                @test length(headers.map[name][path]) == 4
++            end
++        end
++
++        @test length(doc.internal.objects) == 38
++    end
++
++    @testset "HTML: local" begin
++        doc = Main.examples_html_local_doc
++
++        @test isa(doc, Documenter.Documents.Document)
++
++        # TODO: test the HTML build
++    end
++
++    @testset "HTML: deploy" begin
++        doc = Main.examples_html_deploy_doc
++
++        @test isa(doc, Documenter.Documents.Document)
++
++        # TODO: test the HTML build with pretty URLs
++    end
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cdfb6ebc771881a0de47002778c44a50cf94dad7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,59 @@@
++module LaTeXFormatTests
++
++using Test
++
++using Documenter
++
++# Documenter package docs
++@info("Building Documenter's docs with LaTeX.")
++const Documenter_root = normpath(joinpath(dirname(@__FILE__), "..", "..", "docs"))
++doc = makedocs(
++    debug = true,
++    root = Documenter_root,
++    modules = [Documenter],
++    clean = false,
++    format = :latex,
++    sitename = "Documenter.jl",
++    authors = "Michael Hatherly, Morten Piibeleht, and contributors.",
++    pages = [
++        "Home" => "index.md",
++        "Manual" => Any[
++            "Guide" => "man/guide.md",
++            "man/examples.md",
++            "man/syntax.md",
++            "man/doctests.md",
++            "man/latex.md",
++            "man/hosting.md",
++            "man/other-formats.md",
++        ],
++        "Library" => Any[
++            "Public" => "lib/public.md",
++            hide("Internals" => "lib/internals.md", Any[
++                "lib/internals/anchors.md",
++                "lib/internals/builder.md",
++                "lib/internals/cross-references.md",
++                "lib/internals/docchecks.md",
++                "lib/internals/docsystem.md",
++                "lib/internals/doctests.md",
++                "lib/internals/documenter.md",
++                "lib/internals/documentertools.md",
++                "lib/internals/documents.md",
++                "lib/internals/dom.md",
++                "lib/internals/expanders.md",
++                "lib/internals/formats.md",
++                "lib/internals/mdflatten.md",
++                "lib/internals/selectors.md",
++                "lib/internals/textdiff.md",
++                "lib/internals/utilities.md",
++                "lib/internals/writers.md",
++            ])
++        ],
++        "contributing.md",
++    ]
++)
++
++@testset "LaTeX" begin
++    @test isa(doc, Documenter.Documents.Document)
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6933c6372f75a53bf5efa51b1bf12b7e6cfbd2eb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++module MarkdownFormatTests
++
++using Test
++using Random
++
++using Documenter
++
++# Documenter package docs
++@info("Building Documenter's docs with Markdown.")
++const Documenter_root = normpath(joinpath(@__DIR__, "..", "..", "docs"))
++build_dir_relpath = relpath(joinpath(@__DIR__, "builds/markdown"), Documenter_root)
++doc = makedocs(
++    format = :markdown,
++    debug   = true,
++    root    = Documenter_root,
++    modules = Documenter,
++    build   = build_dir_relpath,
++)
++
++@testset "Markdown" begin
++    @test isa(doc, Documenter.Documents.Document)
++
++    let build_dir  = joinpath(Documenter_root, build_dir_relpath),
++        source_dir = joinpath(Documenter_root, "src")
++        @test isdir(build_dir)
++        @test isdir(joinpath(build_dir, "assets"))
++        @test isdir(joinpath(build_dir, "lib"))
++        @test isdir(joinpath(build_dir, "man"))
++
++        @test isfile(joinpath(build_dir, "index.md"))
++        @test isfile(joinpath(build_dir, "assets", "mathjaxhelper.js"))
++        @test isfile(joinpath(build_dir, "assets", "Documenter.css"))
++    end
++
++    @test doc.user.root   == Documenter_root
++    @test doc.user.source == "src"
++    @test doc.user.build  == build_dir_relpath
++    @test doc.user.clean  == true
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..abc58aa706da442b5d7b1503a99746d333cb4aed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,89 @@@
++module HTMLWriterTests
++
++using Test
++
++import Documenter.Writers.HTMLWriter: jsescape, generate_version_file, expand_versions
++
++function verify_version_file(versionfile, entries)
++    @test isfile(versionfile)
++    content = read(versionfile, String)
++    idx = 1
++    for entry in entries
++        i = findnext(entry, content, idx)
++        @test i !== nothing
++        idx = last(i)
++    end
++end
++
++@testset "HTMLWriter" begin
++    @test jsescape("abc123") == "abc123"
++    @test jsescape("▶αβγ") == "▶αβγ"
++    @test jsescape("") == ""
++
++    @test jsescape("a\nb") == "a\\nb"
++    @test jsescape("\r\n") == "\\r\\n"
++    @test jsescape("\\") == "\\\\"
++
++    @test jsescape("\"'") == "\\\"\\'"
++
++    # Ref: #639
++    @test jsescape("\u2028") == "\\u2028"
++    @test jsescape("\u2029") == "\\u2029"
++    @test jsescape("policy to
 delete.") == "policy to\\u2028 delete."
++
++    mktempdir() do tmpdir
++        versionfile = joinpath(tmpdir, "versions.js")
++        versions = ["stable", "dev",
++                    "2.1.1", "v2.1.0", "v2.0.1", "v2.0.0",
++                    "1.1.1", "v1.1.0", "v1.0.1", "v1.0.0",
++                    "0.1.1", "v0.1.0"] # note no `v` on first ones
++        cd(tmpdir) do
++            for version in versions
++                mkdir(version)
++            end
++        end
++
++        # expanding versions
++        versions = ["stable" => "v^", "v#.#", "dev" => "dev"] # default to makedocs
++        entries, symlinks = expand_versions(tmpdir, versions)
++        @test entries == ["stable", "v2.1", "v2.0", "v1.1", "v1.0", "v0.1", "dev"]
++        @test symlinks == ["stable"=>"2.1.1", "v2.1"=>"2.1.1", "v2.0"=>"v2.0.1",
++                           "v1.1"=>"1.1.1", "v1.0"=>"v1.0.1", "v0.1"=>"0.1.1",
++                           "v2"=>"2.1.1", "v1"=>"1.1.1", "v2.1.1"=>"2.1.1",
++                           "v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1"]
++        generate_version_file(versionfile, entries)
++        verify_version_file(versionfile, entries)
++
++        versions = ["v#"]
++        entries, symlinks = expand_versions(tmpdir, versions)
++        @test entries == ["v2.1", "v1.1"]
++        @test symlinks == ["v2.1"=>"2.1.1", "v1.1"=>"1.1.1", "v2"=>"2.1.1", "v1"=>"1.1.1",
++                           "v2.0"=>"v2.0.1", "v1.0"=>"v1.0.1", "v0.1"=>"0.1.1",
++                           "v2.1.1"=>"2.1.1", "v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1"]
++        generate_version_file(versionfile, entries)
++        verify_version_file(versionfile, entries)
++
++        versions = ["v#.#.#"]
++        entries, symlinks = expand_versions(tmpdir, versions)
++        @test entries == ["v2.1.1", "v2.1.0", "v2.0.1", "v2.0.0", "v1.1.1", "v1.1.0",
++                          "v1.0.1", "v1.0.0", "v0.1.1", "v0.1.0"]
++        @test symlinks == ["v2.1.1"=>"2.1.1", "v1.1.1"=>"1.1.1", "v0.1.1"=>"0.1.1",
++                           "v2"=>"2.1.1", "v1"=>"1.1.1", "v2.1"=>"2.1.1",
++                           "v2.0"=>"v2.0.1", "v1.1"=>"1.1.1", "v1.0"=>"v1.0.1", "v0.1"=>"0.1.1"]
++        generate_version_file(versionfile, entries)
++        verify_version_file(versionfile, entries)
++
++        versions = ["v^", "devel" => "dev", "foobar", "foo" => "bar"]
++        entries, symlinks = expand_versions(tmpdir, versions)
++        @test entries == ["v2.1", "devel"]
++        @test ("v2.1" => "2.1.1") in symlinks
++        @test ("devel" => "dev") in symlinks
++        generate_version_file(versionfile, entries)
++        verify_version_file(versionfile, entries)
++
++        versions = ["stable" => "v^", "dev" => "stable"]
++        @test_throws ArgumentError expand_versions(tmpdir, versions)
++    end
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0f78ee4a4a66d48a2f669bc4f3a1afb45ce0b894
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,68 @@@
++module MDFlattenTests
++
++using Test
++
++import Markdown
++using Documenter.Utilities.MDFlatten
++
++@testset "MDFlatten" begin
++    @test mdflatten(Markdown.Paragraph("...")) == "..."
++    @test mdflatten(Markdown.Header{1}("...")) == "..."
++
++    # a simple test for blocks in top-level (each gets two newline appended to it)
++    @test mdflatten(Markdown.parse("# Test\nTest")) == "Test\n\nTest\n\n"
++    block_md = Markdown.parse("""
++    # MDFlatten test
++
++
++    ^^^ Ignoring extra whitespace.
++
++    ```markdown
++    code
++    is forwarded as **is**
++    ```
++    """)
++    block_text = """
++    MDFlatten test
++
++    ^^^ Ignoring extra whitespace.
++
++    code
++    is forwarded as **is**
++
++    """
++    @test mdflatten(block_md) == block_text
++
++    # blocks
++    @test mdflatten(Markdown.parse("> Test\n> Test\n\n> Test")) == "Test Test\n\nTest\n\n"
++    @test mdflatten(Markdown.parse("HRs\n\n---\n\nto whitespace")) == "HRs\n\n\n\nto whitespace\n\n"
++    @test mdflatten(Markdown.parse("HRs\n\n---\n\nto whitespace")) == "HRs\n\n\n\nto whitespace\n\n"
++    @test mdflatten(Markdown.parse("HRs\n\n---\n\nto whitespace")) == "HRs\n\n\n\nto whitespace\n\n"
++
++    # test some inline blocks
++    @test mdflatten(Markdown.parse("`code` *em* normal **strong**")) == "code em normal strong\n\n"
++    @test mdflatten(Markdown.parse("[link text *parsed*](link/itself/ignored)")) == "link text parsed\n\n"
++    @test mdflatten(Markdown.parse("- a\n- b\n- c")) == "a\nb\nc\n\n"
++    @test mdflatten(Markdown.parse("A | B\n---|---\naa|bb\ncc | dd")) == "A B\naa bb\ncc dd\n\n"
++
++    # Math
++    @test mdflatten(Markdown.parse("\$e=mc^2\$")) == "e=mc^2\n\n"
++    # backticks and blocks for math only in 0.5, i.e. these fail on 0.4
++    @test mdflatten(Markdown.parse("``e=mc^2``")) == "e=mc^2\n\n"
++    @test mdflatten(Markdown.parse("```math\n\\(m+n)(m-n)\nx=3\\sin(x)\n```")) == "(m+n)(m-n)\nx=3sin(x)\n\n"
++
++    # symbols in markdown
++    @test mdflatten(Markdown.parse("A \$B C")) == "A B C\n\n"
++
++    # linebreaks
++    @test mdflatten(Markdown.parse("A\\\nB")) == "A\nB\n\n"
++
++    # footnotes
++    @test mdflatten(Markdown.parse("[^name]")) == "[name]\n\n"
++    @test mdflatten(Markdown.parse("[^name]:**Strong** text.")) == "[name]: Strong text.\n\n"
++
++    # admonitions
++    @test mdflatten(Markdown.parse("!!! note \"Admonition Title\"\n    Test")) == "note: Admonition Title\nTest\n\n"
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..edf748d0b40704ac3aadca55a3ccbd8243edc9a2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++module MissingDocs
++    export f
++
++    "exported"
++    f(x) = x
++
++    "unexported"
++    g(x) = x
++end
++
++using Documenter
++
++for sym in [:none, :exports]
++    makedocs(
++        root = dirname(@__FILE__),
++        source = joinpath("src", string(sym)),
++        build = joinpath("build", string(sym)),
++        modules = MissingDocs,
++        checkdocs = sym,
++        sitename = "MissingDocs Checks",
++    )
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..77461048d6cb34055785dc3cb2b4e5f04377ae16
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# MissingDocs Exports
++
++```@docs
++Main.MissingDocs.f
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9b7ae05caf33353fefda9c3642e276353deb2cc3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# MissingDocs None
++
++```@docs
++```
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6716e90ddc8c50b731216aafd1629805f6126bcd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++module NavNodeTests
++
++using Test
++
++import Documenter: Documents, Builder
++import Documenter.Documents: NavNode
++
++mutable struct FakeDocumentInternal
++    pages   :: Dict{String, Nothing}
++    navlist :: Vector{NavNode}
++    FakeDocumentInternal() = new(Dict(), [])
++end
++mutable struct FakeDocument
++    internal :: FakeDocumentInternal
++    FakeDocument() = new(FakeDocumentInternal())
++end
++
++@testset "NavNode" begin
++    @test fieldtype(FakeDocumentInternal, :navlist) == fieldtype(Documents.Internal, :navlist)
++
++    pages = [
++        "page1.md",
++        "Page2" => "page2.md",
++        "Section" => [
++            "page3.md",
++            "Page4" => "page4.md",
++            "Subsection" => [
++                "page5.md",
++            ],
++        ],
++        "page6.md",
++    ]
++    doc = FakeDocument()
++    doc.internal.pages = Dict(map(i -> "page$i.md" => nothing, 1:8))
++    navtree = Builder.walk_navpages(pages, nothing, doc)
++    navlist = doc.internal.navlist
++
++    @test length(navlist) == 6
++    for (i,navnode) in enumerate(navlist)
++        @test navnode.page == "page$i.md"
++    end
++
++    @test isa(navtree, Vector{NavNode})
++    @test length(navtree) == 4
++    @test navtree[1] === navlist[1]
++    @test navtree[2] === navlist[2]
++    @test navtree[4] === navlist[6]
++
++    section = navtree[3]
++    @test section.title_override == "Section"
++    @test section.page === nothing
++    @test length(section.children) == 3
++
++    navpath = Documents.navpath(navlist[5])
++    @test length(navpath) == 3
++    @test navpath[1] === section
++    @test navpath[3] === navlist[5]
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..81f0f9e3570fd88e3d8fbbbd92012f06f5b09f29
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++using Documenter
++
++makedocs(
++    debug = true,
++    doctestfilters = [r"Ptr{0x[0-9]+}"],
++    sitename = "Documenter example",
++    pages = ["index.md"],
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3d93078a6f53755ba3e25ea727dd94dd299fe863
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++# Test
++
++....
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fbb3bf8811d2a54c3fd5ba562e25ad47f970e9b7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++mktempdir() do tmpdir
++    @info("Buiding 'nongit' in $tmpdir")
++    cp(joinpath(@__DIR__, "docs"), joinpath(tmpdir, "docs"))
++    include(joinpath(tmpdir, "docs/make.jl"))
++    # Copy the build/ directory back so that it would be possible to inspect the output.
++    cp(joinpath(tmpdir, "docs/build"), joinpath(@__DIR__, "build"); force=true)
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..482c81b97616d1ff5dd077fe4902e4414f0dc713
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,67 @@@
++using Test
++
++# Build the example docs
++include("examples/make.jl")
++
++# Test missing docs
++include("missingdocs/make.jl")
++
++# Primary @testset
++
++# Error reporting.
++println("="^50)
++@info("The following errors are expected output.")
++include(joinpath("errors", "make.jl"))
++@info("END of expected error output.")
++println("="^50)
++
++@testset "Documenter" begin
++    # Unit tests for module internals.
++    include("utilities.jl")
++
++    # NavNode tests.
++    include("navnode.jl")
++
++    # DocSystem unit tests.
++    include("docsystem.jl")
++
++    # DocTest unit tests.
++    include("doctests/doctests.jl")
++
++    # DOM Tests.
++    include("dom.jl")
++
++    # MDFlatten tests.
++    include("mdflatten.jl")
++
++    # HTMLWriter
++    include("htmlwriter.jl")
++
++    # Mock package docs.
++    include("examples/tests.jl")
++
++    # Documenter package docs with other formats.
++    include("formats/markdown.jl")
++    include("formats/latex.jl")
++
++    # A simple build outside of a Git repository
++    include("nongit/tests.jl")
++end
++
++# Additional tests
++
++## `Markdown.MD` to `DOM.Node` conversion tests.
++module MarkdownToNode
++    import Documenter.DocSystem
++    import Documenter.Writers.HTMLWriter: mdconvert
++
++    # Exhaustive Conversion from Markdown to Nodes.
++    for mod in Base.Docs.modules
++        for (binding, multidoc) in DocSystem.getmeta(mod)
++            for (typesig, docstr) in multidoc.docs
++                md = DocSystem.parsedoc(docstr)
++                string(mdconvert(md))
++            end
++        end
++    end
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c00c547bc505c4cfdea3e2f9a5bb5dff6f88bc65
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,223 @@@
++module UtilitiesTests
++
++using Test
++import Base64: stringmime
++
++import Documenter
++
++module UnitTests
++    module SubModule end
++
++    # Does `submodules` collect *all* the submodules?
++    module A
++        module B
++            module C
++                module D end
++            end
++        end
++    end
++
++    mutable struct T end
++    mutable struct S{T} end
++
++    "Documenter unit tests."
++    Base.length(::T) = 1
++
++    f(x) = x
++
++    const pi = 3.0
++end
++
++module OuterModule
++module InnerModule
++import ..OuterModule
++export OuterModule
++end
++end
++
++module ExternalModule end
++module ModuleWithAliases
++using ..ExternalModule
++Y = ExternalModule
++module A
++    module B
++    const X = Main
++    end
++end
++end
++
++@testset "Utilities" begin
++    let doc = @doc(length)
++        a = Documenter.Utilities.filterdocs(doc, Set{Module}())
++        b = Documenter.Utilities.filterdocs(doc, Set{Module}([UnitTests]))
++        c = Documenter.Utilities.filterdocs(doc, Set{Module}([Base]))
++        d = Documenter.Utilities.filterdocs(doc, Set{Module}([UtilitiesTests]))
++
++        @test a !== nothing
++        @test a === doc
++        @test b !== nothing
++        @test occursin("Documenter unit tests.", stringmime("text/plain", b))
++        @test c !== nothing
++        @test !occursin("Documenter unit tests.", stringmime("text/plain", c))
++        @test d === nothing
++    end
++
++    # Documenter.Utilities.issubmodule
++    @test Documenter.Utilities.issubmodule(Main, Main) === true
++    @test Documenter.Utilities.issubmodule(UnitTests, UnitTests) === true
++    @test Documenter.Utilities.issubmodule(UnitTests.SubModule, Main) === true
++    @test Documenter.Utilities.issubmodule(UnitTests.SubModule, UnitTests) === true
++    @test Documenter.Utilities.issubmodule(UnitTests.SubModule, Base) === false
++    @test Documenter.Utilities.issubmodule(UnitTests, UnitTests.SubModule) === false
++
++    @test UnitTests.A in Documenter.Utilities.submodules(UnitTests.A)
++    @test UnitTests.A.B in Documenter.Utilities.submodules(UnitTests.A)
++    @test UnitTests.A.B.C in Documenter.Utilities.submodules(UnitTests.A)
++    @test UnitTests.A.B.C.D in Documenter.Utilities.submodules(UnitTests.A)
++    @test OuterModule in Documenter.Utilities.submodules(OuterModule)
++    @test OuterModule.InnerModule in Documenter.Utilities.submodules(OuterModule)
++    @test length(Documenter.Utilities.submodules(OuterModule)) == 2
++    @test Documenter.Utilities.submodules(ModuleWithAliases) == Set([ModuleWithAliases, ModuleWithAliases.A, ModuleWithAliases.A.B])
++
++    @test Documenter.Utilities.isabsurl("file.md") === false
++    @test Documenter.Utilities.isabsurl("../file.md") === false
++    @test Documenter.Utilities.isabsurl(".") === false
++    @test Documenter.Utilities.isabsurl("https://example.org/file.md") === true
++    @test Documenter.Utilities.isabsurl("http://example.org") === true
++    @test Documenter.Utilities.isabsurl("ftp://user:pw@example.org") === true
++    @test Documenter.Utilities.isabsurl("/fs/absolute/path") === false
++
++    @test Documenter.Utilities.doccat(UnitTests) == "Module"
++    @test Documenter.Utilities.doccat(UnitTests.T) == "Type"
++    @test Documenter.Utilities.doccat(UnitTests.S) == "Type"
++    @test Documenter.Utilities.doccat(UnitTests.f) == "Function"
++    @test Documenter.Utilities.doccat(UnitTests.pi) == "Constant"
++
++    # repo type
++    @test Documenter.Utilities.repo_host_from_url("https://bitbucket.org/somerepo") == Documenter.Utilities.RepoBitbucket
++    @test Documenter.Utilities.repo_host_from_url("https://www.bitbucket.org/somerepo") == Documenter.Utilities.RepoBitbucket
++    @test Documenter.Utilities.repo_host_from_url("http://bitbucket.org/somethingelse") == Documenter.Utilities.RepoBitbucket
++    @test Documenter.Utilities.repo_host_from_url("http://github.com/Whatever") == Documenter.Utilities.RepoGithub
++    @test Documenter.Utilities.repo_host_from_url("https://github.com/Whatever") == Documenter.Utilities.RepoGithub
++    @test Documenter.Utilities.repo_host_from_url("https://www.github.com/Whatever") == Documenter.Utilities.RepoGithub
++    @test Documenter.Utilities.repo_host_from_url("https://gitlab.com/Whatever") == Documenter.Utilities.RepoGitlab
++
++    # line range
++    let formatting = Documenter.Utilities.LineRangeFormatting(Documenter.Utilities.RepoGithub)
++        @test Documenter.Utilities.format_line(1:1, formatting) == "L1"
++        @test Documenter.Utilities.format_line(123:123, formatting) == "L123"
++        @test Documenter.Utilities.format_line(2:5, formatting) == "L2-L5"
++        @test Documenter.Utilities.format_line(100:9999, formatting) == "L100-L9999"
++    end
++
++    let formatting = Documenter.Utilities.LineRangeFormatting(Documenter.Utilities.RepoGitlab)
++        @test Documenter.Utilities.format_line(1:1, formatting) == "L1"
++        @test Documenter.Utilities.format_line(123:123, formatting) == "L123"
++        @test Documenter.Utilities.format_line(2:5, formatting) == "L2-5"
++        @test Documenter.Utilities.format_line(100:9999, formatting) == "L100-9999"
++    end
++
++    let formatting = Documenter.Utilities.LineRangeFormatting(Documenter.Utilities.RepoBitbucket)
++        @test Documenter.Utilities.format_line(1:1, formatting) == "1"
++        @test Documenter.Utilities.format_line(123:123, formatting) == "123"
++        @test Documenter.Utilities.format_line(2:5, formatting) == "2:5"
++        @test Documenter.Utilities.format_line(100:9999, formatting) == "100:9999"
++    end
++
++    # URL building
++    filepath = string(first(methods(Documenter.Utilities.url)).file)
++    Sys.iswindows() && (filepath = replace(filepath, "/" => "\\")) # work around JuliaLang/julia#26424
++    let expected_filepath = "/src/Utilities/Utilities.jl"
++        Sys.iswindows() && (expected_filepath = replace(expected_filepath, "/" => "\\"))
++        @test endswith(filepath, expected_filepath)
++        @show filepath expected_filepath
++    end
++
++    mktempdir() do path
++        cd(path) do
++            # Create a simple mock repo in a temporary directory with a single file.
++            @test success(`git init`)
++            @test success(`git config user.email "tester@example.com"`)
++            @test success(`git config user.name "Test Committer"`)
++            @test success(`git remote add origin git@github.com:JuliaDocs/Documenter.jl.git`)
++            mkpath("src")
++            filepath = abspath(joinpath("src", "SourceFile.jl"))
++            write(filepath, "X")
++            @test success(`git add -A`)
++            @test success(`git commit -m"Initial commit."`)
++
++            # Run tests
++            commit = Documenter.Utilities.repo_commit(filepath)
++
++            @test Documenter.Utilities.url("//blob/{commit}{path}#{line}", filepath) == "//blob/$(commit)/src/SourceFile.jl#"
++            @test Documenter.Utilities.url(nothing, "//blob/{commit}{path}#{line}", Documenter.Utilities, filepath, 10:20) == "//blob/$(commit)/src/SourceFile.jl#L10-L20"
++
++            # repo_root & relpath_from_repo_root
++            @test Documenter.Utilities.repo_root(filepath) == dirname(abspath(joinpath(dirname(filepath), ".."))) # abspath() keeps trailing /, hence dirname()
++            @test Documenter.Utilities.repo_root(filepath; dbdir=".svn") == nothing
++            @test Documenter.Utilities.relpath_from_repo_root(filepath) == joinpath("src", "SourceFile.jl")
++            # We assume that a temporary file is not in a repo
++            @test Documenter.Utilities.repo_root(tempname()) == nothing
++            @test Documenter.Utilities.relpath_from_repo_root(tempname()) == nothing
++        end
++    end
++
++    import Documenter.Documents: Document, Page, Globals
++    let page = Page("source", "build", [], IdDict{Any,Any}(), Globals()), doc = Document()
++        code = """
++        x += 3
++        γγγ_γγγ
++        γγγ
++        """
++        exprs = Documenter.Utilities.parseblock(code, doc, page)
++
++        @test isa(exprs, Vector)
++        @test length(exprs) === 3
++
++        @test isa(exprs[1][1], Expr)
++        @test exprs[1][1].head === :+=
++        @test exprs[1][2] == "x += 3\n"
++
++        @test exprs[2][2] == "γγγ_γγγ\n"
++
++        @test exprs[3][1] === :γγγ
++        @test exprs[3][2] == "γγγ\n"
++    end
++
++    @testset "TextDiff" begin
++        import Documenter.Utilities.TextDiff: splitby
++        @test splitby(r"\s+", "X Y  Z") == ["X ", "Y  ", "Z"]
++        @test splitby(r"[~]", "X~Y~Z") == ["X~", "Y~", "Z"]
++        @test splitby(r"[▶]", "X▶Y▶Z") == ["X▶", "Y▶", "Z"]
++        @test splitby(r"[▶]+", "X▶▶Y▶Z▶") == ["X▶▶", "Y▶", "Z▶"]
++        @test splitby(r"[▶]+", "▶▶Y▶Z▶") == ["▶▶", "Y▶", "Z▶"]
++        @test splitby(r"[▶]+", "Ω▶▶Y▶Z▶") == ["Ω▶▶", "Y▶", "Z▶"]
++        @test splitby(r"[▶]+", "Ω▶▶Y▶Z▶κ") == ["Ω▶▶", "Y▶", "Z▶", "κ"]
++    end
++
++    @static if isdefined(Base, :with_logger)
++        @testset "withoutput" begin
++            _, _, _, output = Documenter.Utilities.withoutput() do
++                println("println")
++                @info "@info"
++                f() = (Base.depwarn("depwarn", :f); nothing)
++                f()
++            end
++            @test startswith(output, "println\n[ Info: @info\n┌ Warning: depwarn\n")
++        end
++    end
++
++    @testset "issues #749, #790, #823" begin
++        let parse(x) = Documenter.Utilities.parseblock(x, nothing, nothing)
++            for LE in ("\r\n", "\n")
++                l1, l2 = parse("x = Int[]$(LE)$(LE)push!(x, 1)$(LE)")
++                @test l1[1] == :(x = Int[])
++                @test l1[2] == "x = Int[]$(LE)"
++                @test l2[1] == :(push!(x, 1))
++                @test l2[2] == "push!(x, 1)$(LE)"
++            end
++        end
++    end
++end
++
++end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f090c7d1615c77da6d461fc049a44562031fb585
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++https://github.com/JuliaDocs/Documenter.jl/releases
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..727ccc0be30c16c60ed2380588bae713961993e3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/93b6d6de857dc88e665d2c64397852ab9701ba24
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8fcad943a90a11d1aad8922bc6f13a1d6fcf01a0
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..36f475494b870f40c77b38a199d13c09bfab32e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++https://api.github.com/repos/JuliaLang/libuv/tarball/d8ab1c6a33e77bf155facb54215dd8798e13825d
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4471b7f1de3c9d38598613d68bfe78624c9029c1
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a53a330411db4cbc571ab0ebd792b4472bebb5bf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++https://api.github.com/repos/vtjnash/libwhich/tarball/81e9723c0273d78493dc8c8ed570f68d9ce7e89e
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..47e342fd2672034028010644bc1f5396f43e9cb5
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a19c373233b4c79ae939650598709019725be7fd
new file mode 120000 (symlink)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++llvm-6.0.0.src.tar.xz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e6f942d47bdd2f6737ab7454f3dc8c5e3b68b887
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++/* This file is provided by Debian as an replacement to
++ *   https://fonts.googleapis.com/css?family=Lato|Roboto+Mono
++ * MIT License, 2018, Mo Zhou <cdluminate@gmail.com>
++ */
++@font-face {
++  font-family: 'Lato';
++  font-style: normal;
++  font-weight: 400;
++  src: local('Lato Regular'),
++       local('Lato-Regular'),
++         url(file:///usr/share/fonts/truetype/lato/Lato-Regular.ttf) format('truetype');
++}
++@font-face {
++  font-family: 'Inconsolata';
++  font-style: normal;
++  font-weight: 400;
++  src: local('Inconsolata'),
++         url(file:///usr/share/fonts/truetype/inconsolata/Inconsolata.otf) format('opentype');
++}
diff --cc debian/gbp.conf
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cec628c7444886870d72dc8bcd536479e7f8a284
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++[DEFAULT]
++pristine-tar = True
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b7dc52a00be6ea058d9991e6004037f6b446d69f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++include: https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
++
++build:
++    extends: .build-unstable
++
++reprotest:
++    extends: .test-reprotest
++
++lintian:
++    extends: .test-lintian
++
++autopkgtest:
++    extends: .test-autopkgtest
++
++piuparts:
++    extends: .test-piuparts
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..abfdfcba40dffa5781cf95c52668d71dd3fa2f37
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++etc/julia/
++usr/share/julia/base
++usr/share/julia/test
++usr/share/julia/stdlib
++usr/share/julia/julia-config.jl
++usr/share/julia/build_sysimg.jl
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5b6385d82e4f5956ab674188839a17dc1679a80d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Docs are deliberately put there.
++julia-common: package-contains-documentation-outside-usr-share-doc usr/share/julia/stdlib/*
++# This is false-positive
++julia-common: wrong-path-for-interpreter
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fa686314bf27e83aec214f1d232176e1b104a0e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++Document: julia-manual
++Title: Julia Language Manual
++Abstract: Describes the Julia language and its standard library
++Section: Programming
++
++Format: HTML
++Index: /usr/share/doc/julia/html/en/index.html
++Files: /usr/share/doc/julia/html/*
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ede9b5d4ad4d97d8b0d9ac931cc774a461ec4bcb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++Document: julia-manual-pdf
++Title: Julia Language Manual
++Abstract: Describes the Julia language and its standard library
++Section: Programming
++
++Format: PDF
++Files: /usr/share/doc/julia/TheJuliaLanguage.pdf.gz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..84c60ce18f7249ecedd88a06ac608bc7986be7b5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++doc/_build/html
++doc/_build/pdf/en/TheJuliaLanguage.pdf
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..71ced2c3d4380a1267909484885111c91c178051
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/fontface.css  usr/share/doc/julia-doc/
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a67add3a10b130266581dee72ac8e239018f1ab3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++README.md
++CONTRIBUTING.md
++DISTRIBUTING.md
++HISTORY.md
++NEWS.md
++README.arm.md
++README.md
++README.windows.md
++VERSION
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9b68fb55c54186110f70304f98149e1877593d19
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/prompt.example.jl
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e9d188b9743cdf3941a3f87f1c6498587dcb7f73
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++usr/bin/julia
++usr/share/appdata/julia.appdata.xml  usr/share/metainfo/
++usr/share/applications/julia.desktop
++usr/share/icons/hicolor/scalable/apps/julia.svg
++usr/share/julia/base/build_h.jl
++usr/share/julia/base.cache
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..39044809f930ff4b869d8bec03d2599f34d3d78e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/tmp/usr/share/man/man1/julia.1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ab27977497bfad4cd53d162265f64a3d6d85d444
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++usr/include/julia
++usr/lib/*/libjulia.so
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8c0e6effbab7503a72df00ad0e2424e7d3ceb360
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++usr/lib/*/libjulia.so.*
++usr/lib/*/julia
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..309899e05b67619838cef1ec20a721fb3ae428ae
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Deliberately keeping debug info https://github.com/JuliaLang/julia/issues/23115#issuecomment-320715030
++libjulia1: unstripped-binary-or-object usr/lib/*/julia/sys.so
++# Deliberately keeping debug info https://github.com/JuliaLang/julia/issues/23115#issuecomment-320715030
++libjulia1: unstripped-binary-or-object usr/lib/*/libjulia.so.*
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..32f9351dc5521d9168050fea14042d56e3e37bf5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1233 @@@
++libjulia.so.1 libjulia1 #MINVER#
++ LLVMExtraAddInternalizePassWithExportList@Base 0.7.0~beta2
++ LLVMExtraAddMVVMReflectPass@Base 0.7.0~beta2
++ LLVMExtraAddPass@Base 0.7.0~beta2
++ LLVMExtraAddTargetLibraryInfoByTiple@Base 0.7.0~beta2
++ LLVMExtraCreateBasicBlockPass@Base 0.7.0~beta2
++ LLVMExtraCreateFunctionPass@Base 0.7.0~beta2
++ LLVMExtraCreateModulePass@Base 0.7.0~beta2
++ LLVMExtraGetDebugMDVersion@Base 0.7.0~beta2
++ LLVMExtraGetSourceLocation@Base 0.7.0~beta2
++ LLVMExtraGetValueContext@Base 0.7.0~beta2
++ LLVMExtraInitializeAllAsmParsers@Base 0.7.0~beta2
++ LLVMExtraInitializeAllAsmPrinters@Base 0.7.0~beta2
++ LLVMExtraInitializeAllDisassemblers@Base 0.7.0~beta2
++ LLVMExtraInitializeAllTargetInfos@Base 0.7.0~beta2
++ LLVMExtraInitializeAllTargetMCs@Base 0.7.0~beta2
++ LLVMExtraInitializeAllTargets@Base 0.7.0~beta2
++ LLVMExtraInitializeNativeAsmParser@Base 0.7.0~beta2
++ LLVMExtraInitializeNativeAsmPrinter@Base 0.7.0~beta2
++ LLVMExtraInitializeNativeDisassembler@Base 0.7.0~beta2
++ LLVMExtraInitializeNativeTarget@Base 0.7.0~beta2
++ __stack_chk_guard@Base 0.6.3
++ bitvector_get@Base 0.6.3
++ bitvector_new@Base 0.6.3
++ bitvector_resize@Base 0.6.3
++ bitvector_set@Base 0.6.3
++ int32hash@Base 0.6.3
++ int64hash@Base 0.6.3
++ int64to32hash@Base 0.6.3
++ ios_bufmode@Base 0.6.3
++ ios_close@Base 0.6.3
++ ios_copy@Base 0.6.3
++ ios_copyall@Base 0.6.3
++ ios_copyuntil@Base 0.6.3
++ ios_eof@Base 0.6.3
++ ios_eof_blocking@Base 0.6.3
++ ios_fd@Base 0.6.3
++ ios_file@Base 0.6.3
++ ios_flush@Base 0.6.3
++ ios_get_readable@Base 0.6.3
++ ios_get_writable@Base 0.6.3
++ ios_getc@Base 0.6.3
++ ios_getutf8@Base 0.6.3
++ ios_isopen@Base 0.6.3
++ ios_mem@Base 0.6.3
++ ios_mkstemp@Base 0.6.3
++ ios_nchomp@Base 0.6.3
++ ios_peekc@Base 0.6.3
++ ios_peekutf8@Base 0.6.3
++ ios_pos@Base 0.6.3
++ ios_printf@Base 0.6.3
++ ios_purge@Base 0.6.3
++ ios_putc@Base 0.6.3
++ ios_pututf8@Base 0.6.3
++ ios_read@Base 0.6.3
++ ios_readall@Base 0.6.3
++ ios_readline@Base 0.6.3
++ ios_readprep@Base 0.6.3
++ ios_seek@Base 0.6.3
++ ios_seek_end@Base 0.6.3
++ ios_set_readonly@Base 0.6.3
++ ios_setbuf@Base 0.6.3
++ ios_skip@Base 0.6.3
++ ios_stderr@Base 0.6.3
++ ios_stdin@Base 0.6.3
++ ios_stdout@Base 0.6.3
++ ios_take_buffer@Base 0.6.3
++ ios_trunc@Base 0.6.3
++ ios_vprintf@Base 0.6.3
++ ios_write@Base 0.6.3
++ ios_write_direct@Base 0.6.3
++ jl_@Base 0.6.3
++ jl_LLVMContext@Base 0.6.3
++ jl_LLVMCreateDisasm@Base 0.6.3
++ jl_LLVMDisasmInstruction@Base 0.6.3
++ jl_LLVMFlipSign@Base 0.6.3
++ jl_LLVMSMod@Base 0.6.3
++ jl_RTLD_DEFAULT_handle@Base 0.6.3
++ jl_SC_CLK_TCK@Base 0.6.3
++ jl_abs_float@Base 0.6.3
++ jl_abs_float_withtype@Base 0.6.3
++ jl_abstractarray_type@Base 0.6.3
++ jl_abstractslot_type@Base 0.6.3
++ jl_abstractstring_type@Base 0.6.3
++ jl_add_float@Base 0.6.3
++ jl_add_int@Base 0.6.3
++ jl_add_optimization_passes@Base 0.7.0~beta2
++ jl_add_ptr@Base 0.7.0~beta2
++ jl_add_standard_imports@Base 0.6.3
++ jl_alignment@Base 0.6.3
++ jl_alloc_array_1d@Base 0.6.3
++ jl_alloc_array_2d@Base 0.6.3
++ jl_alloc_array_3d@Base 0.6.3
++ jl_alloc_string@Base 0.6.3
++ jl_alloc_svec@Base 0.6.3
++ jl_alloc_svec_uninit@Base 0.6.3
++ jl_alloc_vec_any@Base 0.6.3
++ jl_an_empty_vec_any@Base 0.6.3
++ jl_and_int@Base 0.6.3
++ jl_any_type@Base 0.6.3
++ jl_anytuple_type@Base 0.6.3
++ jl_anytuple_type_type@Base 0.6.3
++ jl_apply_2va@Base 0.6.3
++ jl_apply_array_type@Base 0.6.3
++ jl_apply_generic@Base 0.6.3
++ jl_apply_tuple_type@Base 0.6.3
++ jl_apply_tuple_type_v@Base 0.6.3
++ jl_apply_type1@Base 0.6.3
++ jl_apply_type2@Base 0.6.3
++ jl_apply_type@Base 0.6.3
++ jl_apply_with_saved_exception_state@Base 0.6.3
++ jl_argument_datatype@Base 0.7.0~beta2
++ jl_argumenterror_type@Base 0.6.3
++ jl_array_any_type@Base 0.6.3
++ jl_array_cconvert_cstring@Base 0.6.3
++ jl_array_copy@Base 0.6.3
++ jl_array_data_owner@Base 0.6.3
++ jl_array_del_at@Base 0.6.3
++ jl_array_del_beg@Base 0.6.3
++ jl_array_del_end@Base 0.6.3
++ jl_array_eltype@Base 0.6.3
++ jl_array_grow_at@Base 0.6.3
++ jl_array_grow_beg@Base 0.6.3
++ jl_array_grow_end@Base 0.6.3
++ jl_array_int32_type@Base 0.7.0~beta2
++ jl_array_isassigned@Base 0.6.3
++ jl_array_ptr@Base 0.6.3
++ jl_array_ptr_1d_append@Base 0.6.3
++ jl_array_ptr_1d_push@Base 0.6.3
++ jl_array_ptr_copy@Base 0.6.3
++ jl_array_rank@Base 0.6.3
++ jl_array_size@Base 0.6.3
++ jl_array_sizehint@Base 0.6.3
++ jl_array_store_unboxed@Base 0.7.0~beta2
++ jl_array_symbol_type@Base 0.6.3
++ jl_array_to_string@Base 0.6.3
++ jl_array_type@Base 0.6.3
++ jl_array_typename@Base 0.6.3
++ jl_array_typetagdata@Base 0.7.0
++ jl_array_uint8_type@Base 0.6.3
++ jl_arraylen@Base 0.6.3
++ jl_arrayref@Base 0.6.3
++ jl_arrayset@Base 0.6.3
++ jl_arrayunset@Base 0.6.3
++ jl_ashr_int@Base 0.6.3
++ jl_ast_flag_inferred@Base 0.6.3
++ jl_ast_flag_inlineable@Base 0.6.3
++ jl_ast_flag_pure@Base 0.6.3
++ jl_astaggedvalue@Base 0.6.3
++ jl_atexit_hook@Base 0.6.3
++ jl_backtrace_from_here@Base 0.6.3
++ jl_base_module@Base 0.6.3
++ jl_base_relative_to@Base 0.6.3
++ jl_binding_owner@Base 0.7.0~beta2
++ jl_binding_resolved_p@Base 0.6.3
++ jl_bitcast@Base 0.6.3
++ jl_bool_type@Base 0.6.3
++ jl_bottom_type@Base 0.6.3
++ jl_boundp@Base 0.6.3
++ jl_bounds_error@Base 0.6.3
++ jl_bounds_error_int@Base 0.6.3
++ jl_bounds_error_ints@Base 0.6.3
++ jl_bounds_error_tuple_int@Base 0.6.3
++ jl_bounds_error_unboxed_int@Base 0.6.3
++ jl_bounds_error_v@Base 0.6.3
++ jl_boundserror_type@Base 0.6.3
++ jl_box_bool@Base 0.6.3
++ jl_box_char@Base 0.6.3
++ jl_box_float32@Base 0.6.3
++ jl_box_float64@Base 0.6.3
++ jl_box_int16@Base 0.6.3
++ jl_box_int32@Base 0.6.3
++ jl_box_int64@Base 0.6.3
++ jl_box_int8@Base 0.6.3
++ jl_box_slotnumber@Base 0.6.3
++ jl_box_ssavalue@Base 0.6.3
++ jl_box_uint16@Base 0.6.3
++ jl_box_uint32@Base 0.6.3
++ jl_box_uint64@Base 0.6.3
++ jl_box_uint8@Base 0.6.3
++ jl_box_voidpointer@Base 0.6.3
++ jl_breakpoint@Base 0.6.3
++ jl_bswap_int@Base 0.6.3
++ jl_builtin_type@Base 0.6.3
++ jl_call0@Base 0.6.3
++ jl_call1@Base 0.6.3
++ jl_call2@Base 0.6.3
++ jl_call3@Base 0.6.3
++ jl_call@Base 0.6.3
++ jl_calloc@Base 0.6.3
++ jl_capture_interp_frame@Base 0.7.0~beta2
++ jl_ceil_llvm@Base 0.6.3
++ jl_ceil_llvm_withtype@Base 0.6.3
++ jl_cglobal@Base 0.6.3
++ jl_cglobal_auto@Base 0.6.3
++ jl_char_type@Base 0.6.3
++ jl_checked_assignment@Base 0.6.3
++ jl_checked_sadd_int@Base 0.6.3
++ jl_checked_sdiv_int@Base 0.6.3
++ jl_checked_smul_int@Base 0.6.3
++ jl_checked_srem_int@Base 0.6.3
++ jl_checked_ssub_int@Base 0.6.3
++ jl_checked_uadd_int@Base 0.6.3
++ jl_checked_udiv_int@Base 0.6.3
++ jl_checked_umul_int@Base 0.6.3
++ jl_checked_urem_int@Base 0.6.3
++ jl_checked_usub_int@Base 0.6.3
++ jl_clear_malloc_data@Base 0.6.3
++ jl_clock_now@Base 0.6.3
++ jl_close_uv@Base 0.6.3
++ jl_code_for_staged@Base 0.6.3
++ jl_code_info_type@Base 0.6.3
++ jl_compile_hint@Base 0.6.3
++ jl_compress_ast@Base 0.6.3
++ jl_connect_raw@Base 0.6.3
++ jl_copy_ast@Base 0.6.3
++ jl_copy_code_info@Base 0.6.3
++ jl_copysign_float@Base 0.6.3
++ jl_core_module@Base 0.6.3
++ jl_cpu_pause@Base 0.6.3
++ jl_cpu_threads@Base 0.7.0~beta2
++ jl_cpu_wake@Base 0.6.3
++ (arch=amd64 i386)jl_cpuid@Base 0.6.3
++ (arch=amd64 i386)jl_cpuidex@Base 0.7.0~beta2
++ jl_crc32c@Base 0.6.3
++ jl_crc32c_sw@Base 0.7.0~beta2
++ jl_create_system_image@Base 0.6.3
++ jl_cstr_to_string@Base 0.6.3
++ jl_ctlz_int@Base 0.6.3
++ jl_ctpop_int@Base 0.6.3
++ jl_cttz_int@Base 0.6.3
++ jl_datatype_type@Base 0.6.3
++ jl_declare_constant@Base 0.6.3
++ jl_default_cgparams@Base 0.6.3
++ jl_defines_or_exports_p@Base 0.6.3
++ jl_densearray_type@Base 0.6.3
++ jl_deprecate_binding@Base 0.6.3
++ jl_div_float@Base 0.6.3
++ jl_diverror_exception@Base 0.6.3
++ jl_dl_handle@Base 0.6.3
++ jl_dlclose@Base 0.6.3
++ jl_dlopen@Base 0.6.3
++ jl_dlsym@Base 0.6.3
++ jl_dlsym_e@Base 0.6.3
++ jl_domain_exception@Base 0.6.3
++ jl_dump_compiles@Base 0.6.3
++ jl_dump_fptr_asm@Base 0.7.0~beta2
++ jl_dump_function_asm@Base 0.6.3
++ jl_dump_function_ir@Base 0.6.3
++ jl_dump_host_cpu@Base 0.7.0~beta2
++ jl_egal@Base 0.6.3
++ jl_emptysvec@Base 0.6.3
++ jl_emptytuple@Base 0.6.3
++ jl_emptytuple_type@Base 0.6.3
++ jl_enter_handler@Base 0.6.3
++ jl_environ@Base 0.6.3
++ jl_eof_error@Base 0.6.3
++ jl_eq_float@Base 0.6.3
++ jl_eq_int@Base 0.6.3
++ jl_eqtable_get@Base 0.6.3
++ jl_eqtable_nextind@Base 0.6.3
++ jl_eqtable_pop@Base 0.6.3
++ jl_eqtable_put@Base 0.6.3
++ jl_errno@Base 0.6.3
++ jl_error@Base 0.6.3
++ jl_errorexception_type@Base 0.6.3
++ jl_errorf@Base 0.6.3
++ jl_eval_string@Base 0.6.3
++ jl_exception_clear@Base 0.6.3
++ jl_exception_occurred@Base 0.6.3
++ jl_exceptionf@Base 0.6.3
++ jl_exe_handle@Base 0.6.3
++ jl_exit@Base 0.6.3
++ jl_exit_on_sigint@Base 0.6.3
++ jl_expand@Base 0.6.3
++ jl_expand_stmt@Base 0.7.0~beta2
++ jl_expr_type@Base 0.6.3
++ jl_extern_c@Base 0.6.3
++ jl_f__apply@Base 0.6.3
++ jl_f__apply_latest@Base 0.6.3
++ jl_f__apply_pure@Base 0.6.3
++ jl_f__expr@Base 0.6.3
++ jl_f_applicable@Base 0.6.3
++ jl_f_apply_type@Base 0.6.3
++ jl_f_arrayref@Base 0.6.3
++ jl_f_arrayset@Base 0.6.3
++ jl_f_arraysize@Base 0.6.3
++ jl_f_fieldtype@Base 0.6.3
++ jl_f_getfield@Base 0.6.3
++ jl_f_ifelse@Base 0.7.0~beta2
++ jl_f_intrinsic_call@Base 0.6.3
++ jl_f_invoke@Base 0.6.3
++ jl_f_invoke_kwsorter@Base 0.6.3
++ jl_f_is@Base 0.6.3
++ jl_f_isa@Base 0.6.3
++ jl_f_isdefined@Base 0.6.3
++ jl_f_issubtype@Base 0.6.3
++ jl_f_new_module@Base 0.6.3
++ jl_f_nfields@Base 0.6.3
++ jl_f_setfield@Base 0.6.3
++ jl_f_sizeof@Base 0.6.3
++ jl_f_svec@Base 0.6.3
++ jl_f_throw@Base 0.6.3
++ jl_f_tuple@Base 0.6.3
++ jl_f_typeassert@Base 0.6.3
++ jl_f_typeof@Base 0.6.3
++ jl_false@Base 0.6.3
++ jl_field_index@Base 0.6.3
++ jl_field_isdefined@Base 0.6.3
++ jl_filename@Base 0.6.3
++ jl_fill_argnames@Base 0.6.3
++ jl_finalize@Base 0.6.3
++ jl_finalize_th@Base 0.6.3
++ jl_find_free_typevars@Base 0.6.3
++ jl_first_argument_datatype@Base 0.6.3
++ jl_flipsign_int@Base 0.6.3
++ jl_float16_type@Base 0.6.3
++ jl_float32_type@Base 0.6.3
++ jl_float64_type@Base 0.6.3
++ jl_floatingpoint_type@Base 0.6.3
++ jl_floor_llvm@Base 0.6.3
++ jl_floor_llvm_withtype@Base 0.6.3
++ jl_flush_cstdio@Base 0.6.3
++ jl_fma_float@Base 0.6.3
++ jl_forceclose_uv@Base 0.6.3
++ jl_fpext@Base 0.6.3
++ jl_fpiseq@Base 0.6.3
++ jl_fpislt@Base 0.6.3
++ jl_fptosi@Base 0.6.3
++ jl_fptoui@Base 0.6.3
++ jl_fptr_args@Base 0.7.0~beta2
++ jl_fptr_const_return@Base 0.7.0~beta2
++ jl_fptr_interpret_call@Base 0.7.0~beta2
++ jl_fptr_sparam@Base 0.7.0~beta2
++ jl_fptr_trampoline@Base 0.7.0~beta2
++ jl_fptrunc@Base 0.6.3
++ jl_free@Base 0.6.3
++ jl_fs_chmod@Base 0.6.3
++ jl_fs_chown@Base 0.6.3
++ jl_fs_close@Base 0.6.3
++ jl_fs_read@Base 0.6.3
++ jl_fs_read_byte@Base 0.6.3
++ jl_fs_rename@Base 0.6.3
++ jl_fs_sendfile@Base 0.6.3
++ jl_fs_symlink@Base 0.6.3
++ jl_fs_unlink@Base 0.6.3
++ jl_fs_write@Base 0.6.3
++ jl_fstat@Base 0.6.3
++ jl_ftruncate@Base 0.6.3
++ jl_function_ptr@Base 0.6.3
++ jl_function_ptr_by_llvm_name@Base 0.6.3
++ jl_function_type@Base 0.6.3
++ jl_gc_add_finalizer@Base 0.6.3
++ jl_gc_add_finalizer_th@Base 0.6.3
++ jl_gc_add_ptr_finalizer@Base 0.6.3
++ jl_gc_alloc@Base 0.6.3
++ jl_gc_alloc_0w@Base 0.6.3
++ jl_gc_alloc_1w@Base 0.6.3
++ jl_gc_alloc_2w@Base 0.6.3
++ jl_gc_alloc_3w@Base 0.6.3
++ jl_gc_allocobj@Base 0.6.3
++ jl_gc_big_alloc@Base 0.6.3
++ jl_gc_collect@Base 0.6.3
++ jl_gc_counted_calloc@Base 0.6.3
++ jl_gc_counted_free@Base 0.6.3
++ jl_gc_counted_free_with_size@Base 0.7.0~beta2
++ jl_gc_counted_malloc@Base 0.6.3
++ jl_gc_counted_realloc_with_old_size@Base 0.6.3
++ jl_gc_diff_total_bytes@Base 0.6.3
++ jl_gc_enable@Base 0.6.3
++ jl_gc_enable_finalizers@Base 0.6.3
++ jl_gc_find_taggedvalue_pool@Base 0.6.3
++ jl_gc_is_enabled@Base 0.6.3
++ jl_gc_managed_malloc@Base 0.6.3
++ jl_gc_managed_realloc@Base 0.6.3
++ jl_gc_new_weakref@Base 0.6.3
++ jl_gc_new_weakref_th@Base 0.6.3
++ jl_gc_num@Base 0.6.3
++ jl_gc_pool_alloc@Base 0.6.3
++ jl_gc_queue_root@Base 0.6.3
++ jl_gc_safe_enter@Base 0.6.3
++ jl_gc_safe_leave@Base 0.6.3
++ jl_gc_safepoint@Base 0.6.3
++ jl_gc_total_bytes@Base 0.6.3
++ jl_gc_total_hrtime@Base 0.6.3
++ jl_gc_unsafe_enter@Base 0.6.3
++ jl_gc_unsafe_leave@Base 0.6.3
++ jl_gc_use@Base 0.7.0~beta2
++ jl_gdblookup@Base 0.6.3
++ jl_generating_output@Base 0.6.3
++ jl_generic_function_def@Base 0.6.3
++ jl_gensym@Base 0.6.3
++ jl_get_ARCH@Base 0.6.3
++ jl_get_JIT@Base 0.6.3
++ jl_get_LLVM_VERSION@Base 0.6.3
++ jl_get_UNAME@Base 0.6.3
++ jl_get_backtrace@Base 0.6.3
++ jl_get_binding@Base 0.6.3
++ jl_get_binding_for_method_def@Base 0.6.3
++ jl_get_binding_or_error@Base 0.6.3
++ jl_get_binding_wr@Base 0.6.3
++ jl_get_cfunction_trampoline@Base 0.7.0~beta2
++ jl_get_cpu_name@Base 0.6.3
++ jl_get_current_task@Base 0.6.3
++ jl_get_default_sysimg_path@Base 0.6.3
++ jl_get_dobj_data@Base 0.6.3
++ jl_get_fenv_consts@Base 0.6.3
++ jl_get_field@Base 0.6.3
++ jl_get_field_offset@Base 0.6.3
++ jl_get_global@Base 0.6.3
++ jl_get_image_file@Base 0.6.3
++ jl_get_invoke_lambda@Base 0.6.3
++ jl_get_julia_bin@Base 0.6.3
++ jl_get_julia_bindir@Base 0.7.0~beta2
++ jl_get_keyword_sorter@Base 0.6.3
++ jl_get_kwsorter@Base 0.6.3
++ jl_get_llvm_fptr@Base 0.6.3
++ jl_get_llvmf_decl@Base 0.6.3
++ jl_get_llvmf_defn@Base 0.6.3
++ jl_get_module_of_binding@Base 0.6.3
++ jl_get_nth_field@Base 0.6.3
++ jl_get_nth_field_checked@Base 0.6.3
++ jl_get_nth_field_noalloc@Base 0.7.0~beta2
++ jl_get_ptls_states@Base 0.6.3
++ jl_get_root_symbol@Base 0.6.3
++ jl_get_section_start@Base 0.6.3
++ jl_get_size@Base 0.6.3
++ jl_get_spec_lambda@Base 0.6.3
++ jl_get_tls_world_age@Base 0.6.3
++ jl_get_world_counter@Base 0.6.3
++ jl_get_zero_subnormals@Base 0.6.3
++ jl_getaddrinfo@Base 0.6.3
++ jl_getallocationgranularity@Base 0.6.3
++ jl_getnameinfo6@Base 0.7.0~beta2
++ jl_getnameinfo@Base 0.7.0~beta2
++ jl_getpagesize@Base 0.6.3
++ jl_getpid@Base 0.6.3
++ jl_gettimeofday@Base 0.6.3
++ jl_getutf8@Base 0.6.3
++ jl_gf_invoke_lookup@Base 0.6.3
++ jl_git_branch@Base 0.6.3
++ jl_git_commit@Base 0.6.3
++ jl_global_event_loop@Base 0.6.3
++ jl_globalref_type@Base 0.6.3
++ jl_gotonode_type@Base 0.6.3
++ jl_has_call_ambiguities@Base 0.6.3
++ jl_has_empty_intersection@Base 0.6.3
++ jl_has_free_typevars@Base 0.6.3
++ jl_has_so_reuseport@Base 0.7.0~beta2
++ jl_has_typevar@Base 0.6.3
++ jl_has_typevar_from_unionall@Base 0.6.3
++ jl_hrtime@Base 0.6.3
++ jl_id_char@Base 0.6.3
++ jl_id_start_char@Base 0.6.3
++ jl_idtable_rehash@Base 0.6.3
++ jl_incomplete_sym@Base 0.6.3
++ jl_infer_thunk@Base 0.7.0~beta2
++ jl_init__threading@Base 0.7.0~beta2
++ jl_init_restored_modules@Base 0.7.0
++ jl_init_with_image__threading@Base 0.7.0~beta2
++ jl_initerror_type@Base 0.6.3
++ jl_install_sigint_handler@Base 0.6.3
++ jl_instantiate_type_in_env@Base 0.6.3
++ jl_instantiate_unionall@Base 0.6.3
++ jl_int16_type@Base 0.6.3
++ jl_int32_type@Base 0.6.3
++ jl_int64_type@Base 0.6.3
++ jl_int8_type@Base 0.6.3
++ jl_internal_main_module@Base 0.6.3
++ jl_interrupt_exception@Base 0.6.3
++ jl_intersect_types@Base 0.6.3
++ jl_intrinsic_name@Base 0.6.3
++ jl_intrinsic_type@Base 0.6.3
++ jl_invoke@Base 0.6.3
++ jl_invoke_api@Base 0.7.0~beta2
++ jl_ios_fd@Base 0.6.3
++ jl_ios_get_nbyte_int@Base 0.6.3
++ jl_is_binding_deprecated@Base 0.6.3
++ jl_is_call_ambiguous@Base 0.7.0~beta2
++ jl_is_char_signed@Base 0.6.3
++ jl_is_const@Base 0.6.3
++ jl_is_debugbuild@Base 0.6.3
++ jl_is_enter_interpreter_frame@Base 0.7.0~beta2
++ jl_is_identifier@Base 0.7.0~beta2
++ jl_is_imported@Base 0.6.3
++ jl_is_in_pure_context@Base 0.6.3
++ jl_is_initialized@Base 0.6.3
++ jl_is_interpreter_frame@Base 0.7.0~beta2
++ jl_is_memdebug@Base 0.6.3
++ jl_is_not_broken_subtype@Base 0.7.0~beta2
++ jl_is_operator@Base 0.6.3
++ jl_is_task_started@Base 0.6.3
++ jl_is_unary_and_binary_operator@Base 0.7.0~beta2
++ jl_is_unary_operator@Base 0.7.0~beta2
++ jl_isa@Base 0.6.3
++ jl_isa_compileable_sig@Base 0.7.0~beta2
++ jl_islayout_inline@Base 0.7.0~beta2
++ jl_istopmod@Base 0.6.3
++ jl_le_float@Base 0.6.3
++ jl_lineinfonode_type@Base 0.7.0~beta2
++ jl_lineno@Base 0.6.3
++ jl_linenumbernode_type@Base 0.6.3
++ jl_lisp_prompt@Base 0.6.3
++ jl_load@Base 0.6.3
++ jl_load_@Base 0.6.3
++ jl_load_and_lookup@Base 0.6.3
++ jl_load_dynamic_library@Base 0.6.3
++ jl_load_dynamic_library_e@Base 0.6.3
++ jl_load_file_string@Base 0.6.3
++ jl_loaderror_type@Base 0.6.3
++ jl_lookup_code_address@Base 0.6.3
++ jl_lseek@Base 0.6.3
++ jl_lshr_int@Base 0.6.3
++ jl_lstat@Base 0.6.3
++ jl_lt_float@Base 0.6.3
++ jl_macroexpand1@Base 0.7.0~beta2
++ jl_macroexpand@Base 0.6.3
++ jl_main_module@Base 0.6.3
++ jl_malloc@Base 0.6.3
++ jl_matching_methods@Base 0.6.3
++ jl_maxrss@Base 0.6.3
++ jl_memory_exception@Base 0.6.3
++ jl_method_def@Base 0.6.3
++ jl_method_exists@Base 0.6.3
++ jl_method_instance_add_backedge@Base 0.6.3
++ jl_method_instance_type@Base 0.6.3
++ jl_method_table_add_backedge@Base 0.6.3
++ jl_method_table_disable@Base 0.7.0~beta2
++ jl_method_table_insert@Base 0.6.3
++ jl_method_type@Base 0.6.3
++ jl_methoderror_type@Base 0.6.3
++ jl_methtable_lookup@Base 0.6.3
++ jl_methtable_type@Base 0.6.3
++ jl_mmap@Base 0.6.3
++ jl_module_build_id@Base 0.7.0~beta2
++ jl_module_export@Base 0.6.3
++ jl_module_exports_p@Base 0.6.3
++ jl_module_globalref@Base 0.6.3
++ jl_module_import@Base 0.6.3
++ jl_module_name@Base 0.6.3
++ jl_module_names@Base 0.6.3
++ jl_module_parent@Base 0.6.3
++ jl_module_type@Base 0.6.3
++ jl_module_use@Base 0.6.3
++ jl_module_using@Base 0.6.3
++ jl_module_usings@Base 0.6.3
++ jl_module_uuid@Base 0.6.3
++ jl_mul_float@Base 0.6.3
++ jl_mul_int@Base 0.6.3
++ jl_muladd_float@Base 0.6.3
++ jl_n_threads@Base 0.6.3
++ jl_namedtuple_type@Base 0.7.0~beta2
++ jl_namedtuple_typename@Base 0.7.0~beta2
++ jl_native_alignment@Base 0.6.3
++ jl_nb_available@Base 0.6.3
++ jl_ne_float@Base 0.6.3
++ jl_ne_int@Base 0.6.3
++ jl_neg_float@Base 0.6.3
++ jl_neg_float_withtype@Base 0.6.3
++ jl_neg_int@Base 0.6.3
++ jl_new_array@Base 0.6.3
++ jl_new_bits@Base 0.6.3
++ jl_new_code_info_uninit@Base 0.6.3
++ jl_new_datatype@Base 0.6.3
++ jl_new_main_module@Base 0.6.3
++ jl_new_method_instance_uninit@Base 0.6.3
++ jl_new_method_table@Base 0.6.3
++ jl_new_method_uninit@Base 0.6.3
++ jl_new_module@Base 0.6.3
++ jl_new_primitivetype@Base 0.6.3
++ jl_new_struct@Base 0.6.3
++ jl_new_struct_uninit@Base 0.6.3
++ jl_new_structv@Base 0.6.3
++ jl_new_task@Base 0.6.3
++ jl_new_typename_in@Base 0.6.3
++ jl_new_typevar@Base 0.6.3
++ jl_newvarnode_type@Base 0.6.3
++ jl_next_from_addrinfo@Base 0.6.3
++ jl_no_exc_handler@Base 0.6.3
++ jl_not_int@Base 0.6.3
++ jl_nothing@Base 0.6.3
++ jl_number_type@Base 0.6.3
++ jl_object_id@Base 0.6.3
++ jl_op_suffix_char@Base 0.7.0~beta2
++ jl_operator_precedence@Base 0.6.3
++ jl_options@Base 0.6.3
++ jl_or_int@Base 0.6.3
++ jl_overflow_exception@Base 0.6.3
++ jl_parse_input_line@Base 0.6.3
++ jl_parse_opts@Base 0.6.3
++ jl_parse_string@Base 0.6.3
++ jl_pathname_for_handle@Base 0.6.3
++ jl_pchar_to_array@Base 0.6.3
++ jl_pchar_to_string@Base 0.6.3
++ jl_phicnode_type@Base 0.7.0~beta2
++ jl_phinode_type@Base 0.7.0~beta2
++ jl_pinode_type@Base 0.7.0~beta2
++ jl_pipe_open@Base 0.7.0~beta2
++ jl_pointer_type@Base 0.6.3
++ jl_pointer_typename@Base 0.6.3
++ jl_pointerref@Base 0.6.3
++ jl_pointerset@Base 0.6.3
++ jl_pop_handler@Base 0.6.3
++ jl_preload_sysimg_so@Base 0.6.3
++ jl_prepend_cwd@Base 0.7.0~beta2
++ jl_printf@Base 0.6.3
++ jl_process_events@Base 0.6.3
++ jl_profile_clear_data@Base 0.6.3
++ jl_profile_delay_nsec@Base 0.6.3
++ jl_profile_get_data@Base 0.6.3
++ jl_profile_init@Base 0.6.3
++ jl_profile_is_running@Base 0.6.3
++ jl_profile_len_data@Base 0.6.3
++ jl_profile_maxlen_data@Base 0.6.3
++ jl_profile_start_timer@Base 0.6.3
++ jl_profile_stop_timer@Base 0.6.3
++ jl_ptr_to_array@Base 0.6.3
++ jl_ptr_to_array_1d@Base 0.6.3
++ jl_ptrarrayref@Base 0.7.0~beta2
++ jl_pwrite@Base 0.6.3
++ jl_queue_work@Base 0.6.3
++ jl_quotenode_type@Base 0.6.3
++ jl_raise_debugger@Base 0.6.3
++ jl_read_verify_header@Base 0.6.3
++ jl_readonlymemory_exception@Base 0.6.3
++ jl_readuntil@Base 0.6.3
++ jl_realloc@Base 0.6.3
++ jl_ref_type@Base 0.6.3
++ jl_register_linfo_tracer@Base 0.6.3
++ jl_register_method_tracer@Base 0.6.3
++ jl_register_newmeth_tracer@Base 0.6.3
++ jl_rem_float@Base 0.6.3
++ jl_repl_raise_sigtstp@Base 0.7.0~beta2
++ jl_reshape_array@Base 0.6.3
++ jl_restore_incremental@Base 0.6.3
++ jl_restore_incremental_from_buf@Base 0.6.3
++ jl_restore_system_image@Base 0.6.3
++ jl_restore_system_image_data@Base 0.6.3
++ jl_rethrow@Base 0.6.3
++ jl_rethrow_other@Base 0.6.3
++ jl_rint_llvm@Base 0.6.3
++ jl_rint_llvm_withtype@Base 0.6.3
++ jl_run_event_loop@Base 0.6.3
++ jl_run_once@Base 0.6.3
++ jl_running_on_valgrind@Base 0.6.3
++ jl_safe_printf@Base 0.6.3
++ jl_save_incremental@Base 0.6.3
++ jl_save_system_image@Base 0.6.3
++ jl_sdiv_int@Base 0.6.3
++ jl_set_ARGS@Base 0.6.3
++ jl_set_const@Base 0.6.3
++ jl_set_errno@Base 0.6.3
++ jl_set_global@Base 0.6.3
++ jl_set_istopmod@Base 0.6.3
++ jl_set_method_inferred@Base 0.6.3
++ jl_set_module_nospecialize@Base 0.7.0
++ jl_set_module_uuid@Base 0.7.0~beta2
++ jl_set_nth_field@Base 0.6.3
++ jl_set_ptls_states_getter@Base 0.6.3
++ jl_set_sysimg_so@Base 0.6.3
++ jl_set_typeinf_func@Base 0.6.3
++ jl_set_zero_subnormals@Base 0.6.3
++ jl_sext_int@Base 0.6.3
++ jl_shl_int@Base 0.6.3
++ jl_sigatomic_begin@Base 0.6.3
++ jl_sigatomic_end@Base 0.6.3
++ jl_signal_pending@Base 0.6.3
++ jl_signed_type@Base 0.6.3
++ jl_simplevector_type@Base 0.6.3
++ jl_sitofp@Base 0.6.3
++ jl_sizeof_ios_t@Base 0.6.3
++ jl_sizeof_jl_options@Base 0.7.0~beta2
++ jl_sizeof_mode_t@Base 0.6.3
++ jl_sizeof_off_t@Base 0.6.3
++ jl_sizeof_stat@Base 0.6.3
++ jl_sizeof_uv_fs_t@Base 0.6.3
++ jl_sizeof_uv_mutex@Base 0.6.3
++ jl_sle_int@Base 0.6.3
++ jl_slotnumber_type@Base 0.6.3
++ jl_slt_int@Base 0.6.3
++ jl_smod_int@Base 0.6.3
++ jl_sockaddr_from_addrinfo@Base 0.6.3
++ jl_sockaddr_host4@Base 0.6.3
++ jl_sockaddr_host6@Base 0.6.3
++ jl_sockaddr_in_is_ip4@Base 0.6.3
++ jl_sockaddr_in_is_ip6@Base 0.6.3
++ jl_sockaddr_is_ip4@Base 0.6.3
++ jl_sockaddr_is_ip6@Base 0.6.3
++ jl_sockaddr_set_port@Base 0.6.3
++ jl_spawn@Base 0.6.3
++ jl_specializations_get_linfo@Base 0.6.3
++ jl_specializations_lookup@Base 0.6.3
++ jl_sqrt_llvm@Base 0.6.3
++ jl_sqrt_llvm_withtype@Base 0.6.3
++ jl_srem_int@Base 0.6.3
++ jl_ssavalue_type@Base 0.6.3
++ jl_stackovf_exception@Base 0.6.3
++ jl_stat@Base 0.6.3
++ jl_stat_blksize@Base 0.6.3
++ jl_stat_blocks@Base 0.6.3
++ jl_stat_ctime@Base 0.6.3
++ jl_stat_dev@Base 0.6.3
++ jl_stat_gid@Base 0.6.3
++ jl_stat_ino@Base 0.6.3
++ jl_stat_mode@Base 0.6.3
++ jl_stat_mtime@Base 0.6.3
++ jl_stat_nlink@Base 0.6.3
++ jl_stat_rdev@Base 0.6.3
++ jl_stat_size@Base 0.6.3
++ jl_stat_uid@Base 0.6.3
++ jl_static_show@Base 0.6.3
++ jl_static_show_func_sig@Base 0.6.3
++ jl_stderr_obj@Base 0.6.3
++ jl_stderr_stream@Base 0.6.3
++ jl_stdin_stream@Base 0.6.3
++ jl_stdout_obj@Base 0.6.3
++ jl_stdout_stream@Base 0.6.3
++ jl_string_ptr@Base 0.6.3
++ jl_string_to_array@Base 0.6.3
++ jl_string_type@Base 0.6.3
++ jl_strtod_c@Base 0.6.3
++ jl_strtof_c@Base 0.6.3
++ jl_sub_float@Base 0.6.3
++ jl_sub_int@Base 0.6.3
++ jl_sub_ptr@Base 0.7.0~beta2
++ jl_substrtod@Base 0.6.3
++ jl_substrtof@Base 0.6.3
++ jl_subtype@Base 0.6.3
++ jl_subtype_env@Base 0.6.3
++ jl_subtype_env_size@Base 0.6.3
++ jl_svec1@Base 0.6.3
++ jl_svec2@Base 0.6.3
++ jl_svec@Base 0.6.3
++ jl_svec_copy@Base 0.6.3
++ jl_svec_fill@Base 0.6.3
++ jl_switchto@Base 0.6.3
++ jl_sym_type@Base 0.6.3
++ jl_symbol@Base 0.6.3
++ jl_symbol_lookup@Base 0.6.3
++ jl_symbol_n@Base 0.6.3
++ jl_symbol_name@Base 0.6.3
++ jl_symbol_type@Base 0.6.3
++ jl_tagged_gensym@Base 0.6.3
++ jl_take_buffer@Base 0.6.3
++ jl_task_type@Base 0.6.3
++ jl_tcp4_connect@Base 0.6.3
++ jl_tcp6_connect@Base 0.6.3
++ jl_tcp_bind6@Base 0.6.3
++ jl_tcp_bind@Base 0.6.3
++ jl_tcp_getpeername@Base 0.6.3
++ jl_tcp_getsockname@Base 0.6.3
++ jl_tcp_quickack@Base 0.6.3
++ jl_tcp_reuseport@Base 0.6.3
++ jl_threadid@Base 0.6.3
++ jl_threading_enabled@Base 0.6.3
++ jl_threading_profile@Base 0.6.3
++ jl_threading_run@Base 0.6.3
++ jl_throw@Base 0.6.3
++ jl_too_few_args@Base 0.6.3
++ jl_too_many_args@Base 0.6.3
++ jl_top_module@Base 0.6.3
++ jl_toplevel_eval@Base 0.6.3
++ jl_toplevel_eval_in@Base 0.6.3
++ jl_trace_linfo@Base 0.6.3
++ jl_trace_method@Base 0.6.3
++ jl_true@Base 0.6.3
++ jl_trunc_int@Base 0.6.3
++ jl_trunc_llvm@Base 0.6.3
++ jl_trunc_llvm_withtype@Base 0.6.3
++ jl_try_substrtod@Base 0.6.3
++ jl_try_substrtof@Base 0.6.3
++ jl_tty_set_mode@Base 0.6.3
++ jl_tuple_typename@Base 0.6.3
++ jl_tupletype_fill@Base 0.6.3
++ jl_tvar_type@Base 0.6.3
++ jl_type_error@Base 0.6.3
++ jl_type_error_new_expr@Base 0.7.0~beta2
++ jl_type_error_rt@Base 0.6.3
++ jl_type_intersection@Base 0.6.3
++ jl_type_intersection_with_env@Base 0.7.0~beta2
++ jl_type_morespecific@Base 0.6.3
++ jl_type_morespecific_no_subtype@Base 0.6.3
++ jl_type_type@Base 0.6.3
++ jl_type_typename@Base 0.6.3
++ jl_type_union@Base 0.6.3
++ jl_type_unionall@Base 0.6.3
++ jl_typeassert@Base 0.6.3
++ jl_typedslot_type@Base 0.6.3
++ jl_typeerror_type@Base 0.6.3
++ jl_typeinf_begin@Base 0.6.3
++ jl_typeinf_end@Base 0.6.3
++ jl_typemap_entry_type@Base 0.6.3
++ jl_typemap_level_type@Base 0.6.3
++ jl_typemax_uint@Base 0.7.0~beta2
++ jl_typename_str@Base 0.6.3
++ jl_typename_type@Base 0.6.3
++ jl_typeof@Base 0.6.3
++ jl_typeof_str@Base 0.6.3
++ jl_typeofbottom_type@Base 0.6.3
++ jl_types_equal@Base 0.6.3
++ jl_typetype_type@Base 0.6.3
++ jl_udiv_int@Base 0.6.3
++ jl_udp_bind6@Base 0.6.3
++ jl_udp_bind@Base 0.6.3
++ jl_udp_send6@Base 0.6.3
++ jl_udp_send@Base 0.6.3
++ jl_uint16_type@Base 0.6.3
++ jl_uint32_type@Base 0.6.3
++ jl_uint64_type@Base 0.6.3
++ jl_uint8_type@Base 0.6.3
++ jl_uitofp@Base 0.6.3
++ jl_ule_int@Base 0.6.3
++ jl_ult_int@Base 0.6.3
++ jl_unbox_bool@Base 0.6.3
++ jl_unbox_float32@Base 0.6.3
++ jl_unbox_float64@Base 0.6.3
++ jl_unbox_int16@Base 0.6.3
++ jl_unbox_int32@Base 0.6.3
++ jl_unbox_int64@Base 0.6.3
++ jl_unbox_int8@Base 0.6.3
++ jl_unbox_uint16@Base 0.6.3
++ jl_unbox_uint32@Base 0.6.3
++ jl_unbox_uint64@Base 0.6.3
++ jl_unbox_uint8@Base 0.6.3
++ jl_unbox_voidpointer@Base 0.6.3
++ jl_uncompress_ast@Base 0.6.3
++ jl_undefined_var_error@Base 0.6.3
++ jl_undefref_exception@Base 0.6.3
++ jl_undefvarerror_type@Base 0.6.3
++ jl_unionall_type@Base 0.6.3
++ jl_uniontype_type@Base 0.6.3
++ jl_untrace_linfo@Base 0.6.3
++ jl_untrace_method@Base 0.6.3
++ jl_upsilonnode_type@Base 0.7.0~beta2
++ jl_urem_int@Base 0.6.3
++ jl_uv_associate_julia_struct@Base 0.6.3
++ jl_uv_buf_base@Base 0.6.3
++ jl_uv_buf_len@Base 0.6.3
++ jl_uv_buf_set_base@Base 0.6.3
++ jl_uv_buf_set_len@Base 0.6.3
++ jl_uv_connect_handle@Base 0.6.3
++ jl_uv_disassociate_julia_struct@Base 0.6.3
++ jl_uv_file_handle@Base 0.6.3
++ jl_uv_fs_req_cleanup@Base 0.6.3
++ jl_uv_fs_result@Base 0.6.3
++ jl_uv_fs_t_ptr@Base 0.6.3
++ jl_uv_handle@Base 0.6.3
++ jl_uv_handle_data@Base 0.6.3
++ jl_uv_handle_type@Base 0.6.3
++ jl_uv_interface_address_is_internal@Base 0.6.3
++ jl_uv_interface_address_sockaddr@Base 0.6.3
++ jl_uv_interface_addresses@Base 0.6.3
++ jl_uv_process_data@Base 0.6.3
++ jl_uv_putb@Base 0.6.3
++ jl_uv_putc@Base 0.6.3
++ jl_uv_puts@Base 0.6.3
++ jl_uv_req_data@Base 0.6.3
++ jl_uv_req_set_data@Base 0.6.3
++ jl_uv_sizeof_interface_address@Base 0.6.3
++ jl_uv_stderr@Base 0.6.3
++ jl_uv_stdin@Base 0.6.3
++ jl_uv_stdout@Base 0.6.3
++ jl_uv_unix_fd_is_watched@Base 0.6.3
++ jl_uv_write@Base 0.6.3
++ jl_uv_write_handle@Base 0.6.3
++ jl_uv_writecb@Base 0.6.3
++ jl_value_ptr@Base 0.6.3
++ jl_valueof@Base 0.6.3
++ jl_vararg_type@Base 0.6.3
++ jl_vararg_typename@Base 0.6.3
++ jl_vecelement_typename@Base 0.6.3
++ jl_ver_is_release@Base 0.6.3
++ jl_ver_major@Base 0.6.3
++ jl_ver_minor@Base 0.6.3
++ jl_ver_patch@Base 0.6.3
++ jl_ver_string@Base 0.6.3
++ jl_void_type@Base 0.6.3
++ jl_voidpointer_type@Base 0.6.3
++ jl_vprintf@Base 0.6.3
++ jl_weakref_type@Base 0.6.3
++ jl_world_counter@Base 0.6.3
++ jl_xor_int@Base 0.6.3
++ jl_yield@Base 0.6.3
++ jl_zext_int@Base 0.6.3
++ jlbacktrace@Base 0.6.3
++ julia_init__threading@Base 0.7.0~beta2
++ julia_type_to_llvm@Base 0.6.3
++ libsupport_init@Base 0.6.3
++ memhash32@Base 0.6.3
++ memhash32_seed@Base 0.6.3
++ memhash@Base 0.6.3
++ memhash_seed@Base 0.6.3
++ u8_charnum@Base 0.6.3
++ u8_isvalid@Base 0.6.3
++ u8_offset@Base 0.6.3
++ u8_strwidth@Base 0.6.3
++ uv__accept4@Base 0.7.0~beta2
++ uv__accept@Base 0.7.0~beta2
++ uv__async_close@Base 0.7.0~beta2
++ uv__async_stop@Base 0.7.0~beta2
++ uv__calloc@Base 0.7.0~beta2
++ uv__check_close@Base 0.7.0~beta2
++ uv__cloexec_fcntl@Base 0.7.0~beta2
++ uv__cloexec_ioctl@Base 0.7.0~beta2
++ uv__close@Base 0.7.0~beta2
++ uv__close_nocheckstdio@Base 0.7.0~beta2
++ uv__count_bufs@Base 0.7.0~beta2
++ uv__dup2_cloexec@Base 0.7.0~beta2
++ uv__dup3@Base 0.7.0~beta2
++ uv__dup@Base 0.7.0~beta2
++ uv__epoll_create1@Base 0.7.0~beta2
++ uv__epoll_create@Base 0.7.0~beta2
++ uv__epoll_ctl@Base 0.7.0~beta2
++ uv__epoll_pwait@Base 0.7.0~beta2
++ uv__epoll_wait@Base 0.7.0~beta2
++ uv__eventfd2@Base 0.7.0~beta2
++ uv__eventfd@Base 0.7.0~beta2
++ uv__free@Base 0.7.0~beta2
++ uv__fs_event_close@Base 0.7.0~beta2
++ uv__fs_poll_close@Base 0.7.0~beta2
++ uv__fs_scandir_cleanup@Base 0.7.0~beta2
++ uv__getaddrinfo_translate_error@Base 0.7.0~beta2
++ uv__getiovmax@Base 0.7.0~beta2
++ uv__getpwuid_r@Base 0.7.0~beta2
++ uv__handle_type@Base 0.7.0~beta2
++ uv__hrtime@Base 0.7.0~beta2
++ uv__idle_close@Base 0.7.0~beta2
++ uv__inotify_add_watch@Base 0.7.0~beta2
++ uv__inotify_init1@Base 0.7.0~beta2
++ uv__inotify_init@Base 0.7.0~beta2
++ uv__inotify_rm_watch@Base 0.7.0~beta2
++ uv__io_active@Base 0.7.0~beta2
++ uv__io_check_fd@Base 0.7.0~beta2
++ uv__io_close@Base 0.7.0~beta2
++ uv__io_feed@Base 0.7.0~beta2
++ uv__io_init@Base 0.7.0~beta2
++ uv__io_poll@Base 0.7.0~beta2
++ uv__io_start@Base 0.7.0~beta2
++ uv__io_stop@Base 0.7.0~beta2
++ uv__loop_close@Base 0.7.0~beta2
++ uv__loop_configure@Base 0.7.0~beta2
++ uv__make_close_pending@Base 0.7.0~beta2
++ uv__make_pipe@Base 0.7.0~beta2
++ uv__malloc@Base 0.7.0~beta2
++ uv__next_timeout@Base 0.7.0~beta2
++ uv__nonblock_fcntl@Base 0.7.0~beta2
++ uv__nonblock_ioctl@Base 0.7.0~beta2
++ uv__open_cloexec@Base 0.7.0~beta2
++ uv__open_file@Base 0.7.0~beta2
++ uv__pipe2@Base 0.7.0~beta2
++ uv__pipe_close@Base 0.7.0~beta2
++ uv__platform_invalidate_fd@Base 0.7.0~beta2
++ uv__platform_loop_delete@Base 0.7.0~beta2
++ uv__platform_loop_init@Base 0.7.0~beta2
++ uv__poll_close@Base 0.7.0~beta2
++ uv__preadv@Base 0.7.0~beta2
++ uv__prepare_close@Base 0.7.0~beta2
++ uv__process_close@Base 0.7.0~beta2
++ uv__pwritev@Base 0.7.0~beta2
++ uv__realloc@Base 0.7.0~beta2
++ uv__recvmmsg@Base 0.7.0~beta2
++ uv__recvmsg@Base 0.7.0~beta2
++ uv__run_check@Base 0.7.0~beta2
++ uv__run_idle@Base 0.7.0~beta2
++ uv__run_prepare@Base 0.7.0~beta2
++ uv__run_timers@Base 0.7.0~beta2
++ uv__sendmmsg@Base 0.7.0~beta2
++ uv__server_io@Base 0.7.0~beta2
++ uv__set_process_title@Base 0.7.0~beta2
++ uv__signal_close@Base 0.7.0~beta2
++ uv__signal_global_once_init@Base 0.7.0~beta2
++ uv__signal_loop_cleanup@Base 0.7.0~beta2
++ uv__socket@Base 0.7.0~beta2
++ uv__socket_sockopt@Base 0.7.0~beta2
++ uv__strdup@Base 0.7.0~beta2
++ uv__stream_close@Base 0.7.0~beta2
++ uv__stream_destroy@Base 0.7.0~beta2
++ uv__stream_flush_write_queue@Base 0.7.0~beta2
++ uv__stream_init@Base 0.7.0~beta2
++ uv__stream_open@Base 0.7.0~beta2
++ uv__strndup@Base 0.7.0~beta2
++ uv__tcp_bind@Base 0.7.0~beta2
++ uv__tcp_close@Base 0.7.0~beta2
++ uv__tcp_connect@Base 0.7.0~beta2
++ uv__tcp_keepalive@Base 0.7.0~beta2
++ uv__tcp_nodelay@Base 0.7.0~beta2
++ uv__timer_close@Base 0.7.0~beta2
++ uv__udp_bind@Base 0.7.0~beta2
++ uv__udp_close@Base 0.7.0~beta2
++ uv__udp_finish_close@Base 0.7.0~beta2
++ uv__udp_recv_start@Base 0.7.0~beta2
++ uv__udp_recv_stop@Base 0.7.0~beta2
++ uv__udp_send@Base 0.7.0~beta2
++ uv__udp_try_send@Base 0.7.0~beta2
++ uv__utimesat@Base 0.7.0~beta2
++ uv__work_done@Base 0.7.0~beta2
++ uv__work_submit@Base 0.7.0~beta2
++ uv_accept@Base 0.6.3
++ uv_async_init@Base 0.6.3
++ uv_async_send@Base 0.6.3
++ uv_backend_fd@Base 0.6.3
++ uv_backend_timeout@Base 0.6.3
++ uv_barrier_destroy@Base 0.6.3
++ uv_barrier_init@Base 0.6.3
++ uv_barrier_wait@Base 0.6.3
++ uv_buf_init@Base 0.6.3
++ uv_cancel@Base 0.6.3
++ uv_chdir@Base 0.6.3
++ uv_check_init@Base 0.6.3
++ uv_check_start@Base 0.6.3
++ uv_check_stop@Base 0.6.3
++ uv_close@Base 0.6.3
++ uv_cond_broadcast@Base 0.6.3
++ uv_cond_destroy@Base 0.6.3
++ uv_cond_init@Base 0.6.3
++ uv_cond_signal@Base 0.6.3
++ uv_cond_timedwait@Base 0.6.3
++ uv_cond_wait@Base 0.6.3
++ uv_cpu_info@Base 0.6.3
++ uv_cpumask_size@Base 0.7.0~beta2
++ uv_cwd@Base 0.6.3
++ uv_default_loop@Base 0.6.3
++ uv_disable_stdio_inheritance@Base 0.6.3
++ uv_dlclose@Base 0.6.3
++ uv_dlerror@Base 0.6.3
++ uv_dlopen@Base 0.6.3
++ uv_dlsym@Base 0.6.3
++ uv_err_name@Base 0.6.3
++ uv_exepath@Base 0.6.3
++ uv_fileno@Base 0.6.3
++ uv_free_cpu_info@Base 0.6.3
++ uv_free_interface_addresses@Base 0.6.3
++ uv_freeaddrinfo@Base 0.6.3
++ uv_fs_access@Base 0.6.3
++ uv_fs_chmod@Base 0.6.3
++ uv_fs_chown@Base 0.6.3
++ uv_fs_close@Base 0.6.3
++ uv_fs_event_getpath@Base 0.6.3
++ uv_fs_event_init@Base 0.6.3
++ uv_fs_event_start@Base 0.6.3
++ uv_fs_event_stop@Base 0.6.3
++ uv_fs_fchmod@Base 0.6.3
++ uv_fs_fchown@Base 0.6.3
++ uv_fs_fdatasync@Base 0.6.3
++ uv_fs_fstat@Base 0.6.3
++ uv_fs_fsync@Base 0.6.3
++ uv_fs_ftruncate@Base 0.6.3
++ uv_fs_futime@Base 0.6.3
++ uv_fs_link@Base 0.6.3
++ uv_fs_lstat@Base 0.6.3
++ uv_fs_mkdir@Base 0.6.3
++ uv_fs_mkdtemp@Base 0.6.3
++ uv_fs_open@Base 0.6.3
++ uv_fs_poll_getpath@Base 0.6.3
++ uv_fs_poll_init@Base 0.6.3
++ uv_fs_poll_start@Base 0.6.3
++ uv_fs_poll_stop@Base 0.6.3
++ uv_fs_read@Base 0.6.3
++ uv_fs_readlink@Base 0.6.3
++ uv_fs_realpath@Base 0.6.3
++ uv_fs_rename@Base 0.6.3
++ uv_fs_req_cleanup@Base 0.6.3
++ uv_fs_rmdir@Base 0.6.3
++ uv_fs_scandir@Base 0.6.3
++ uv_fs_scandir_next@Base 0.6.3
++ uv_fs_sendfile@Base 0.6.3
++ uv_fs_stat@Base 0.6.3
++ uv_fs_symlink@Base 0.6.3
++ uv_fs_unlink@Base 0.6.3
++ uv_fs_utime@Base 0.6.3
++ uv_fs_write@Base 0.6.3
++ uv_get_free_memory@Base 0.6.3
++ uv_get_process_title@Base 0.6.3
++ uv_get_total_memory@Base 0.6.3
++ uv_getaddrinfo@Base 0.6.3
++ uv_getnameinfo@Base 0.6.3
++ uv_getrusage@Base 0.6.3
++ uv_guess_handle@Base 0.6.3
++ uv_handle_size@Base 0.6.3
++ uv_has_ref@Base 0.6.3
++ uv_hrtime@Base 0.6.3
++ uv_idle_init@Base 0.6.3
++ uv_idle_start@Base 0.6.3
++ uv_idle_stop@Base 0.6.3
++ uv_inet_ntop@Base 0.6.3
++ uv_inet_pton@Base 0.6.3
++ uv_interface_addresses@Base 0.6.3
++ uv_ip4_addr@Base 0.6.3
++ uv_ip4_name@Base 0.6.3
++ uv_ip6_addr@Base 0.6.3
++ uv_ip6_name@Base 0.6.3
++ uv_is_active@Base 0.6.3
++ uv_is_closing@Base 0.6.3
++ uv_is_readable@Base 0.6.3
++ uv_is_writable@Base 0.6.3
++ uv_key_create@Base 0.6.3
++ uv_key_delete@Base 0.6.3
++ uv_key_get@Base 0.6.3
++ uv_key_set@Base 0.6.3
++ uv_kill@Base 0.6.3
++ uv_listen@Base 0.6.3
++ uv_loadavg@Base 0.6.3
++ uv_loop_alive@Base 0.6.3
++ uv_loop_close@Base 0.6.3
++ uv_loop_configure@Base 0.6.3
++ uv_loop_delete@Base 0.6.3
++ uv_loop_init@Base 0.6.3
++ uv_loop_new@Base 0.6.3
++ uv_loop_size@Base 0.6.3
++ uv_mutex_destroy@Base 0.6.3
++ uv_mutex_init@Base 0.6.3
++ uv_mutex_lock@Base 0.6.3
++ uv_mutex_trylock@Base 0.6.3
++ uv_mutex_unlock@Base 0.6.3
++ uv_now@Base 0.6.3
++ uv_once@Base 0.6.3
++ uv_os_free_passwd@Base 0.6.3
++ uv_os_get_passwd@Base 0.6.3
++ uv_os_getenv@Base 0.7.0~beta2
++ uv_os_gethostname@Base 0.7.0~beta2
++ uv_os_homedir@Base 0.6.3
++ uv_os_setenv@Base 0.7.0~beta2
++ uv_os_tmpdir@Base 0.6.3
++ uv_os_unsetenv@Base 0.7.0~beta2
++ uv_pipe@Base 0.7.0~beta2
++ uv_pipe_bind@Base 0.6.3
++ uv_pipe_connect@Base 0.6.3
++ uv_pipe_getpeername@Base 0.6.3
++ uv_pipe_getsockname@Base 0.6.3
++ uv_pipe_init@Base 0.6.3
++ uv_pipe_listen@Base 0.7.0~beta2
++ uv_pipe_open@Base 0.6.3
++ uv_pipe_pending_count@Base 0.6.3
++ uv_pipe_pending_instances@Base 0.6.3
++ uv_pipe_pending_type@Base 0.6.3
++ uv_poll_init@Base 0.6.3
++ uv_poll_start@Base 0.6.3
++ uv_poll_stop@Base 0.6.3
++ uv_prepare_init@Base 0.6.3
++ uv_prepare_start@Base 0.6.3
++ uv_prepare_stop@Base 0.6.3
++ uv_print_active_handles@Base 0.6.3
++ uv_print_all_handles@Base 0.6.3
++ uv_process_kill@Base 0.6.3
++ uv_queue_work@Base 0.6.3
++ uv_read_start@Base 0.6.3
++ uv_read_stop@Base 0.6.3
++ uv_recv_buffer_size@Base 0.6.3
++ uv_ref@Base 0.6.3
++ uv_replace_allocator@Base 0.6.3
++ uv_req_size@Base 0.6.3
++ uv_resident_set_memory@Base 0.6.3
++ uv_run@Base 0.6.3
++ uv_rwlock_destroy@Base 0.6.3
++ uv_rwlock_init@Base 0.6.3
++ uv_rwlock_rdlock@Base 0.6.3
++ uv_rwlock_rdunlock@Base 0.6.3
++ uv_rwlock_tryrdlock@Base 0.6.3
++ uv_rwlock_trywrlock@Base 0.6.3
++ uv_rwlock_wrlock@Base 0.6.3
++ uv_rwlock_wrunlock@Base 0.6.3
++ uv_sem_destroy@Base 0.6.3
++ uv_sem_init@Base 0.6.3
++ uv_sem_post@Base 0.6.3
++ uv_sem_trywait@Base 0.6.3
++ uv_sem_wait@Base 0.6.3
++ uv_send_buffer_size@Base 0.6.3
++ uv_set_process_title@Base 0.6.3
++ uv_setup_args@Base 0.6.3
++ uv_shutdown@Base 0.6.3
++ uv_signal_init@Base 0.6.3
++ uv_signal_start@Base 0.6.3
++ uv_signal_start_oneshot@Base 0.7.0~beta2
++ uv_signal_stop@Base 0.6.3
++ uv_socketpair@Base 0.7.0~beta2
++ uv_spawn@Base 0.6.3
++ uv_stop@Base 0.6.3
++ uv_stream_set_blocking@Base 0.6.3
++ uv_strerror@Base 0.6.3
++ uv_tcp_bind@Base 0.6.3
++ uv_tcp_connect@Base 0.6.3
++ uv_tcp_getpeername@Base 0.6.3
++ uv_tcp_getsockname@Base 0.6.3
++ uv_tcp_init@Base 0.6.3
++ uv_tcp_init_ex@Base 0.6.3
++ uv_tcp_keepalive@Base 0.6.3
++ uv_tcp_listen@Base 0.7.0~beta2
++ uv_tcp_nodelay@Base 0.6.3
++ uv_tcp_open@Base 0.6.3
++ uv_tcp_simultaneous_accepts@Base 0.6.3
++ uv_thread_create@Base 0.6.3
++ uv_thread_detach@Base 0.6.3
++ uv_thread_equal@Base 0.6.3
++ uv_thread_getaffinity@Base 0.6.3
++ uv_thread_join@Base 0.6.3
++ uv_thread_self@Base 0.6.3
++ uv_thread_setaffinity@Base 0.6.3
++ uv_timer_again@Base 0.6.3
++ uv_timer_get_repeat@Base 0.6.3
++ uv_timer_init@Base 0.6.3
++ uv_timer_set_repeat@Base 0.6.3
++ uv_timer_start@Base 0.6.3
++ uv_timer_stop@Base 0.6.3
++ uv_translate_sys_error@Base 0.7.0~beta2
++ uv_try_write@Base 0.6.3
++ uv_try_write_cb@Base 0.7.0~beta2
++ uv_tty_get_winsize@Base 0.6.3
++ uv_tty_init@Base 0.6.3
++ uv_tty_reset_mode@Base 0.6.3
++ uv_tty_set_mode@Base 0.6.3
++ uv_udp_bind@Base 0.6.3
++ uv_udp_getsockname@Base 0.6.3
++ uv_udp_init@Base 0.6.3
++ uv_udp_init_ex@Base 0.6.3
++ uv_udp_open@Base 0.6.3
++ uv_udp_recv_start@Base 0.6.3
++ uv_udp_recv_stop@Base 0.6.3
++ uv_udp_send@Base 0.6.3
++ uv_udp_set_broadcast@Base 0.6.3
++ uv_udp_set_membership@Base 0.6.3
++ uv_udp_set_multicast_interface@Base 0.6.3
++ uv_udp_set_multicast_loop@Base 0.6.3
++ uv_udp_set_multicast_ttl@Base 0.6.3
++ uv_udp_set_ttl@Base 0.6.3
++ uv_udp_try_send@Base 0.6.3
++ uv_unref@Base 0.6.3
++ uv_update_time@Base 0.6.3
++ uv_uptime@Base 0.6.3
++ uv_version@Base 0.6.3
++ uv_version_string@Base 0.6.3
++ uv_walk@Base 0.6.3
++ uv_write2@Base 0.6.3
++ uv_write@Base 0.6.3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dd86603678474715d434527c9fb1d5bcc0def43d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++activate-noawait ldconfig
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e799388291c753a3529b7799eb9c25f07f67085e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++usr/share/doc/julia/html/*
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7fe6af96ba5e61b6a8544be52b4b16331e9932a5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++Description:  Build with -latomic
++Author: Peter Michael Green <plugwash@raspbian.org>
++Last-Update: 2019-03-03
++
++--- julia-1.0.3+dfsg.orig/Make.inc
+++++ julia-1.0.3+dfsg/Make.inc
++@@ -986,7 +986,7 @@ else ifneq ($(USEMSVC), 1)
++ endif
++ 
++ ifeq ($(OS), Linux)
++-OSLIBS += -Wl,--no-as-needed -ldl -lrt -lpthread -Wl,--export-dynamic,--as-needed,--no-whole-archive $(LIBUNWIND)
+++OSLIBS += -Wl,--no-as-needed -ldl -lrt -lpthread -Wl,--export-dynamic,--as-needed,--no-whole-archive $(LIBUNWIND) -latomic
++ # Detect if ifunc is supported
++ IFUNC_DETECT_SRC := 'void (*f0(void))(void) { return (void(*)(void))0L; }; void f(void) __attribute__((ifunc("f0")));'
++ ifeq (supported, $(shell echo $(IFUNC_DETECT_SRC) | $(CC) -Werror -x c - -S -o /dev/null > /dev/null 2>&1 && echo supported))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..305527023bfdc83c7eb080649eafde6427ef1913
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++Description: lintian error due to ancient version of metadata format
++Reference: https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html
++Created-by: Mo Zhou
++Last-Update: 2018-08-16
++Forwarded: [Merged] https://github.com/JuliaLang/julia/pull/28020
++
++Index: julia/contrib/julia.appdata.xml
++===================================================================
++--- julia.orig/contrib/julia.appdata.xml
+++++ julia/contrib/julia.appdata.xml
++@@ -1,9 +1,15 @@
++ <?xml version="1.0" encoding="UTF-8"?>
++ <!-- Copyright 2014 Paul Lange <palango@gmx.de> -->
++-<application>
++- <id type="desktop">julia.desktop</id>
+++<component>
+++ <id>org.julialang.julia</id>
+++ <name>Julia</name>
+++ <launchable type="desktop-id">julia.desktop</launchable>
++  <metadata_license>CC-BY-SA-3.0</metadata_license>
++  <project_license>MIT and LGPL-2.1+ and GPL-2.0+</project_license>
+++ <summary>High-performance programming language for technical computing</summary>
+++ <provides>
+++  <binary>julia</binary>
+++ </provides>
++  <description>
++   <p>
++    Julia is a high-level, high-performance dynamic programming language for
++@@ -21,8 +27,9 @@
++   </p>
++  </description>
++  <screenshots>
++-  <screenshot type="default">https://julialang.org/images/julia-gnome.png</screenshot>
+++  <screenshot type="default">
+++   <image>https://julialang.org/images/julia-gnome.png</image>
+++  </screenshot>
++  </screenshots>
++  <url type="homepage">https://julialang.org/</url>
++- <updatecontact>julia-dev@googlegroups.com</updatecontact>
++-</application>
+++</component>
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..612bba4d8dcc0167332f52c022e865d690e8b932
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++Description: enable distro julia packages so that they are immediately importable after install
++See: https://github.com/cdluminate/DistroHelper.jl
++     https://github.com/JuliaLang/julia/issues/30528
++Author: Mo Zhou
++
++diff --git a/base/initdefs.jl b/base/initdefs.jl
++index f95c22b4..e63d395b 100644
++--- a/base/initdefs.jl
+++++ b/base/initdefs.jl
++@@ -61,6 +61,7 @@ end
++ # entries starting with `@` are named environments:
++ #  - the first three `#`s in a named environment are replaced with version numbers
++ #  - `@stdlib` is a special name for the standard library and expands to its path
+++#  - `@distro` is a special name for distributions' vendored julia packages
++ 
++ # if you want a current env setup, use direnv and
++ # have your .envrc do something like this:
++@@ -70,7 +71,7 @@ end
++ # this will inherit an existing JULIA_LOAD_PATH value or if there is none, leave
++ # a trailing empty entry in JULIA_LOAD_PATH which will be replaced with defaults.
++ 
++-const DEFAULT_LOAD_PATH = ["@", "@v#.#", "@stdlib"]
+++const DEFAULT_LOAD_PATH = ["@", "@v#.#", "@stdlib", "@distro"]
++ 
++ """
++     LOAD_PATH
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cd81c44fa3422344872f155450c92a442774b009
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++Description: Let it download the embedded source tarball through a file:// URI
++Author: Mo Zhou
++Last-Update: 20180711
++Forward: no need
++
++Index: julia/deps/libuv.mk
++===================================================================
++--- julia.orig/deps/libuv.mk
+++++ julia/deps/libuv.mk
++@@ -1,6 +1,5 @@
++ ## LIBUV ##
++-LIBUV_GIT_URL:=git://github.com/JuliaLang/libuv.git
++-LIBUV_TAR_URL=https://api.github.com/repos/JuliaLang/libuv/tarball/$1
+++LIBUV_TAR_URL=file://$(CURDIR)/../debian/embedded/libuv-$1.tar.gz
++ $(eval $(call git-external,libuv,LIBUV,configure,,$(SRCCACHE)))
++ 
++ UV_CFLAGS := -D_GNU_SOURCE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8e6de143385be13af523e03796101c34eb103f3f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++Description: prevent upstream build system from accessing internet
++Author: Mo Zhou
++Forwarded: no need
++Last-Update: 20180719
++Index: julia/deps/libwhich.mk
++===================================================================
++--- julia.orig/deps/libwhich.mk
+++++ julia/deps/libwhich.mk
++@@ -1,6 +1,5 @@
++ ## LIBWHICH ##
++-LIBWHICH_GIT_URL := git://github.com/vtjnash/libwhich.git
++-LIBWHICH_TAR_URL = https://api.github.com/repos/vtjnash/libwhich/tarball/$1
+++LIBWHICH_TAR_URL = file://$(CURDIR)/../debian/embedded/libwhich-$1.tar.gz
++ $(eval $(call git-external,libwhich,LIBWHICH,,,$(BUILDDIR)))
++ 
++ LIBWHICH_OBJ_LIB := $(build_depsbindir)/libwhich
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e8ea05a80c4b86bac6fbc639e87e2c7aa829bdc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++Index: julia/deps/llvm.mk
++===================================================================
++--- julia.orig/deps/llvm.mk
+++++ julia/deps/llvm.mk
++@@ -161,7 +161,7 @@ ifeq ($(BUILD_LLDB),0)
++ LLVM_CMAKE += -DLLVM_TOOL_LLDB_BUILD=OFF
++ endif
++ 
++-LLVM_SRC_URL := http://releases.llvm.org/$(LLVM_VER)
+++LLVM_SRC_URL := file://$(shell pwd)/../debian/embedded/$(LLVM_VER)
++ 
++ ifneq ($(LLVM_CLANG_TAR),)
++ $(LLVM_CLANG_TAR): | $(SRCCACHE)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0d58665d6d5915651bb08bb05a720dcf7de1da87
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++Description: Prevent upstream build system from downloading Pkg.jl
++Forward: no need
++Author: Mo Zhou
++Index: julia/stdlib/Makefile
++===================================================================
++--- julia.orig/stdlib/Makefile
+++++ julia/stdlib/Makefile
++@@ -22,7 +22,7 @@ STDLIBS-EXT = Pkg
++ 
++ # Download and extract Pkg
++ PKG_GIT_URL := git://github.com/JuliaLang/Pkg.jl.git
++-PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1
+++PKG_TAR_URL = file://$(CURDIR)/../debian/embedded/$1
++ $(eval $(call git-external,Pkg,PKG,,,$(BUILDDIR)))
++ $(BUILDDIR)/$(PKG_SRC_DIR)/build-compiled: $(BUILDDIR)/$(PKG_SRC_DIR)/source-extracted
++      @# no build steps
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8c640a5b8e466c5684cb9a78df78ace6b84ce235
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++Description: Prevent the build system from downloading anything while building docs.
++Forwarded: no need.
++Author: Mo Zhou
++Last-Update: 2018-07-03
++
++Index: julia/doc/make.jl
++===================================================================
++--- julia.orig/doc/make.jl
+++++ julia/doc/make.jl
++@@ -3,8 +3,7 @@ empty!(LOAD_PATH)
++ push!(LOAD_PATH, @__DIR__, "@stdlib")
++ empty!(DEPOT_PATH)
++ pushfirst!(DEPOT_PATH, joinpath(@__DIR__, "deps"))
++-using Pkg
++-Pkg.instantiate()
+++push!(LOAD_PATH, "../debian/embedded")
++ 
++ using Documenter
++ 
++Index: julia/doc/Makefile
++===================================================================
++--- julia.orig/doc/Makefile
+++++ julia/doc/Makefile
++@@ -23,10 +23,8 @@ help:
++ DOCUMENTER_OPTIONS := linkcheck=$(linkcheck) doctest=$(doctest) buildroot=$(call cygpath_w,$(BUILDROOT))
++ 
++ UnicodeData.txt:
++-     $(JLDOWNLOAD) http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt
++-
++-deps: UnicodeData.txt
++-     $(JLCHECKSUM) UnicodeData.txt
+++deps:
+++     true
++ 
++ clean:
++      -rm -rf _build/* deps/* docbuild.log UnicodeData.txt
++Index: julia/doc/Project.toml
++===================================================================
++--- julia.orig/doc/Project.toml
+++++ julia/doc/Project.toml
++@@ -1,2 +0,0 @@
++-[deps]
++-Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8aee92f71433c71cdd448d4bec0a5cec357b5415
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++diff --git a/debian/embedded/Documenter.jl-0.20.0/src/Writers/LaTeXWriter.jl b/debian/embedded/Documenter.jl-0.20.0/src/Writers/LaTeXWriter.jl
++index f442d959..51ce92e7 100644
++--- a/debian/embedded/Documenter.jl-0.20.0/src/Writers/LaTeXWriter.jl
+++++ b/debian/embedded/Documenter.jl-0.20.0/src/Writers/LaTeXWriter.jl
++@@ -87,7 +87,7 @@ function render(doc::Documents.Document)
++                 outdir = joinpath(doc.user.root, doc.user.build)
++                 pdf = replace("$(doc.user.sitename).pdf", " " => "")
++                 try
++-                    run(`latexmk -f -interaction=nonstopmode -view=none -lualatex -shell-escape $file`)
+++                    run(`latexmk -silent -f -interaction=nonstopmode -view=none -lualatex -shell-escape $file`)
++                 catch err
++                     Utilities.warn("failed to compile. Check generated LaTeX file.")
++                     cp(file, joinpath(outdir, file); force = true)
++
++diff --git a/debian/embedded/Documenter.jl-0.21.0/src/Writers/LaTeXWriter.jl b/debian/embedded/Documenter.jl-0.21.0/src/Writers/LaTeXWriter.jl
++index 9b98b34e..21727866 100644
++--- a/debian/embedded/Documenter.jl-0.21.0/src/Writers/LaTeXWriter.jl
+++++ b/debian/embedded/Documenter.jl-0.21.0/src/Writers/LaTeXWriter.jl
++@@ -139,7 +139,7 @@ function compile_tex(doc::Documents.Document, settings::LaTeX, texfile::String)
++         Sys.which("latexmk") === nothing && (@error "LaTeXWriter: latexmk command not found."; return false)
++         @info "LaTeXWriter: using latexmk to compile tex."
++         try
++-            piperun(`latexmk -f -interaction=nonstopmode -view=none -lualatex -shell-escape $texfile`)
+++            piperun(`latexmk -silent -f -interaction=nonstopmode -view=none -lualatex -shell-escape $texfile`)
++             return true
++         catch err
++             logs = cp(pwd(), mktempdir(); force=true)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..30caa21f5c00274f4c2ef6a52ce5550ad5f09821
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++Description: build documentation using Debian's unicode data,
++ instead of a downloaded one
++Forwarded: no need
++Author: Mo Zhou
++Index: julia/doc/src/manual/unicode-input.md
++===================================================================
++--- julia.orig/doc/src/manual/unicode-input.md
+++++ julia/doc/src/manual/unicode-input.md
++@@ -31,7 +31,7 @@ function tab_completions(symbols...)
++ end
++ 
++ function unicode_data()
++-    file = normpath(@__DIR__, "..", "..", "..", "..", "..", "doc", "UnicodeData.txt")
+++    file = "/usr/share/unicode/UnicodeData.txt"
++     names = Dict{UInt32, String}()
++     open(file) do unidata
++         for line in readlines(unidata)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4dbc121945876d0596beb19a40e6f0d9b9ba93a0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++Description: LLVM's cmake doesn't install stuff to multiarch directory, which
++ breaks julia installation when MULTIARCH* options in Make.inc is turned on.
++ This hacky solution aims to workaround installation failure.
++See: https://github.com/JuliaLang/julia/issues/27922
++Forward: no need
++Author: Mo Zhou
++Index: julia/deps/llvm.mk
++===================================================================
++--- julia.orig/deps/llvm.mk
+++++ julia/deps/llvm.mk
++@@ -560,6 +560,7 @@ ifeq ($(OS),Darwin)
++ # https://github.com/JuliaLang/julia/issues/29981
++ LLVM_INSTALL += && ln -s libLLVM.dylib $2$$(build_shlibdir)/libLLVM-$$(LLVM_VER_SHORT).dylib
++ endif
+++LLVM_INSTALL += && find $2 -type f,l -name 'libLLVM*so*' -print -exec install -Dv '{}' $(shell pwd)/../$$(libdir)/julia/ \;
++ 
++ $(eval $(call staged-install,llvm,llvm-$$(LLVM_VER)/build_$$(LLVM_BUILDTYPE), \
++      LLVM_INSTALL,,,))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..830f08c5e216d0d7ab9fc75b706de538068e4ef4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++If DESTDIR is defined in d/rules, embedded LLVM installation would break.
++If DESTDIR is not defined in d/rules, embedded LLVM installation works, but Julia breaks.
++This hack makes both LLVM and Julia happy.
++
++Index: julia/Makefile
++===================================================================
++--- julia.orig/Makefile
+++++ julia/Makefile
++@@ -328,6 +328,7 @@ JL_PRIVATE_LIBS-0 += libgfortran libgcc_
++ endif
++ 
++ 
+++override DESTDIR=./debian/tmp/
++ install: $(build_depsbindir)/stringreplace $(BUILDROOT)/doc/_build/html/en/index.html
++      @$(MAKE) $(QUIET_MAKE) all
++      @for subdir in $(bindir) $(datarootdir)/julia/stdlib/$(VERSDIR) $(docdir) $(man1dir) $(includedir)/julia $(libdir) $(private_libdir) $(sysconfdir); do \
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bb3646489bfe4f4f288dc8fec46192606a10d908
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++Description: Let the upstream downloader used during build be verbose,
++         and prevent it from accessing internet.
++Author: Mo Zhou
++Last-Update: 20180711
++Forwarded: no need
++
++Index: julia/deps/tools/jldownload
++===================================================================
++--- julia.orig/deps/tools/jldownload
+++++ julia/deps/tools/jldownload
++@@ -2,6 +2,7 @@
++ #
++ # usage: jldownload [<output-filename>] <url>
++ #
+++set -x
++ 
++ CACHE_HOST=https://cache.julialang.org
++ 
++@@ -44,4 +45,5 @@ fi
++ # forward to the original URL if it has not cached this download yet, or
++ # if the URL is not cacheable.  We fallback to directly querying the
++ # uncached URL to protect against cache service downtime
++-$GETURL $CACHE_URL || $GETURL $URL
+++#$GETURL $CACHE_URL || $GETURL $URL
+++$GETURL $URL
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5f2081e9cf2b79d7cb83dc011c8228a3d547f10d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++Description: Avoid baseline violation on armhf
++Forwarded: not-yet
++Bug-Debian: https://bugs.debian.org/919183
++Author: Graham Inggs <ginggs@debian.org>
++Last-Update: 2018-01-22
++
++--- a/deps/llvm.mk
+++++ b/deps/llvm.mk
++@@ -508,6 +508,7 @@
++ $(eval $(call LLVM_PATCH,llvm-D50167-scev-umin))
++ $(eval $(call LLVM_PATCH,llvm-windows-race))
++ $(eval $(call LLVM_PATCH,llvm-rL326967-aligned-load)) # remove for 7.0
+++$(eval $(call LLVM_PATCH,clang-arm-default-vfp3-on-armv7a))
++ endif # LLVM_VER
++ 
++ # Remove hardcoded OS X requirements in compilter-rt cmake build
++--- /dev/null
+++++ b/deps/patches/clang-arm-default-vfp3-on-armv7a.patch
++@@ -0,0 +1,24 @@
+++--- a/include/llvm/Support/ARMTargetParser.def
++++++ b/include/llvm/Support/ARMTargetParser.def
+++@@ -75,7 +75,7 @@ ARM_ARCH("armv6kz", ARMV6KZ, "6KZ", "v6k
+++ ARM_ARCH("armv6-m", ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M,
+++           FK_NONE, ARM::AEK_NONE)
+++ ARM_ARCH("armv7-a", ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7,
+++-          FK_NEON, ARM::AEK_DSP)
++++          FK_VFPV3_D16, ARM::AEK_DSP)
+++ ARM_ARCH("armv7ve", ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
+++           FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+++           ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
+++--- a/lib/Target/ARM/ARM.td
++++++ b/lib/Target/ARM/ARM.td
+++@@ -530,7 +530,8 @@ def ARMv6sm   : Architecture<"armv6s-m",
+++                                                        FeatureMClass]>;
+++ 
+++ def ARMv7a    : Architecture<"armv7-a",   "ARMv7a",   [HasV7Ops,
+++-                                                       FeatureNEON,
++++                                                       FeatureVFP3,
++++                                                       FeatureD16,
+++                                                        FeatureDB,
+++                                                        FeatureDSP,
+++                                                        FeatureAClass]>;
+++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e441fa3f39ee035522af1115e1648138a84862bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++Description: don't try to touch libunwind when it's disabled
++Author: Mo Zhou
++Forwarded: https://github.com/JuliaLang/julia/issues/29163
++Index: julia/base/Makefile
++===================================================================
++--- julia.orig/base/Makefile
+++++ julia/base/Makefile
++@@ -192,7 +192,7 @@ $(eval $(call symlink_system_library,lib
++ $(eval $(call symlink_system_library,libumfpack,SUITESPARSE))
++ $(eval $(call symlink_system_library,libspqr,SUITESPARSE))
++ $(eval $(call symlink_system_library,libsuitesparseconfig,SUITESPARSE))
++-ifneq ($(DISABLE_LIBUNWIND),0)
+++ifneq ($(DISABLE_LIBUNWIND), 1)
++ $(eval $(call symlink_system_library,libunwind,LIBUNWIND))
++ endif
++ endif # WINNT
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dd362e5008eef096f86c064b66df7ff978137d49
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++Description: Do not compile and install the debugging version of Julia
++Author: Sébastien Villemot <sebastien@debian.org>
++Author: Mo Zhou <cdluminate@gmail.com>
++Forwarded: not-needed
++Last-Update: 2018-07-19
++---
++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
++Index: julia/Makefile
++===================================================================
++--- julia.orig/Makefile
+++++ julia/Makefile
++@@ -4,7 +4,7 @@ include $(JULIAHOME)/Make.inc
++ VERSDIR := v`cut -d. -f1-2 < $(JULIAHOME)/VERSION`
++ 
++ default: $(JULIA_BUILD_MODE) # contains either "debug" or "release"
++-all: debug release
+++all: release
++ 
++ # sort is used to remove potential duplicates
++ DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0b6106fcd16f08fb595ecd67fb04234d47019ed2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,59 @@@
++Purpose: fix lintian error caused by embedded documenter
++Author: Mo Zhou <cdluminate@gmail.com>
++
++--- a/debian/embedded/Documenter/assets/html/documenter.css
+++++ b/debian/embedded/Documenter/assets/html/documenter.css
++@@ -21,7 +21,7 @@ body, input {
++ }
++ 
++ pre, code, kbd {
++-  font-family: 'Roboto Mono', Monaco, courier, monospace;
+++  font-family: Inconsolata, Monaco, courier, monospace;
++   font-size: 0.90em;
++ }
++ 
++--- a/debian/embedded/Documenter/assets/html/documenter.js
+++++ b/debian/embedded/Documenter/assets/html/documenter.js
++@@ -7,13 +7,14 @@
++ 
++ requirejs.config({
++     paths: {
++-        'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min',
++-        'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min',
++-        'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.9.3/headroom.min',
++-        'mathjax': 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML',
++-        'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min',
++-        'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/languages/julia.min',
++-        'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/languages/julia-repl.min',
+++        'jquery': 'file:///usr/share/javascript/jquery/jquery.min.js',
+++        'jqueryui': 'file:///usr/share/javascript/jquery-ui/jquery-ui.min.js',
+++             //'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.9.3/headroom.min',
+++             'headroom': 'http://localhost',
+++        'mathjax': 'file:///usr/share/javascript/mathjax/MathJax.js?config=TeX-AMS_HTML',
+++        'highlight': 'file:///usr/lib/nodejs/highlight.js/highlight.js',
+++        'highlight-julia': 'file:////usr/lib/nodejs/highlight.js/languages/julia.js',
+++        'highlight-julia-repl': 'file:////usr/lib/nodejs/highlight.js/languages/julia-repl.js',
++     },
++     shim: {
++         'mathjax' : {
++
++--- a/debian/embedded/Documenter/src/Writers/HTMLWriter.jl
+++++ b/debian/embedded/Documenter/src/Writers/HTMLWriter.jl
++@@ -98,11 +98,12 @@ import ...Documenter:
++ import ...Utilities.DOM: DOM, Tag, @tags
++ using ...Utilities.MDFlatten
++ 
++-const requirejs_cdn = "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"
++-const normalize_css = "https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css"
++-const google_fonts = "https://fonts.googleapis.com/css?family=Lato|Roboto+Mono"
++-const fontawesome_css = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"
++-const highlightjs_css = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"
+++const requirejs_cdn = "file:///usr/share/javascript/requirejs/require.min.js"
+++const normalize_css = "file:///usr/share/javascript/normalize.css/normalize.min.css"
+++const google_fonts = "file:///usr/share/doc/julia-doc/fontface.css"
+++const fontawesome_css = "file:///usr/share/fonts-font-awesome/css/font-awesome.min.css"
+++const highlightjs_css = "file:///usr/share/javascript/highlight.js/styles/default.css"
+++
++ 
++ """
++ [`HTMLWriter`](@ref)-specific globals that are passed to [`domify`](@ref) and
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9aa36ee66042fbee47c024744e4ada76ce8c9dd2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++Description: Julia requires SSE2 on i386
++ This patch adds an explicit error message if the CPU does not support SSE2.
++ The CPU features are queried using the x86 CPUID opcode. The wrapper function
++ __get_cpuid() is provided by GCC and Clang. See <cpuid.h> for the list of
++ supported CPU extension flags.
++Author: Sébastien Villemot <sebastien@debian.org>
++Author: Peter Colberg <peter@colberg.org>
++Bug: https://github.com/JuliaLang/julia/issues/7185
++Forwarded: no
++Last-Update: 2015-11-01
++---
++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
++Index: julia/src/codegen.cpp
++===================================================================
++--- julia.orig/src/codegen.cpp
+++++ julia/src/codegen.cpp
++@@ -26,6 +26,9 @@
++ #endif
++ 
++ #include <setjmp.h>
+++#ifdef __i386__
+++#include <cpuid.h>
+++#endif
++ #include <string>
++ #include <sstream>
++ #include <fstream>
++@@ -7378,6 +7381,15 @@ static void init_julia_llvm_env(Module *
++ 
++ extern "C" void *jl_init_llvm(void)
++ {
+++#ifdef __i386__
+++    unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
+++    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
+++    if (!(edx & bit_SSE2)) {
+++        fprintf(stderr, "Your processor does not have SSE2 extension, which is required by Julia. Exiting.\n");
+++        exit(EXIT_FAILURE);
+++    }
+++#endif
+++
++     const char *const argv_tailmerge[] = {"", "-enable-tail-merge=0"}; // NOO TOUCHIE; NO TOUCH! See #922
++     cl::ParseCommandLineOptions(sizeof(argv_tailmerge)/sizeof(argv_tailmerge[0]), argv_tailmerge, "disable-tail-merge\n");
++ #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..732250aa75835b3695f977def6bee2ac8cf0880c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,32 @@@
++# Build system and feature
++jldownload-verbose-fakedownload.patch
++support-noopt.patch
++require-sse2-on-i386.patch
++no-debug-version.patch
++do-not-download-libuv.patch
++do-not-download-libwhich.patch
++do-not-download-pkgjl.patch
++do-not-download-llvm.patch
++doc-make.patch
++doc-unicode-data-path.patch
++make-unwind-logic-error.patch
++install-embedded-llvm-hack.patch
++install-julia-hack.patch
++llvm-armhf-baseline.patch
++
++# distro integration, wip, experimental, disabled by default
++#default-load-path-distro.patch
++
++# Misc enhancement
++appstream.patch
++
++# Test
++test-skip-sigint.patch
++test-skip-i386-spec.patch
++test-skip-dns-ubuntu.patch
++
++
++# This patch is for embedded sources. Already pre-applied.
++# privacy-breach.patch
++# doc-silent.patch
++add-libatomic.patch
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..af8cfd37487c5565ce6f656c8d13d906bb31d040
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,50 @@@
++Description: Remove hardcoded GCC optimization flags
++ This is necessary in order to make DEB_BUILD_OPTIONS=noopt work as expected.
++ .
++ Note that the hack on llvm-config --cxxflags is not absolutely needed, because
++ the -O2 that it brings come before the -O0 brought by dpkg-buildflags. But I
++ leave it for clarity.
++Author: Sébastien Villemot <sebastien@debian.org>
++Forwarded: not-needed
++Last-Update: 2015-11-17
++---
++This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
++Index: julia/Make.inc
++===================================================================
++--- julia.orig/Make.inc
+++++ julia/Make.inc
++@@ -413,7 +413,7 @@ ifneq ($(OS), WINNT)
++ JCXXFLAGS += -pedantic
++ endif
++ DEBUGFLAGS := -O0 -ggdb2 -DJL_DEBUG_BUILD -fstack-protector-all
++-SHIPFLAGS := -O3 -ggdb2 -falign-functions
+++SHIPFLAGS := -ggdb2 -falign-functions
++ endif
++ 
++ ifeq ($(USECLANG),1)
++Index: julia/deps/suitesparse.mk
++===================================================================
++--- julia.orig/deps/suitesparse.mk
+++++ julia/deps/suitesparse.mk
++@@ -111,7 +111,7 @@ endif
++ 
++ $(build_shlibdir)/libsuitesparse_wrapper.$(SHLIB_EXT): $(SRCDIR)/SuiteSparse_wrapper.c
++      mkdir -p $(build_shlibdir)
++-     $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -O2 -shared $(fPIC) $(SUITESPARSE_INC) $< -o $@ $(SUITESPARSE_LIB)
+++     $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared $(fPIC) $(SUITESPARSE_INC) $< -o $@ $(SUITESPARSE_LIB)
++      $(INSTALL_NAME_CMD)libsuitesparse_wrapper.$(SHLIB_EXT) $@
++      touch -c $@
++ 
++Index: julia/src/Makefile
++===================================================================
++--- julia.orig/src/Makefile
+++++ julia/src/Makefile
++@@ -136,7 +136,7 @@ $(BUILDDIR)/%.o: $(SRCDIR)/%.c $(HEADERS
++ $(BUILDDIR)/%.dbg.obj: $(SRCDIR)/%.c $(HEADERS) | $(BUILDDIR)
++      @$(call PRINT_CC, $(CC) $(CPPFLAGS) $(CFLAGS) $(DEBUGFLAGS) -c $< -o $@)
++ $(BUILDDIR)/%.o: $(SRCDIR)/%.cpp $(SRCDIR)/llvm-version.h $(HEADERS) $(LLVM_CONFIG_ABSOLUTE) | $(BUILDDIR)
++-     @$(call PRINT_CC, $(CXX) $(shell $(LLVM_CONFIG_HOST) --cxxflags) $(CPPFLAGS) $(CXXFLAGS) $(SHIPFLAGS) $(CXX_DISABLE_ASSERTION) -c $< -o $@)
+++     @$(call PRINT_CC, $(CXX) $(shell $(LLVM_CONFIG_HOST) --cxxflags | sed 's/^/ /;s/$$/ /;s/\s-O.\s/ /') $(CPPFLAGS) $(CXXFLAGS) $(SHIPFLAGS) $(CXX_DISABLE_ASSERTION) -c $< -o $@)
++ $(BUILDDIR)/%.dbg.obj: $(SRCDIR)/%.cpp $(SRCDIR)/llvm-version.h $(HEADERS) $(LLVM_CONFIG_ABSOLUTE) | $(BUILDDIR)
++      @$(call PRINT_CC, $(CXX) $(shell $(LLVM_CONFIG_HOST) --cxxflags) $(CPPFLAGS) $(CXXFLAGS) $(DEBUGFLAGS) -c $< -o $@)
++ 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8ec3904443fb51eea32659ce65036e1f75bf6009
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,49 @@@
++Description: Skip DNS tests which fail on Ubuntu autopkgtest infrastructure
++Author: Graham Inggs <ginggs@debian.org>
++Last-Update: 2018-10-01
++
++Index: julia/stdlib/Sockets/test/runtests.jl
++===================================================================
++--- julia.orig/stdlib/Sockets/test/runtests.jl
+++++ julia/stdlib/Sockets/test/runtests.jl
++@@ -151,25 +151,25 @@ defaultport = rand(2000:4000)
++ end
++ 
++ @testset "getnameinfo on some unroutable IP addresses (RFC 5737)" begin
++-    @test getnameinfo(ip"192.0.2.1") == "192.0.2.1"
++-    @test getnameinfo(ip"198.51.100.1") == "198.51.100.1"
++-    @test getnameinfo(ip"203.0.113.1") == "203.0.113.1"
++-    @test getnameinfo(ip"0.1.1.1") == "0.1.1.1"
++-    @test getnameinfo(ip"::ffff:0.1.1.1") == "::ffff:0.1.1.1"
++-    @test getnameinfo(ip"::ffff:192.0.2.1") == "::ffff:192.0.2.1"
++-    @test getnameinfo(ip"2001:db8::1") == "2001:db8::1"
+++#    @test getnameinfo(ip"192.0.2.1") == "192.0.2.1"
+++#    @test getnameinfo(ip"198.51.100.1") == "198.51.100.1"
+++#    @test getnameinfo(ip"203.0.113.1") == "203.0.113.1"
+++#    @test getnameinfo(ip"0.1.1.1") == "0.1.1.1"
+++#    @test getnameinfo(ip"::ffff:0.1.1.1") == "::ffff:0.1.1.1"
+++#    @test getnameinfo(ip"::ffff:192.0.2.1") == "::ffff:192.0.2.1"
+++#    @test getnameinfo(ip"2001:db8::1") == "2001:db8::1"
++ end
++ 
++ @testset "getnameinfo on some valid IP addresses" begin
++     @test !isempty(getnameinfo(ip"::")::String)
++-    @test !isempty(getnameinfo(ip"0.0.0.0")::String)
++-    @test !isempty(getnameinfo(ip"10.1.0.0")::String)
++-    @test !isempty(getnameinfo(ip"10.1.0.255")::String)
++-    @test !isempty(getnameinfo(ip"10.1.255.1")::String)
++-    @test !isempty(getnameinfo(ip"255.255.255.255")::String)
++-    @test !isempty(getnameinfo(ip"255.255.255.0")::String)
++-    @test !isempty(getnameinfo(ip"192.168.0.1")::String)
++-    @test !isempty(getnameinfo(ip"::1")::String)
+++#    @test !isempty(getnameinfo(ip"0.0.0.0")::String)
+++#    @test !isempty(getnameinfo(ip"10.1.0.0")::String)
+++#    @test !isempty(getnameinfo(ip"10.1.0.255")::String)
+++#    @test !isempty(getnameinfo(ip"10.1.255.1")::String)
+++#    @test !isempty(getnameinfo(ip"255.255.255.255")::String)
+++#    @test !isempty(getnameinfo(ip"255.255.255.0")::String)
+++#    @test !isempty(getnameinfo(ip"192.168.0.1")::String)
+++#    @test !isempty(getnameinfo(ip"::1")::String)
++ end
++ 
++ @testset "getaddrinfo" begin
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4de449bfa265bf011dd5f948203aeb1778a9b2f5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,40 @@@
++Description: skip some tests specifically for i386
++Author: Mo Zhou
++Forward: no need.
++Index: julia/test/compiler/compiler.jl
++===================================================================
++--- julia.orig/test/compiler/compiler.jl
+++++ julia/test/compiler/compiler.jl
++@@ -879,11 +879,15 @@ function break_21369()
++             end
++             i += 1
++         end
+++             if !(Sys.ARCH in [:i386, :i686])
++         @test fr.func === :break_21369
+++             end
++         rethrow()
++     end
++ end
+++if !(Sys.ARCH in [:i386, :i686])
++ @test_throws ErrorException break_21369()  # not TypeError
+++end
++ 
++ # issue #17003
++ abstract type AArray_17003{T,N} end
++Index: julia/test/stacktraces.jl
++===================================================================
++--- julia.orig/test/stacktraces.jl
+++++ julia/test/stacktraces.jl
++@@ -76,10 +76,12 @@ let ct = current_task()
++     @test try_stacktrace()[1] == StackFrame(:try_stacktrace, @__FILE__, line_numbers[2])
++ 
++     # Test try...catch with catch_backtrace
+++     if !(Sys.ARCH in [:i386, :i686])
++     @test try_catch()[1:2] == [
++         StackFrame(:bad_function, @__FILE__, line_numbers[1]),
++         StackFrame(:try_catch, @__FILE__, line_numbers[3])
++     ]
+++     end
++ end
++ 
++ module inlined_test
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6816779cb3c8bed856ebf19c2241f0478aa7363d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++Description: temporarily skip this test which causes random test failure. Further investigation needed.
++Forward: never
++Last-Update: 20180812
++Author: Mo Zhou
++
++Index: julia/test/stress.jl
++===================================================================
++--- julia.orig/test/stress.jl
+++++ julia/test/stress.jl
++@@ -91,16 +91,3 @@ if !Sys.iswindows()
++         test_22566()
++     end
++ end  # !Sys.iswindows
++-
++-# sig 2 is SIGINT per the POSIX.1-1990 standard
++-if !Sys.iswindows()
++-    ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0)
++-    @test_throws InterruptException begin
++-        ccall(:kill, Cvoid, (Cint, Cint,), getpid(), 2)
++-        for i in 1:10
++-            Libc.systemsleep(0.1)
++-            ccall(:jl_gc_safepoint, Cvoid, ()) # wait for SIGINT to arrive
++-        end
++-    end
++-    ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 1)
++-end
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..74976d1714e195e8714e12a4639ac78975d522bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++# This example changes the default prompt string.
++# Just include this file in ~/.julia/config/startup.jl
++# For more tweaks to your REPL, please install the "OhMyREPL" package.
++import REPL
++function myrepl(repl)
++    repl.interface = REPL.setup_interface(repl)
++    repl.interface.modes[1].prompt = "⛬ >"
++    return
++end
++atreplinit(myrepl)
diff --cc debian/rules
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b17b5eed1ccd1f10402f262c0214b5026b685d14
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,195 @@@
++#!/usr/bin/make -f
++include /usr/share/dpkg/default.mk
++export DEB_BUILD_MAINT_OPTIONS=hardening=+all
++
++# Disable unaligned access on armhf
++ifneq (,$(filter $(DEB_HOST_ARCH),armhf))
++      export DEB_CFLAGS_MAINT_APPEND += -mno-unaligned-access
++endif
++
++# Ensure pcre_h.jl and errno_h.jl are sorted reproducibly
++export LC_ALL=C.UTF-8
++# HOME is needed to avoid "mkdir(): Permission denied" while building docs.
++# Some tests also need a HOME directory.
++export HOME=/tmp
++# If you want to do a custom build of Julia against MKL, set it to 1.
++export CUSTOM_MKL ?= 0
++# If you want to do a custom build for native machine architecture
++export CUSTOM_NATIVE ?= 0
++
++# NOTES:
++# 1. Some of these flags come from upstream's Make.inc .
++# 2. To enable USE_BLAS64=0 (ILP64), we need to set INTERFACE64=1 for OpenBLAS.
++# 3. Julia is tightly coupled with a specific libuv1 version. we cannot use the one provided in archive.
++# 4. ∴ is unicode "therefore", ⛬  is unicode "historic site" https://unicode-table.com/en/26EC/
++COMMON_FLAGS = \
++      prefix=/usr \
++      sysconfdir=/etc \
++      MULTIARCH=$(DEB_HOST_MULTIARCH) \
++      MULTIARCH_INSTALL=1 \
++      NO_GIT=1 \
++      TAGGED_RELEASE_BANNER='$(DEB_VENDOR) ⛬  julia/$(DEB_VERSION)' \
++      USE_BLAS64=0  \
++      USE_LLVM_SHLIB=1 \
++      USE_SYSTEM_BLAS=1 \
++      USE_SYSTEM_CURL=1 \
++      USE_SYSTEM_DSFMT=1 \
++      USE_SYSTEM_GMP=1 \
++      USE_SYSTEM_LAPACK=1 \
++      USE_SYSTEM_LIBGIT2=1 \
++      USE_SYSTEM_LIBSSH2=1 \
++      USE_SYSTEM_LIBUNWIND=1 \
++      USE_SYSTEM_LIBUV=0 \
++      USE_SYSTEM_LLVM=0 \
++      USE_SYSTEM_MBEDTLS=1 \
++      USE_SYSTEM_MPFR=1 \
++      USE_SYSTEM_OPENSPECFUN=1 \
++      USE_SYSTEM_PATCHELF=1 \
++      USE_SYSTEM_PCRE=1 \
++      USE_SYSTEM_SUITESPARSE=1 \
++      USE_SYSTEM_UTF8PROC=1 \
++      VERBOSE=1
++
++# Set architecture specific CPU targets. See: #910784
++ifneq (,$(filter $(DEB_HOST_ARCH),amd64 kfreebsd-amd64 x32))
++COMMON_FLAGS += MARCH=x86-64 \
++      JULIA_CPU_TARGET="generic;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)"
++else ifneq (,$(filter $(DEB_HOST_ARCH),i386 hurd-i386 kfreebsd-i386))
++COMMON_FLAGS += MARCH=pentium4 \
++      JULIA_CPU_TARGET="pentium4;sandybridge,-xsaveopt,clone_all"
++else ifneq (,$(filter $(DEB_HOST_ARCH),armhf))
++COMMON_FLAGS += JULIA_CPU_TARGET="arm1176jzf-s"
++else ifneq (,$(filter $(DEB_HOST_ARCH),ppc64el))
++COMMON_FLAGS += JULIA_CPU_TARGET="pwr8"
++else
++COMMON_FLAGS += JULIA_CPU_TARGET="generic"
++endif
++
++# Use libopenlibm on architectures that have it
++ifneq (,$(filter $(DEB_HOST_ARCH),amd64 kfreebsd-amd64 x32))
++COMMON_FLAGS += USE_SYSTEM_OPENLIBM=1 USE_SYSTEM_LIBM=0
++else ifneq (,$(filter $(DEB_HOST_ARCH),i386 hurd-i386 kfreebsd-i386))
++COMMON_FLAGS += USE_SYSTEM_OPENLIBM=1 USE_SYSTEM_LIBM=0
++else ifneq (,$(filter $(DEB_HOST_ARCH),arm64 armhf mips mips64el mipsel powerpc ppc64 ppc64el))
++COMMON_FLAGS += USE_SYSTEM_OPENLIBM=1 USE_SYSTEM_LIBM=0
++else
++# Use libm elsewhere
++COMMON_FLAGS += USE_SYSTEM_OPENLIBM=0 USE_SYSTEM_LIBM=1
++endif
++
++# Use libopenblas on architectures that have it
++ifneq (,$(filter $(DEB_HOST_ARCH),amd64 arm64 armhf i386 kfreebsd-amd64 kfreebsd-i386 mips64el ppc64el s390x))
++COMMON_FLAGS += LIBBLAS=-lopenblas LIBBLASNAME=libopenblas \
++                LIBLAPACK=-lopenblas LIBLAPACKNAME=libopenblas
++else
++# Use libblas and liblapack elsewhere
++COMMON_FLAGS += LIBBLAS=-lblas LIBBLASNAME=libblas \
++                LIBLAPACK=-llapack LIBLAPACKNAME=liblapack
++endif
++
++# [s390x] Disable libunwind
++ifneq (,$(filter $(DEB_HOST_ARCH),s390x))
++COMMON_FLAGS += DISABLE_LIBUNWIND=1
++endif
++
++# Set number of parallel workers for tests
++ifneq (,$(filter parallel=1,$(DEB_BUILD_OPTIONS)))
++TESTS_ENV += JULIA_CPU_THREADS=2
++else ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
++TESTS_ENV += JULIA_CPU_THREADS=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
++else
++TESTS_ENV += JULIA_CPU_THREADS=2
++endif
++# Restart workers exceeding maximum resident memory size (requires JULIA_CPU_THREADS >= 2)
++TESTS_ENV += JULIA_TEST_MAXRSS_MB=500
++
++ifeq (1,$(CUSTOM_MKL))
++COMMON_FLAGS += USE_INTEL_MKL=1 USE_BLAS64=1 \
++                LIBBLAS=-lmkl_rt LIBBLASNAME=libmkl_rt \
++                LIBLAPACK=-lmkl_rt LIBLAPACKNAME=libmkl_rt \
++                              MKLROOT=/usr MKLLIB=/usr/lib/$(DEB_HOST_MULTIARCH)
++endif
++ifeq (1,$(CUSTOM_NATIVE))
++COMMON_FLAGS += MARCH=native JULIA_CPU_TARGET=native
++endif
++
++
++%:
++      dh $@
++
++override_dh_auto_build-arch:
++      dh_auto_build -- $(COMMON_FLAGS)
++
++override_dh_auto_build-indep:
++      dh_auto_build -- $(COMMON_FLAGS)
++      -$(MAKE) -C doc pdf
++
++override_dh_auto_test-arch:
++ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
++ifeq (,$(filter $(DEB_HOST_ARCH),amd64 i386))
++      -env $(TESTS_ENV) make -C test $(COMMON_FLAGS)
++else
++      env $(TESTS_ENV) make -C test $(COMMON_FLAGS)
++endif
++endif
++
++override_dh_auto_test-indep:
++
++override_dh_auto_clean:
++      make $(COMMON_FLAGS) distcleanall
++      make -f debian/shlibdeps.mk $(COMMON_FLAGS) clean
++
++override_dh_auto_install:
++      make $(COMMON_FLAGS) install
++      # FIXME: any better solution than this hack?
++      find deps -type f -name 'libLLVM*so*' -exec cp -v '{}' debian/tmp/usr/lib/$(shell gcc -print-multiarch)/julia/ \;
++      -ln -s libLLVM-6.0.so debian/tmp/usr/lib/$(shell gcc -print-multiarch)/julia/libLLVM-6.0.0.so
++      -ln -s libLLVM-6.0.so debian/tmp/usr/lib/$(shell gcc -print-multiarch)/julia/libLLVM.so
++      rm -rf usr # Otherwise dh_install does not see debian/tmp/usr
++      find debian -type f -name '*.so.debug' -delete
++      find debian -type f -name .gitignore -delete
++      find debian -type f -name 'LICENSE.md' -delete
++
++override_dh_missing:
++      dh_missing --list-missing
++
++override_dh_link-arch:
++      # Create *.so symlinks for dlopen'd libraries in private libdir.
++      make -f debian/shlibdeps.mk $(COMMON_FLAGS)
++      dh_link
++
++override_dh_shlibdeps:
++      # Generate dependencies for dlopen'd libraries using dummy executable.
++      # Suppress useless dependency warnings caused by unused library symbols.
++      dh_shlibdeps -- --warnings=1 debian/shlibdeps
++
++override_dh_compress:
++      dh_compress --exclude=examples/
++
++override_dh_install-indep:
++      dh_install --exclude=build_h.jl --exclude=build.h
++
++override_dh_fixperms:
++      dh_fixperms
++      # Fix shebang and mode bits
++      find debian \( -type f -name '*.jl' \
++              -exec grep -q '..usr/bin/env julia' '{}' \; \
++              -a -exec sed -i -e 's@#!/usr/bin/env julia@#!/usr/bin/julia@g' '{}' \; \
++              -a -exec chmod +x '{}' \; -print \)
++
++# Don't strip sys.so and libjulia.so.* to keep the sanity of this program.
++# https://github.com/JuliaLang/julia/issues/23115#issuecomment-320715030
++#
++# Julia sysimage (i.e. sys.so) sys.so is NOT compiled from any compiled
++# language such as C/C++, but from Julia scripts instead. Julia precompiles .jl
++# scripts under the base and stdlib directories into this ELF-formated shared
++# object sys.so to speedup program startup time. A glance at the symbol table
++# (readelf -sW sys.so) would illustrate that. For more detail about how such
++# debugging information is useful, please refer the official documentation:
++# https://docs.julialang.org/en/v1.0.0/manual/stacktraces/
++#
++override_dh_strip:
++      dh_strip -X"sys.so"
++
++override_dh_makeshlibs:
++      dh_makeshlibs --no-scripts -XLLVM
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..953a1cdbe7eec18cd000be10b55ce47ffd02a12c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * Query soname of shared library.
++ * Copyright © 2015 Peter Colberg.
++ * Distributed under the MIT license.
++ */
++
++#define _GNU_SOURCE
++#include <dlfcn.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#define error(fmt, ...) fprintf(stderr, "%s: "fmt"\n", argv[0], ##__VA_ARGS__)
++
++/*
++ * For a given symbol name, this program prints the path relative to /
++ * of the shared library containing that symbol. The program must be
++ * linked against the shared libraries to be queried for symbols, and
++ * compiled as a position-independent executable using -fPIE.
++ */
++int main(int argc, const char *const *argv)
++{
++  Dl_info info;
++  void *sym;
++
++  if (argc != 2) {
++    fprintf(stderr, "Usage: %s SYMBOL\n", argv[0]);
++    return 1;
++  }
++  if (!(sym = dlsym(RTLD_DEFAULT, argv[1]))) {
++    fprintf(stderr, "%s\n", dlerror());
++    return 1;
++  }
++  if (dladdr(sym, &info) == 0) {
++    fprintf(stderr, "%s\n", dlerror());
++    return 1;
++  }
++  if (info.dli_saddr != sym) {
++    error("mismatching symbol name: %s", info.dli_sname);
++    return 1;
++  }
++  if (info.dli_fname[0] != '/') {
++    error("library name not an absolute path: %s", info.dli_fname);
++    return 1;
++  }
++  printf("%s", info.dli_fname + 1);
++  return 0;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..52e68aeeb5c9accaeed0193b4e29d88e6ef483d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,188 @@@
++# This makefile compiles a dummy executable linked against
++# those shared libraries that are dlopen'd by Julia modules
++# in Base. The dummy executable is passed to dpkg-shlibdeps
++# to generate library dependencies for the julia package.
++#
++# The dummy executable is further used to generate symbolic
++# links lib*.so => lib*.so.SOVERSION in the private library
++# path for Julia, which ensures that ccall() loads exactly
++# those library versions that the julia package was built
++# with and depends on.
++
++# Include Julia makefile with LIB*NAME definitions.
++JULIAHOME := $(CURDIR)
++include Make.inc
++
++TARGETS := debian/shlibdeps debian/libjulia$(SOMAJOR).links
++
++all: $(TARGETS)
++
++ifeq ($(USE_SYSTEM_ARPACK),1)
++SHLIBDEPS += -larpack
++endif
++
++ifeq ($(USE_SYSTEM_BLAS),1)
++SHLIBDEPS += $(LIBBLAS)
++# OpenBLAS library provides both BLAS and LAPACK.
++ifneq ($(LIBBLASNAME),$(LIBLAPACKNAME))
++SHLIBDEPS += $(LIBLAPACK)
++endif
++endif
++
++ifeq ($(USE_SYSTEM_CURL),1)
++SHLIBDEPS += -lcurl
++endif
++
++ifeq ($(USE_SYSTEM_DSFMT),1)
++SHLIBDEPS += -ldSFMT
++endif
++
++ifeq ($(USE_SYSTEM_GMP),1)
++SHLIBDEPS += -lgmp
++endif
++
++ifeq ($(USE_SYSTEM_LIBGIT2),1)
++SHLIBDEPS += -lgit2
++endif
++
++ifeq ($(USE_SYSTEM_LIBM),1)
++SHLIBDEPS += $(LIBM)
++else ifeq ($(USE_SYSTEM_OPENLIBM),1)
++SHLIBDEPS += $(LIBM)
++endif
++
++ifeq ($(USE_SYSTEM_LIBSSH2),1)
++SHLIBDEPS += -lssh2
++endif
++
++ifeq ($(USE_SYSTEM_LIBUNWIND),1)
++ifeq (,$(filter $(DEB_HOST_ARCH),s390x))
++SHLIBDEPS += -lunwind
++endif
++endif
++
++ifeq ($(USE_SYSTEM_LIBUV),1)
++SHLIBDEPS += -luv
++endif
++
++ifeq ($(USE_SYSTEM_LLVM),1)
++SHLIBDEPS += -lLLVM -L/usr/lib/llvm-$(LLVM_VER)/lib/
++endif
++
++ifeq ($(USE_SYSTEM_MBEDTLS),1)
++SHLIBDEPS += -lmbedtls -lmbedcrypto -lmbedx509
++endif
++
++ifeq ($(USE_SYSTEM_MPFR),1)
++SHLIBDEPS += -lmpfr
++endif
++
++ifeq ($(USE_SYSTEM_PCRE),1)
++SHLIBDEPS += -lpcre2-8
++endif
++
++ifeq ($(USE_SYSTEM_SUITESPARSE),1)
++SHLIBDEPS += -lcholmod -lspqr -lsuitesparseconfig -lumfpack
++endif
++
++ifeq ($(USE_SYSTEM_UTF8PROC),1)
++SHLIBDEPS += -lutf8proc
++endif
++
++# The dummy executable is linked with --no-as-needed to prevent
++# the linker from potentially disregarding the given libraries
++# because none of the library symbols are used at compile time.
++debian/shlibdeps: debian/shlibdeps.c
++      $(CC) -fPIE -o $@ $< -ldl -Wl,--no-as-needed $(SHLIBDEPS)
++
++# The soname for each library is looked up by invoking the
++# dummy executable with the name of an arbitrary symbol such
++# as a function exported by that library. Ideally, these
++# should be functions that are ccall'd by the Julia modules.
++debian/libjulia$(SOMAJOR).links: debian/shlibdeps
++      rm -f $@.tmp
++ifeq ($(USE_SYSTEM_ARPACK),1)
++      debian/shlibdeps snaupd_ >> $@.tmp
++      echo " $(private_libdir)/libarpack.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_BLAS),1)
++      debian/shlibdeps daxpy_ >> $@.tmp
++      echo " $(private_libdir)/$(LIBBLASNAME).so" >> $@.tmp
++ifneq ($(LIBBLASNAME),$(LIBLAPACKNAME))
++      debian/shlibdeps dggsvd_ >> $@.tmp
++      echo " $(private_libdir)/$(LIBLAPACKNAME).so" >> $@.tmp
++endif
++endif
++ifeq ($(USE_SYSTEM_CURL),1)
++      debian/shlibdeps curl_easy_recv >> $@.tmp
++      echo " $(private_libdir)/libcurl.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_DSFMT),1)
++      debian/shlibdeps dsfmt_get_idstring >> $@.tmp
++      echo " $(private_libdir)/libdSFMT.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_GMP),1)
++      debian/shlibdeps __gmpz_get_str >> $@.tmp
++      echo " $(private_libdir)/libgmp.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LIBGIT2),1)
++      debian/shlibdeps git_libgit2_version >> $@.tmp
++      echo " $(private_libdir)/libgit2.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LIBM),1)
++      debian/shlibdeps pow >> $@.tmp
++      echo " $(private_libdir)/$(LIBMNAME).so" >> $@.tmp
++else ifeq ($(USE_SYSTEM_OPENLIBM),1)
++      debian/shlibdeps pow >> $@.tmp
++      echo " $(private_libdir)/$(LIBMNAME).so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_MPFR),1)
++      debian/shlibdeps mpfr_init2 >> $@.tmp
++      echo " $(private_libdir)/libmpfr.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_PCRE),1)
++      debian/shlibdeps pcre2_compile_8 >> $@.tmp
++      echo " $(private_libdir)/libpcre2-8.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LIBSSH2),1)
++      debian/shlibdeps libssh2_version >> $@.tmp
++      echo " $(private_libdir)/libssh2.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LIBUV),1)
++      debian/shlibdeps uv_tcp_open >> $@.tmp
++      echo " $(private_libdir)/libuv.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LIBUNWIND),1)
++      debian/shlibdeps backtrace >> $@.tmp
++      echo " $(private_libdir)/libunwind.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_LLVM),1)
++      debian/shlibdeps llvm_regexec >> $@.tmp
++      echo " $(private_libdir)/libLLVM.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_MBEDTLS),1)
++      debian/shlibdeps mbedtls_net_init >> $@.tmp
++      echo " $(private_libdir)/libmbedtls.so" >> $@.tmp
++      debian/shlibdeps mbedtls_md5 >> $@.tmp
++      echo " $(private_libdir)/libmbedcrypto.so" >> $@.tmp
++      debian/shlibdeps mbedtls_x509_get_serial >> $@.tmp
++      echo " $(private_libdir)/libmbedx509.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_SUITESPARSE),1)
++      debian/shlibdeps cholmod_version >> $@.tmp
++      echo " $(private_libdir)/libcholmod.so" >> $@.tmp
++      debian/shlibdeps SuiteSparseQR_C_free >> $@.tmp
++      echo " $(private_libdir)/libspqr.so" >> $@.tmp
++      debian/shlibdeps SuiteSparse_config >> $@.tmp
++      echo " $(private_libdir)/libsuitesparseconfig.so" >> $@.tmp
++      debian/shlibdeps umfpack_dl_report_info >> $@.tmp
++      echo " $(private_libdir)/libumfpack.so" >> $@.tmp
++endif
++ifeq ($(USE_SYSTEM_UTF8PROC),1)
++      debian/shlibdeps utf8proc_errmsg >> $@.tmp
++      echo " $(private_libdir)/libutf8proc.so" >> $@.tmp
++endif
++      mv $@.tmp $@
++
++clean:
++      $(RM) $(TARGETS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..163aaf8d82b6c54f23c45f32895dbdfdcc27b047
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++3.0 (quilt)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ab74339c56c56a2304acb28f6c78d62e32008950
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++debian/embedded/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e.tar.gz
++debian/embedded/libwhich-81e9723c0273d78493dc8c8ed570f68d9ce7e89e.tar.gz
++debian/embedded/93b6d6de857dc88e665d2c64397852ab9701ba24
++debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen-generated.png
++debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen-export-private-key.png
++debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/puttygen.png
++debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/travis-variables.png
++debian/embedded/Documenter.jl-0.20.0/docs/src/man/hosting/github-add-deploy-key.png
++debian/embedded/Documenter.jl-0.20.0/docs/src/assets/favicon.ico
++debian/embedded/Documenter.jl-0.20.0/docs/src/assets/logo.png
++debian/embedded/Documenter.jl-0.20.0/test/examples/src/assets/favicon.ico
++debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.jpg
++debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.webp
++debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.gif
++debian/embedded/Documenter.jl-0.20.0/test/examples/images/logo.png
++debian/embedded/DocStringExtensions.jl-0.5.0/docs/src/assets/logo.png
++debian/embedded/llvm-6.0.0.src.tar.xz
++debian/embedded/llvm-6.0.src.tar.xz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6dd32e530963c638ebe773bd05050939d7163fa4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Justification for "needs-root": https://github.com/JuliaLang/julia/issues/28023
++Tests: runtests.sh
++Restrictions: allow-stderr, needs-root
++Depends: @, curl, dpkg-dev
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..127aa713fef7f073b9fe0441b4399ff5321422d2
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,12 @@@
++#!/bin/sh
++set -ex
++
++export JULIA_TEST_MAXRSS_MB=500
++export HOME=/tmp
++
++cd $AUTOPKGTEST_TMP
++
++/usr/bin/julia \
++      --check-bounds=yes \
++      --startup-file=no \
++      /usr/share/julia/test/runtests.jl all
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..49876875412590eacfbf4a7d2bec274b13f860bc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++Name: Julia
++Bug-Database: https://github.com/julialang/julia/issues
++Bug-Submit: https://github.com/julialang/julia/issues
++Cite-As: "Julia: A Fresh Approach to Numerical Computing. Jeff Bezanson, Alan Edelman, Stefan Karpinski and Viral B. Shah (2017) SIAM Review, 59: 65–98. doi: 10.1137/141000671. url: http://julialang.org/publications/julia-fresh-approach-BEKS.pdf."
++Documentation: https://docs.julialang.org/
++Reference:
++  Author: Jeff Bezanson, Alan Edelman, Stefan Karpinski and Viral B. Shah
++  Booktitle: SIAM Review
++  DOI: 10.1137/141000671
++  Number: 59
++  Pages: 65–98
++  Title: "Julia: A Fresh Approach to Numerical Computing"
++  Year: 2017
++Repository: https://github.com/JuliaLang/julia
++Repository-Browse: https://github.com/JuliaLang/julia
diff --cc debian/watch
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac69ac3183898707d0d452438df51ce8b1ddacf7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++version=4
++opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%julia-$1.tar.gz%,\
++      dversionmangle=s/\+dfsg\d*$// ,repacksuffix=+dfsg" \
++    https://github.com/JuliaLang/julia/tags \
++    (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate