--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++julia (1.0.4+dfsg-1) unstable; urgency=medium
++
++ * New upstream version 1.0.4+dfsg
++ * Uscan: Monitor the 1.0.X series.
++ * Upgrade embedded Pkg.jl -> 1609a05aee5d5960670738d8d834d91235bd6b1e
++
++ -- Mo Zhou <cdluminate@gmail.com> Fri, 17 May 2019 09:01:01 +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
--- /dev/null
--- /dev/null
++deps/libuv/Makefile
++deps/libuv/config.log
++deps/libuv/config.status
++deps/libuv/libtool
++deps/libuv/libuv.pc
++src/*.dwo
++base/version_git.jl
--- /dev/null
--- /dev/null
++11
--- /dev/null
--- /dev/null
++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.
--- /dev/null
--- /dev/null
++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.
--- /dev/null
--- /dev/null
++.
--- /dev/null
--- /dev/null
++.
--- /dev/null
--- /dev/null
++DocStringExtensions.jl-0.5.0
--- /dev/null
--- /dev/null
++comment: false
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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.
++>
--- /dev/null
--- /dev/null
++# 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] — **most recently tagged version of the documentation.**
++- [**LATEST**][docs-latest-url] — *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
--- /dev/null
--- /dev/null
++julia 0.7
--- /dev/null
--- /dev/null
++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%"
--- /dev/null
--- /dev/null
++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",
++)
++
--- /dev/null
--- /dev/null
++# DocStringExtensions
++
++```@docs
++DocStringExtensions
++```
++
++## Index
++
++```@index
++Modules = [DocStringExtensions]
++```
++
++## Reference
++
++```@autodocs
++Modules = [DocStringExtensions]
++Order = [:constant, :function, :macro, :type]
++```
++
--- /dev/null
--- /dev/null
++__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
--- /dev/null
--- /dev/null
++
++#
++# 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.
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++
++#
++# 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
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++using DocStringExtensions
++using Test
++import Markdown
++
++include("tests.jl")
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++https://github.com/JuliaDocs/DocStringExtensions.jl/releases
--- /dev/null
--- /dev/null
++Documenter.jl-0.20.0
--- /dev/null
--- /dev/null
++comment: false
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++# 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]
++-->
--- /dev/null
--- /dev/null
++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.
++>
--- /dev/null
--- /dev/null
++
++# 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] — **documentation of the most recently tagged version.**
++- [**DEVEL**][docs-dev-url] — *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
--- /dev/null
--- /dev/null
++julia 0.7
++DocStringExtensions 0.2
--- /dev/null
--- /dev/null
++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%"
--- /dev/null
--- /dev/null
++<?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>
--- /dev/null
--- /dev/null
++/*
++ * 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;
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * 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();
++ }
++ })
++})
--- /dev/null
--- /dev/null
++/*
++ * 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();
++ })
++})
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
++% 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
++%
--- /dev/null
--- /dev/null
++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;
++}
--- /dev/null
--- /dev/null
++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" } }
++});
--- /dev/null
--- /dev/null
++[deps]
++Coverage = "a2441757-f6aa-5fb2-8edb-039e3f45d037"
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++[[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"
--- /dev/null
--- /dev/null
++[deps]
++DocumenterTools = "46bb7b6e-9a58-11e8-21f8-9f2f45a0fcba"
--- /dev/null
--- /dev/null
++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",
++)
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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"]
++```
--- /dev/null
--- /dev/null
++# 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")]
++```
--- /dev/null
--- /dev/null
++# Anchors
++
++```@autodocs
++Modules = [Documenter.Anchors]
++```
--- /dev/null
--- /dev/null
++# Builder
++
++```@autodocs
++Modules = [Documenter.Builder]
++```
--- /dev/null
--- /dev/null
++# CrossReferences
++
++```@autodocs
++Modules = [Documenter.CrossReferences]
++```
--- /dev/null
--- /dev/null
++# DocChecks
++
++```@autodocs
++Modules = [Documenter.DocChecks]
++```
--- /dev/null
--- /dev/null
++# DocSystem
++
++```@autodocs
++Modules = [Documenter.DocSystem]
++```
--- /dev/null
--- /dev/null
++# DocTests
++
++```@autodocs
++Modules = [Documenter.DocTests]
++```
--- /dev/null
--- /dev/null
++# Documenter
++
++```@docs
++Documenter.gitrm_copy
++Documenter.git_push
++```
--- /dev/null
--- /dev/null
++# DocumenterTools
++
++```@docs
++DocumenterTools.package_devpath
++```
++
++## Generator
++
++```@autodocs
++Modules = [DocumenterTools.Generator]
++```
--- /dev/null
--- /dev/null
++# Documents
++
++```@autodocs
++Modules = [Documenter.Documents]
++```
--- /dev/null
--- /dev/null
++# DOM
++
++```@autodocs
++Modules = [Documenter.Utilities.DOM]
++```
--- /dev/null
--- /dev/null
++# Expanders
++
++```@autodocs
++Modules = [Documenter.Expanders]
++```
--- /dev/null
--- /dev/null
++# Formats
++
++```@autodocs
++Modules = [Documenter.Formats]
++```
--- /dev/null
--- /dev/null
++# MDFlatten
++
++```@autodocs
++Modules = [Documenter.Utilities.MDFlatten]
++```
--- /dev/null
--- /dev/null
++# Selectors
++
++```@autodocs
++Modules = [Documenter.Selectors]
++```
--- /dev/null
--- /dev/null
++# TextDiff
++
++```@autodocs
++Modules = [Documenter.Utilities.TextDiff]
++```
--- /dev/null
--- /dev/null
++# Utilities
++
++```@autodocs
++Modules = [Documenter.Utilities]
++```
--- /dev/null
--- /dev/null
++# Writers
++
++```@autodocs
++Modules = [
++ Documenter.Writers,
++ Documenter.Writers.MarkdownWriter,
++ Documenter.Writers.HTMLWriter,
++ Documenter.Writers.LaTeXWriter,
++]
++```
--- /dev/null
--- /dev/null
++# 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
++```
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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/)
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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://USER_NAME.github.io/PACKAGE_NAME.jl/stable)
++[](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.
--- /dev/null
--- /dev/null
++# 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:
++
++
++
++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:
++
++
++
++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.
++
++ 
++
++ !!! 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:
++
++
++
++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:
++
++
++
++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).
--- /dev/null
--- /dev/null
++# [``\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.
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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
++```
++
++
++
++and then we do the same with `g`
++
++```@example 1
++plot(x, g(x), color = "blue")
++savefig("g-plot.svg"); nothing # hide
++```
++
++
++````
++
++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
++```
++
++
++````
++
++**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
++```
++
++
++````
++
++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>
++```
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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("")
++```
++````
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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 `<`
++- `>` to `>`
++- `&` to `&`
++- `'` to `'`
++- `\"` to `"`
++
++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, "<") :
++ char === '>' ? write(buffer, ">") :
++ char === '&' ? write(buffer, "&") :
++ char === '\'' ? write(buffer, "'") :
++ char === '"' ? write(buffer, """) : 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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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)")),
++ " — ", # —
++ 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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++"""
++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)`** — *$(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
--- /dev/null
--- /dev/null
++"""
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++```@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
++```
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++```@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
++```
--- /dev/null
--- /dev/null
++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> < > & ' " </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
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++
++```@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
++```
--- /dev/null
--- /dev/null
++# 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,
++)
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++
++"""
++`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
--- /dev/null
--- /dev/null
++
++"""
++`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
--- /dev/null
--- /dev/null
++
++"""
++`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
--- /dev/null
--- /dev/null
++
++"""
++`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()
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++/* custom.css */
++
++center.raw-html-block {
++ color: red;
++}
--- /dev/null
--- /dev/null
++// custom javascript
--- /dev/null
--- /dev/null
++// overrides Documenter's search.js
--- /dev/null
--- /dev/null
++# Hidden (toplevel)
++
++## Section
--- /dev/null
--- /dev/null
++# 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
++```
--- /dev/null
--- /dev/null
++# Hidden 1
++
++## First heading
++## Second heading
--- /dev/null
--- /dev/null
++# Hidden 2
--- /dev/null
--- /dev/null
++# Hidden 3
--- /dev/null
--- /dev/null
++# 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)
--- /dev/null
--- /dev/null
++# `@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]
++```
++
--- /dev/null
--- /dev/null
++!!! 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
--- /dev/null
--- /dev/null
++
++```@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).
--- /dev/null
--- /dev/null
++csv,data,file
++1,2,3
--- /dev/null
--- /dev/null
++# 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
++```
++
++
++
++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>
++```
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++# MissingDocs Exports
++
++```@docs
++Main.MissingDocs.f
++```
--- /dev/null
--- /dev/null
++# MissingDocs None
++
++```@docs
++```
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++using Documenter
++
++makedocs(
++ debug = true,
++ doctestfilters = [r"Ptr{0x[0-9]+}"],
++ sitename = "Documenter example",
++ pages = ["index.md"],
++)
--- /dev/null
--- /dev/null
++# Test
++
++....
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++https://github.com/JuliaDocs/Documenter.jl/releases
--- /dev/null
--- /dev/null
++https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/1609a05aee5d5960670738d8d834d91235bd6b1e
--- /dev/null
--- /dev/null
++https://api.github.com/repos/JuliaLang/libuv/tarball/d8ab1c6a33e77bf155facb54215dd8798e13825d
--- /dev/null
--- /dev/null
++https://api.github.com/repos/vtjnash/libwhich/tarball/81e9723c0273d78493dc8c8ed570f68d9ce7e89e
--- /dev/null
--- /dev/null
++llvm-6.0.0.src.tar.xz
--- /dev/null
--- /dev/null
++/* 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');
++}
--- /dev/null
--- /dev/null
++[DEFAULT]
++pristine-tar = True
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++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/*
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++doc/_build/html
++doc/_build/pdf/en/TheJuliaLanguage.pdf
--- /dev/null
--- /dev/null
++debian/fontface.css usr/share/doc/julia-doc/
--- /dev/null
--- /dev/null
++README.md
++CONTRIBUTING.md
++DISTRIBUTING.md
++HISTORY.md
++NEWS.md
++README.arm.md
++README.md
++README.windows.md
++VERSION
--- /dev/null
--- /dev/null
++debian/prompt.example.jl
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++debian/tmp/usr/share/man/man1/julia.1
--- /dev/null
--- /dev/null
++usr/include/julia
++usr/lib/*/libjulia.so
--- /dev/null
--- /dev/null
++usr/lib/*/libjulia.so.*
++usr/lib/*/julia
--- /dev/null
--- /dev/null
++# 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.*
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++activate-noawait ldconfig
--- /dev/null
--- /dev/null
++usr/share/doc/julia/html/*
--- /dev/null
--- /dev/null
++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>
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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"
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++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,,,))
--- /dev/null
--- /dev/null
++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 \
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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]>;
+++
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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))
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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_)
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++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 $@)
++
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++# 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)
--- /dev/null
--- /dev/null
++#!/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="armv7-a;armv7-a,neon;armv7-a,neon,vfp4"
++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
--- /dev/null
--- /dev/null
++/*
++ * 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;
++}
--- /dev/null
--- /dev/null
++# 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)
--- /dev/null
--- /dev/null
++3.0 (quilt)
--- /dev/null
--- /dev/null
++debian/embedded/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e.tar.gz
++debian/embedded/libwhich-81e9723c0273d78493dc8c8ed570f68d9ce7e89e.tar.gz
++debian/embedded/1609a05aee5d5960670738d8d834d91235bd6b1e
++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
--- /dev/null
--- /dev/null
++# Justification for "needs-root": https://github.com/JuliaLang/julia/issues/28023
++Tests: runtests.sh
++Restrictions: allow-stderr, needs-root
++Depends: @, curl, dpkg-dev
--- /dev/null
--- /dev/null
++#!/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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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?(1\.0[\d.]*)\.tar\.gz debian uupdate