diff --git a/static/docs/v4.5.x/.buildinfo b/static/docs/v4.5.x/.buildinfo new file mode 100644 index 00000000..194bc967 --- /dev/null +++ b/static/docs/v4.5.x/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 000aa872ae49209e7dd10d9c94d85f7f +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/static/docs/v4.5.x/_images/beowulf_architecture.png b/static/docs/v4.5.x/_images/beowulf_architecture.png new file mode 100644 index 00000000..8c75d919 Binary files /dev/null and b/static/docs/v4.5.x/_images/beowulf_architecture.png differ diff --git a/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png b/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png new file mode 100644 index 00000000..656dd5d7 Binary files /dev/null and b/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png differ diff --git a/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png.map b/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png.map new file mode 100644 index 00000000..8be6a309 --- /dev/null +++ b/static/docs/v4.5.x/_images/graphviz-45530e0b437388de246c86a5b4638e7b3654235b.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png b/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png new file mode 100644 index 00000000..7f88dc9e Binary files /dev/null and b/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png differ diff --git a/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png.map b/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png.map new file mode 100644 index 00000000..8be6a309 --- /dev/null +++ b/static/docs/v4.5.x/_images/graphviz-5cb5701ea7fd182b13828ac567d21b2e09945929.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png b/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png new file mode 100644 index 00000000..79e8dff8 Binary files /dev/null and b/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png differ diff --git a/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png.map b/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png.map new file mode 100644 index 00000000..649d660c --- /dev/null +++ b/static/docs/v4.5.x/_images/graphviz-87f2b5a9fa342f42cc8028f4a60d24c3ea795fd3.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png b/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png new file mode 100644 index 00000000..67542884 Binary files /dev/null and b/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png differ diff --git a/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png.map b/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png.map new file mode 100644 index 00000000..8be6a309 --- /dev/null +++ b/static/docs/v4.5.x/_images/graphviz-8be43717679b33953ee198ed82f1999c0ddd0b61.png.map @@ -0,0 +1,2 @@ + + diff --git a/static/docs/v4.5.x/_sources/contents/background.rst.txt b/static/docs/v4.5.x/_sources/contents/background.rst.txt new file mode 100644 index 00000000..52899dfe --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/background.rst.txt @@ -0,0 +1,38 @@ +========== +Background +========== + +Warewulf is based on the design of the original Beowulf Cluster design +(and thus the name, soft\ **WARE** implementation of the beo\ +**WULF**) + +The `Beowulf Cluster `_ +design was developed in 1996 by Dr. Thomas Sterling and Dr. Donald +Becker at NASA. The architecture is defined as a group of similar +compute worker nodes all connected together using standard commodity +equipment on a private network segment. The control node (historically +referred to as the "master" or "head" node) is dual homed (has two +network interface cards) with one of these network interface cards +attached to the upstream public network and the other connected to a +private network which connects to all of the compute worker nodes (as +seen in the figure below). + +.. image:: beowulf_architecture.png + :alt: Beowulf architecture + +This simple topology is the foundation for creating every scalable HPC +cluster resource. Even today, almost 30 years after the inception of +this architecture, this is the baseline architecture that traditional +HPC systems are built to. + +Other considerations for a working HPC-type cluster are storage, +scheduling and resource management, monitoring, interactive systems, +etc. For smaller systems, much of these requirements can be managed +all from a single control node, but as the system scales, it may need +to have groups of nodes dedicated to these different services. + +Warewulf is easily capable of building simple and turnkey HPC +clusters, to giant massive complex multi-purpose computing clusters, +through next generation computing platforms. + +Anytime a cluster of systems is needed, Warewulf is your tool! diff --git a/static/docs/v4.5.x/_sources/contents/boot-management.rst.txt b/static/docs/v4.5.x/_sources/contents/boot-management.rst.txt new file mode 100644 index 00000000..1bfa83e6 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/boot-management.rst.txt @@ -0,0 +1,138 @@ +=============== +Boot Management +=============== + +Warewulf uses iPXE to for network boot by default. As a tech preview, support +for GRUB is also available, which adds support for secure boot. + +Booting with iPXE +================= + +.. graphviz:: + + digraph G{ + node [shape=box]; + compound=true; + edge [label2node=true] + bios [shape=record label="{BIOS | boots from DHCP/next-server via TFTP}"] + + subgraph cluster0 { + label="iPXE boot" + iPXE; + ipxe_cfg [shape=record label="{ipxe.cfg|generated for each node}"]; + iPXE -> ipxe_cfg [label="http"]; + } + + bios->iPXE [lhead=cluster0,label="iPXE.efi"]; + + kernel [shape=record label="{kernel|ramdisk (root fs)|wwinit overlay}|extracted from node container"]; + ipxe_cfg->kernel[ltail=cluster0,label="http"]; + } + +Booting with GRUB +================= + +Support for GRUB as a network bootloader (replacing iPXE) is available in +Warewulf as a technology preview. + +.. graphviz:: + + digraph G{ + node [shape=box]; + compound=true; + edge [label2node=true] + bios [shape=record label="{BIOS | boots from DHCP/next-server via TFTP}"] + + bios->shim [lhead=cluster1,label="shim.efi"]; + subgraph cluster1{ + label="Grub boot" + shim[shape=record label="{shim.efi|from ww4 host}"]; + grub[shape=record label="{grubx64.efi | name hardcoded in shim.efi|from ww4 host}"] + shim->grub[label="TFTP"]; + grubcfg[shape=record label="{grub.cfg|static under TFTP root}"]; + grub->grubcfg[label="TFTP"]; + } + kernel [shape=record label="{kernel|ramdisk (root fs)|wwinit overlay}|extracted from node container"]; + grubcfg->kernel[ltail=cluster1,label="http"]; + } + +Instead of the iPXE starter a combination of `shim and GRUB +`_ can be used with the +advantage that secure boot can be used. That means that only the signed kernel +of a distribution can be booted. This can be a huge security benefit for some +scenarios. + +In order to enable the grub boot method it has to be enabled in `warewulf.conf`. + +.. code-block: yaml + + warewulf: + grubboot: true + +Nodes which are not known to Warewulf are booted with the shim/grub from the +Warewulf server host. + +Secure boot +----------- + +.. graphviz:: + + digraph foo { + node [shape=box]; + subgraph boot { + "EFI" [label="EFI",row=boot]; + "Shim" [label="Shim",row=boot]; + "Grub" [label="Grub",row=boot]; + "Kernel" [label="kernel",row=boot]; + EFI -> Shim[label="Check for Microsoft signature"]; + Shim -> Grub[label="Check for Distribution signature"]; + Grub->Kernel[label="Check for Distribution or MOK signature"]; + } + } + +If secure boot is enabled at every step a signature is checked and the boot +process fails if this check fails. The shim typically only includes the key for +a single operating system, which means that each distribution needs separate +`shim` and `grub` executables. Warewulf extracts these binaries from the +containers. If the node is unknown to Warewulf or can't be identified during +the TFTP boot phase, the shim/grub binaries of the host in which Warewulf is +running are used. + +Install shim and efi +-------------------- + +`shim.efi` and `grub.efi` must be installed in the container for it to be +booted by GRUB. + +.. code-block:: console + + # wwctl container shell leap15.5 + [leap15.5] Warewulf> zypper install grub2 shim + + # wwctl container shell rocky9 + [rocky9] Warewulf> dnf install shim-x64.x86_64 grub2-efi-x64.x86_64 + +These packages must also be installed on the Warewulf server host to enable +node discovery using GRUB. + +http boot +--------- + +Modern EFI systems have the possibility to directly boot per http. The flow diagram +is the following: + +.. graphviz:: + + digraph G{ + node [shape=box]; + efi [shape=record label="{EFI|boots from URI defined in filename}"]; + shim [shape=record label="{shim.efi|replaces shim.efi with grubx64.efi in URI|extracted from node container}"]; + grub [shape=record label="{grub.efi|checks for grub.cfg|extracted from node container}"] + kernel [shape=record label="{kernel|ramdisk (root fs)|wwinit overlay}|extracted from node container"]; + efi->shim [label="http"]; + shim->grub [label="http"]; + grub->kernel [label="http"]; + } + +Warewulf delivers the initial `shim.efi` and `grub.efi` via http as taken +directly from the node's assigned container. diff --git a/static/docs/v4.5.x/_sources/contents/configuration.rst.txt b/static/docs/v4.5.x/_sources/contents/configuration.rst.txt new file mode 100644 index 00000000..8b737be2 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/configuration.rst.txt @@ -0,0 +1,182 @@ +====================== +Warewulf Configuration +====================== + +The default installation of Warewulf will put all of the configuration +files into ``/etc/warewulf/``. In that directory, you will find the +primary configuration files needed by Warewulf. + +warewulf.conf +============= + +The Warewulf configuration exists as follows in the current version of +Warewulf (4.4.0): + +.. code-block:: yaml + + WW_INTERNAL: 45 + ipaddr: 10.0.0.1 + netmask: 255.255.252.0 + network: 10.0.0.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 10.0.1.1 + range end: 10.0.1.255 + systemd name: dhcpd + tftp: + enabled: true + systemd name: tftp + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true + +Generally you can leave this file as is, as long as you set the +appropriate networking information. Specifically the following +configurations: + +* ``ipaddr``: This is the control node's networking interface + connecting to the cluster's **PRIVATE** network. This configuration + must match the host's network IP address for the cluster's private + interface. + +* ``netmask``: Similar to the ``ipaddr``, this is the subnet mask for + the cluster's **PRIVATE** network and it must also match the host's + subnet mask for the cluster's private interface. + +* ``dhcp:range start`` and ``dhcp:range end``: This address range must + exist in the network defined above. If it is outside of this + network, failures will occur. This specifies the range of addresses + you want DHCP to use. + +The other configuration options are usually not touched, but they are +explained as follows: + +* ``*:enabled``: This can be used to disable Warewulf's control of a + system service. This is useful if you want to manage that service + directly. + +* ``*:systemd name``: This is so Warewulf can control some of the + host's services. For the distributions that we've built and tested + this on, these will require no changes. + +* ``warewulf:port``: This is the port that the Warewulf web server + will be listening on. It is recommended not to change this so there + is no misalignment with node's expectations of how to contact the + Warewulf service. + +* ``warewulf:secure``: When ``true``, this limits the Warewulf server + to only respond to runtime overlay requests originating from a + privileged port. This prevents non-root users from requesting the + runtime overlay, which may contain sensitive information. + + When ``true``, ``wwclient`` uses TCP port 987. + + Changing this option requires rebuilding node overlays and rebooting + compute nodes, to configure them to use a privileged port. + +* ``warewulf:update interval``: This defines the frequency (in + seconds) with which the Warewulf client on the compute node fetches + overlay updates. + +* ``warewulf:autobuild overlays``: This determines whether per-node + overlays will automatically be rebuilt, e.g., when an underlying + overlay is changed. + +* ``warewulf:host overlay``: This determines whether the special + ``host`` overlay is applied to the Warewulf server during + configuration. (The host overlay is used to configure the dependent + services.) + +* ``warewulf:syslog``: This determines whether Warewulf server logs go + to syslog or are written directly to a log file. (e.g., + ``/var/log/warewulfd.log``) + +* ``nfs:export paths``: Warewulf can automatically set up these NFS + exports. + +* ``container mounts``: These paths are mounted into the container + during ``container exec`` or ``container shell``, typically to allow + them to operate in the host environment prior to deployment. + +nodes.conf +========== + +The ``nodes.conf`` file is the primary database file for all compute +nodes. It is a flat text YAML configuration file that is managed by +the ``wwctl`` command, but some sites manage the compute nodes and +infrastructure via configuration management. This file being flat text +and very light weight makes management of the node configurations very +easy no matter what your configuration paradigm is. + +For the purpose of this document, we will not go into the detailed +format of this file as it is recommended to edit with the ``wwctl`` +command. + +.. note:: + + This configuration is not written at install time; but, the first + time you attempt to run ``wwctl``, this file will be generated if + it does not exist already. + +defaults.conf +============= + +The ``defaults.conf`` file configures default values used when none +are specified in ``nodes.conf``. For example: if a node does not have +a "runtime overlay" specified, the respective value from +``defaultnode`` is used. If a network device does not specify a +"device," the device value of the ``dummy`` device is used. + +If ``defaults.conf`` does not exist, the following values are used as +compiled into Warewulf at build-time: + +.. code-block:: yaml + + -- + defaultnode: + runtime overlay: + - generic + system overlay: + - wwinit + kernel: + args: quiet crashkernel=no vga=791 net.naming-scheme=v238 + init: /sbin/init + root: initramfs + ipxe template: default + profiles: + - default + network devices: + dummy: + device: eth0 + type: ethernet + netmask: 255.255.255.0 + +There should never be a need to change this file: all site-local +parameters should be specified using either nodes or profiles. + +Directories +=========== + +The ``/etc/warewulf/ipxe/`` directory contains *text/templates* that +are used by the Warewulf configuration process to configure the +``ipxe`` service. diff --git a/static/docs/v4.5.x/_sources/contents/containers.rst.txt b/static/docs/v4.5.x/_sources/contents/containers.rst.txt new file mode 100644 index 00000000..a802f98b --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/containers.rst.txt @@ -0,0 +1,361 @@ +==================== +Container Management +==================== + +Since the inception of Warewulf over 20 years ago, Warewulf has used +the model of the "Virtual Node File System" (VNFS) as a template image +for the compute nodes. This is similar to a golden master image, +except that the node file system exists within a directory on the +Warewulf control node (e.g. a ``chroot()``). + +In hindsight, we've been using containers all along, but the buzzword +just didn't exist. Over the last 5-6 years, the enterprise has created +a lot of tooling and standards around defining, building, +distributing, securing, and managing containers, so Warewulf v4 now +integrates directly within the container ecosystem to facilitate the +process of VNFS image management. + +If you are not currently leveraging the container ecosystem in any +other way, you can still build your own chroot directories and use +Warewulf as before. + +It is important to understand that Warewulf is not running a container +runtime on cluster nodes. While it is absolutely possible to run +containers on cluster nodes, Warewulf is provisioning the container +image to the bare metal and booting it. This container will be used as +the base operating system and, by default, it will run entirely in +memory. This means that when you reboot the node, the node retains no +information about Warewulf or how it booted. + +Container Tools +=============== + +There are different container managment tools available. Docker is +probably the most recognizable one in the enterprise. Podman is +another one that is gaining traction on the RHEL platforms. In HPC, +Apptainer is the most utilized container management tool. You can use +any of these to create and manage the containers to be later imported +into Warewulf. + +Importing Containers +==================== + +Warewulf supports importing an image from any OCI compliant +registry. This means you can import from a public registry or from a +private registry. + +Here is an example of importing from Docker Hub. + +.. code-block:: console + + # wwctl container import docker://ghcr.io/warewulf/warewulf-rockylinux:8 rocky-8 + Getting image source signatures + Copying blob d7f16ed6f451 done + Copying config da2ca70704 done + Writing manifest to image destination + Storing signatures + [LOG] info unpack layer: sha256:d7f16ed6f45129c7f4adb3773412def4ba2bf9902de42e86e77379a65d90a984 + Updating the container's /etc/resolv.conf + Building container: rocky-8 + +.. note:: + + Most containers in Docker Hub are not "bootable", in that, they + have a limited version of Systemd to make them lighter weight for + container purposes. For this reason, don't expect any base Docker + container (e.g. ``docker://rockylinux`` or ``docker://debian``) to + boot properly. They will not, as they will get stuck into a single + user mode. The containers in `https://hub.docker.com/u/warewulf + `_ are not limited and thus + they boot as you would expect. + +Private Registry +---------------- + +It is possible to use a private registry that is password protected or +does not have the requirement for TLS. In order to do so, you have two +choices for handling the credentials. + +* Set environmental variables +* Use ``docker login`` or ``podman login`` which will store the + credentials locally + +Please note, there is no requirement to install and use docker or +podman on your control node just for importing images into Warewulf. + +Here are the environmental variables that can be used. + +.. code-block:: console + + WAREWULF_OCI_USERNAME + WAREWULF_OCI_PASSWORD + WAREWULF_OCI_NOHTTPS + +Here is an example: + +.. code-block:: console + + # export WAREWULF_OCI_USERNAME=privateuser + # export WAREWULF_OCI_PASSWORD=super-secret-password-or-token + # wwctl import docker://ghcr.io/privatereg/rocky:8 + +The above is just an example. Consideration should be done before +doing it this way if you are in a security sensitive environment or +shared environments. You would not want these showing up in bash +history or logs. + +Local Files +----------- + +It is also possible to import a container from a local file or +directory. For example, Podman can save a `.tar` archive of an OCI +image. This archive can be directly imported into Warewulf, no +registry required. + +.. code-block:: console + + # podman save alpine:latest >alpine.tar + # wwctl container import alpine.tar alpine + +Chroot directories and Apptainer sandbox images can also be imported +directly. + +.. code-block:: console + + $ apptainer build --sandbox ./rockylinux-8/ docker://ghcr.io/warewulf/warewulf-rockylinux:8 + $ sudo wwctl container import ./rockylinux-8/ rockylinux-8 + +Syncuser +======== + +At import time Warewulf checks if the names of the users on the host +match the users and UIDs/GIDs in the imported container. If there is +mismatch, the import command will print out a warning. By setting the +``--syncuser`` flag you advise Warewulf to try to syncronize the users +from the host to the container, which means that ``/etc/passwd`` and +``/etc/group`` of the imported container are updated and all the files +belonning to these UIDs and GIDs will also be updated. + +A check if the users of the host and container matches can be +triggered with the ``syncuser`` command. + +.. code-block:: console + + # wwctl container syncuser container-name + +With the ``--write`` flag it will update the container to match the +user database of the host as described above. + +.. code-block:: console + + wwctl container syncuser --write container-name + +Listing All Imported Containers +=============================== + +Once the container has been imported, you can list them all with the +following command: + +.. code-block:: console + + # wwctl container list + CONTAINER NAME BUILT NODES + rocky-8 true 0 + +Once a container has been imported and showing up in this list you can +configure it to boot compute nodes. + +Making Changes To Containers +============================ + +Warewulf has a minimal container runtime built into it. This means you +can run commands inside of any of the containers and make changes to +them as follows: + +.. code-block:: console + + # wwctl container exec rocky-8 /bin/sh + [rocky-8] Warewulf> cat /etc/rocky-release + Rocky Linux release 8.4 (Green Obsidian) + [rocky-8] Warewulf> exit + Rebuilding container... + [INFO] Skipping (VNFS is current) + +You can also ``--bind`` directories from your host into the container +when using the exec command. This works as follows: + +.. code-block:: console + + # wwctl container exec --bind /tmp:/mnt rocky-8 /bin/sh + [rocky-8] Warewulf> + +.. note:: + + As with any mount command, both the source and the target must + exist. This is why the example uses the ``/mnt/`` directory + location, as it is almost always present and empty in every Linux + distribution (as prescribed by the LSB file hierarchy standard). + +When the command completes, if anything within the container changed, +the container will be rebuilt into a bootable static object +automatically. + +If the files ``/etc/passwd`` or ``/etc/group`` were updated, there +will be an additional check to confirm if the users are in sync as +described in `Syncuser`_ section. + +Excluding Files from a Container +-------------------------------- + +Warewulf can exclude files from a source container to prevent them +from being delivered to the compute node. This is typically used to +reduce the size of the image when some files are unnecessary. + +Patterns for excluded files are read from the file +``/etc/warewulf/excludes`` in the container image itself. For example, +the default Rocky Linux images exclude these paths: + +.. code-block:: + + /boot/ + /usr/share/GeoIP + +``/etc/warewulf/excludes`` supports the patterns implemented by +`filepath.Match `_. + +Preparing a container for build +------------------------------- + +Warewulf executes the script ``/etc/warewulf/container_exit.sh`` after +a ``wwctl container shell`` or ``wwctl container exec`` and prior to +(re)building the final node image for delivery. This is typically used +to remove cache or log files that may have been generated by the +executed command or interactive session. + +For example, the default Rocky Linux images runs ``dnf clean all`` to +remove any package repository caches that may have been generated. + +Creating Containers From Scratch +================================ + +You can also create containers from scratch and import those +containers into Warewulf as previous versions of Warewulf did. + +Building A Container From Your Host +----------------------------------- + +RPM based distributions, as well as Debian variants can all bootstrap +mini ``chroot()`` directories which can then be used to bootstrap your +node's container. + +For example, on an RPM based Linux distribution with YUM or DNF, you +can do something like the following: + +.. code-block:: console + + # yum install --installroot /tmp/newroot basesystem bash \ + chkconfig coreutils e2fsprogs ethtool filesystem findutils \ + gawk grep initscripts iproute iputils net-tools nfs-utils pam \ + psmisc rsync sed setup shadow-utils rsyslog tzdata util-linux \ + words zlib tar less gzip which util-linux openssh-clients \ + openssh-server dhclient pciutils vim-minimal shadow-utils \ + strace cronie crontabs cpio wget rocky-release ipmitool yum \ + NetworkManager + +You can do something similar with Debian-based distributions: + +.. code-block:: console + + # apt-get install debootstrap + # debootstrap stable /tmp/newroot http://ftp.us.debian.org/debian + +Once you have created and modified your new ``chroot()``, you can +import it into Warewulf with the following command: + +.. code-block:: console + + # wwctl container import /tmp/newroot containername + +Building A Container Using Apptainer +------------------------------------ + +Apptainer, a container platform for HPC and performance intensive +applications, can also be used to create node containers for +Warewulf. There are several Apptainer container recipes in the +``containers/Apptainer/`` directory and can be found on GitHub at +`https://github.com/warewulf/warewulf/tree/main/containers/Apptainer +`_. + +You can use these as starting points and adding any additional steps +you want in the ``%post`` section of the recipe file. Once you've done +that, installing Apptainer, building a container sandbox and importing +into Warewulf can be done with the following steps: + +.. code-block:: console + + # yum install epel-release + # yum install Apptainer + # Apptainer build --sandbox /tmp/newroot /path/to/Apptainer/recipe.def + # wwctl container import /tmp/newroot containername + +Building A Container Using Podman +--------------------------------- + +You can also build a container using podman via a ``Dockerfile``. For +this step the container must be exported to a tar archive, which then +can be imported to Warewulf. The following steps will create an +openSUSE Leap container and import it to Warewulf: + +.. code-block:: console + + # podman build -f containers/Docker/openSUSE/Containerfile --tag leap-ww + # podman save localhost/leap-ww:latest -o ~/leap-ww.tar + # wwctl container import file://root/leap-ww.tar leap-ww + +Container Size Considerations +============================= + +Base compute node container images start quite small (a few hundred +megabytes), but can grow quickly as packages and other files are added +to them. Even these larger images are typically not an issue in modern +environments; but some architectural limits exist that can impede the +use of images larger than a few gigabytes. Workarounds exist for these +issues in most circumstances: + +* Systems booting in legacy / BIOS mode, being a 32-bit environment, + cannot boot an image that requires more than 4GB to decompress. This + means that the compressed image and the decompressed image together + must be < 4GB. This is typically reported by the system as "No space + left on device (https://ipxe.org/34182006)." + + The best work-around for this limitation is to switch to UEFI. UEFI + is 64-bit and should support booting significantly larger images, + though sometimes system-specific implementation details have led to + artificial limitations on image size. + +* The Linux kernel itself can only decompress an image up to 4GB due + to the use of 32-bit integers in critical sections of the kernel + initrd decompression code. + + The best work-around for this limitation is to use an iPXE with + support for `imgextract `_. This + allows iPXE to decompress the image rather than the kernel. + +* Some BIOS / firmware retain a "memory hole" feature for legacy + devices, e.g., reserving a 1MB block of memory at the 15MB-16MB + address range. this feature can interfere with booting stateless + node images. + + If you are still getting "Not enough memory" or "No space left on + device" errors, try disabling any "memory hole" features or updating + your system BIOS or firmware. + +Duplicating a container +============================ +It is possible to duplicate an installed image by using : + +.. code-block:: console + + # wwctl container copy CONTAINER_NAME DUPLICATED_CONTAINER_NAME + +This kind of duplication can be useful if you are looking for canary tests. \ No newline at end of file diff --git a/static/docs/v4.5.x/_sources/contents/disks.rst.txt b/static/docs/v4.5.x/_sources/contents/disks.rst.txt new file mode 100644 index 00000000..bc521eba --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/disks.rst.txt @@ -0,0 +1,113 @@ +=============== +Disk Management +=============== + +Warewulf itself does not manage disks, partitions, or file systems directly, but provides structures in the configuration for these objects. +At the moment warewulf supports `ignition`_ to create the partitions and file systems. + +.. _ignition: https://coreos.github.io/ignition/ + +.. note:: + + It is not currently possible to manage the root file system with + Warewulf. + +Warewulf can be used, for example, to create ``swap`` partitions or ``/scratch`` file systems. + +Requirements +============ + +Partition and file system creation requires both ``ignition`` and ``sgdisk`` to be installed in the container image. + +Rocky Linux +----------- + +.. code-block:: shell + + dnf install ignition gdisk + +openSuse Leap +------------- + +.. code-block:: shell + + zypper install ignition gptfdisk + +Storage objects +=============== + +The format of the storage objects is inspired by ``butane/ignition``; +but, where ``butane/ignition`` uses lists for holding disks, partitions and file systems, Warewulf uses maps instead. + +A node or profile can have several disks, where each disk is identified by the path to its block device. +Every disks holds a map to its partitions and a ``bool`` switch to indicate if an existing partition table should be overwritten if it does not matched the desired configuration. + +Each partition is identified by its label. +The partition number can be omitted, but specifying it is recommended as ``ignition`` may fail without it. +Partition sizes should also be set (specified in MiB), except of the last partition: +if no size is given, the maximum available size is used. +Each partition has the switches ``should_exist`` and ``wipe_partition_entry`` which control the partition creation process. + +File systems are identified by their underlying block device, preferably using the ``/dev/by-partlabel`` format. +Except for a ``swap`` partition, an absolute path for the mount point must be specified for each file system. +Depending on the container used, valid formats are ``btrfs``, ``ext3``, ``ext4``, and ``xfs``. +Each file system has the switch ``wipe_filesystem`` to control whether an existing file system is wiped. + +Ignition Implementation +======================= + +The ignition implementation uses systemd services, as the underlying ``sgdisk`` command relies on dbus notifications. +All necessary services are distributed by the ``wwinit`` overlay and depends on the existence of the file ``/warewulf/ignition.json``. +This file is created by the template function ``{{ createIgnitionJson }}`` only if the configuration contains necessary specifications for disks, partitions, and file systems. +If the file ``/warewulf/ignition.json`` exists, the service ``ignition-disks-ww4.service`` calls the ignition binary which takes creates partitions and file systems. +A systemd ``.mount`` unit is created for each configured file system, which also creates the necessary mount points in the root file system. +These mount units are required by the enabled ``ww4-disks.target``. +Entries in ``/etc/fstab`` are created with the ``no_auto`` option so that file systems can be easily mounted. + +Example disk configuration +========================== + +The following command will create a ``/scratch`` file system on the node ``n01``. + +.. code-block:: shell + + wwctl node set n01 \ + --diskname /dev/vda --diskwipe \ + --partname scratch --partcreate \ + --fsname scratch --fsformat btrfs --fspath /scratch --fswipe + +As this is a single file system, the partition number can be omitted. + +A swap partition with 1Gig can be added with + +.. code-block:: shell + + wwctl node set n01 \ + --diskname /dev/vda \ + --partname swap --partsize=1024 --partnumber 1 \ + --fsname swap --fsformat swap --fspath swap + +which has the partition number ``1`` so that it will be added before the +``/scratch`` partition. + +Troubleshooting +=============== + +If the partition creation didn't work as expected you have a few options to investigate: + +- Add ``systemd.log_level=debug`` and or ``rd.debug`` to the kernelArgs of the node you're working on. +- After the next boot you should be able to find verbose information on the node with ``journalctl -u ignition-ww4-disks.service``. +- You could also check the content of ``/warewulf/ignition.json``. +- You could try to tinker with ``/warewulf/ignition.json`` calling + + .. code-block:: shell + + /usr/lib/dracut/modules.d/30ignition/ignition \ + --platform=metal \ + --stage=disks \ + --config-cache=/warewulf/ignition.json \ + --log-to-stdout + + after each iteration on the node directly until you find the settings you need. + (Make sure to unmount all partitions if ``ignition`` was partially successful.) +- Sometimes you need to add ``should_exist: "true"`` for the swap partition as well. diff --git a/static/docs/v4.5.x/_sources/contents/dnsmasq.rst.txt b/static/docs/v4.5.x/_sources/contents/dnsmasq.rst.txt new file mode 100644 index 00000000..29f4ca0f --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/dnsmasq.rst.txt @@ -0,0 +1,62 @@ +======= +Dnsmasq +======= + +Usage +===== + +As experimental feature its possible to use ``dnsmasq`` instead of the ISC ``dhcpd`` server in combination with a ``TFTP`` server. +The ``dnsmasq`` service is then acting as ``dhcp`` and ``TFTP`` server. +In order to keep the file ``/etc/dnsmasq.d/ww4-hosts.conf`` is created and must be included in the main ``dnsmasq.conf`` via the ``conf-dir=/etc/dnsmasq.d`` option. + + +Installation +------------ + +Before the installation, make sure that ``dhcpd`` and ``tftp`` are disabled. +You can do that with the commands: + +.. code-block:: shell + + systemctl disable dhcpd + systemctl stop dhcpd + systemctl disable tftp + systemctl stop tftp + +Now you can install ``dnsmasq``. + +.. code-block:: shell + + zypper install dnsmasq + +After the installation you have to instruct ``warewulf`` to use ``dnsmasq`` as its ``dhcpd`` and ``tftp`` service. +``dnsmasq`` has to be specified in the configuration file ``/etc/warewulf/warewulf.conf``. + +.. code-block:: shell + + tftp: + systemd name: dnsmasq + dhcp: + systemd name: dnsmasq + +The configuration of ``dnsmasq`` doesn't need to be changed, as the default configuration includes all files with following pattern ``/etc/dnsmasq.d/*conf`` into its configuration. +This configuration is created by the overlay template ``host:/etc/dnsmasq.d/ww4-hosts.conf.ww``. +In order to build this template run + +.. code-block:: shell + + wwctl overlay build -H + +After that the ``dnsmasq`` service has to be enabled. +Either + +.. code-block:: shell + + systemctl enable --now dnsmasq + +or by (re)configuring warewulf with + +.. code-block:: shell + + wwctl configure dhcp + wwctl configure tftp diff --git a/static/docs/v4.5.x/_sources/contents/glossary.rst.txt b/static/docs/v4.5.x/_sources/contents/glossary.rst.txt new file mode 100644 index 00000000..2f576530 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/glossary.rst.txt @@ -0,0 +1,32 @@ +======== +Glossary +======== + +Container + Containers are used by Warewulf as the template for the VNFS + image. Warewulf containers can be any type of OCI or Singularity + standard image formats but maintained on disk as an "OCI + bundle". Warewulf integrates with Docker, Docker Hub, any OCI + registery, Singularity, standard chroots, etc. + +Controller + The controller node(s) are the resources responsible for + management, control, and administration of the + cluster. Historically these systems have been called "master", + "head", or "administrative" nodes, but we feel the term + "controller" is more appropriate and descriptive of the role of + this system. + +Initramfs + +Kernel + +Overlays + +Virtual Node File System (VNFS) + +Workers + Worker nodes are the systems that are being provisioned by + Warewulf. The roles of these systems could be "compute", + "storage", "GPU", "IO", etc. which would typically be used as a + prefix, for example: "**compute worker node**" diff --git a/static/docs/v4.5.x/_sources/contents/initialization.rst.txt b/static/docs/v4.5.x/_sources/contents/initialization.rst.txt new file mode 100644 index 00000000..2e605901 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/initialization.rst.txt @@ -0,0 +1,69 @@ +======================= +Warewulf Initialization +======================= + +System Services +=============== + +Once Warewulf has been installed and configured, it is ready to be +initialized and have the associated system services started. To do +this, start by configuring the system services that Warewulf depends +on for operation. To do that, run the following command: + +.. code-block:: console + + # wwctl configure --all + +This command will configure the system for Warewulf to run +properly. Here are the things it will do: + +* **dhcp**: (re)Write the DHCP configuration and restart the service + from the **host** template under ``/etc/dhcpd.conf.ww`` and enable + the system service. +* **hostfile**: Update the system's /etc/hosts file based on the + **host** template ``/etc/hosts.ww``. +* **nfs**: Configure the NFS server on the control node as well as the + ``/etc/fstab`` in the system overlay based on the configuration in + ``/etc/warewulf/warewulf.conf`` and enable the system service. Also + the file ``/etc/exports.ww`` from the **host** template is installed. +* **ssh**: Create the appropriate host keys (stored in + ``/etc/warewulf/keys/``) and user keys for passwordless ``ssh`` into + the nodes. Addionally the shell profiles + ``/etc/profile.d/ssh_setup.csh`` and ``/etc/profile.d/ssh_setup.sh`` + are installed. +* **tftp**: Write the appropriate binary PXE/iPXE blobs to the TFTP + root directory and enable the system service. + +This command will quickly setup the system services per the Warewulf +configuration. Watch this output carefully for errors and resolve them +in the configuration portion of this manual. + +Warewulf Service +================ + +The Warewulf installation attempts to register the Warewulf service +with systemd, so it should be as easy to start/stop/check as any other +systemd service: + +.. code-block:: console + + # systemctl enable --now warewulfd + +You can also check and control the Warewulf service using the ``wwctl`` +command line program as follows: + +.. code-block:: console + + # wwctl server status + +.. note:: + + If the Warewulf service is running via systemd, restarting + stopping, and starting it from the ``wwctl`` command may result in + unexpected results. + +Logs +---- + +The Warewulf server logs are by default written to +``/var/log/warewulfd.log``. diff --git a/static/docs/v4.5.x/_sources/contents/installation.rst.txt b/static/docs/v4.5.x/_sources/contents/installation.rst.txt new file mode 100644 index 00000000..caadecf0 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/installation.rst.txt @@ -0,0 +1,110 @@ +===================== +Warewulf Installation +===================== + +There are multiple methods to install Warewulf. This page describes +the installation process for some of those methods. + +Binary RPMs +=========== + +The Warewulf project builds binary RPMs as part of its CI/CD +process. You can obtain them from the `GitHub releases`_ page. + +.. _GitHub releases: https://github.com/warewulf/warewulf/releases + +Rocky Linux 8 +------------- + +.. code-block:: console + + # dnf install https://github.com/warewulf/warewulf/releases/download/v4.4.0/warewulf-4.4.0-1.git_afcdb21.el8.x86_64.rpm + +openSuse Leap +------------- + +.. code-block:: console + + # zypper install https://github.com/warewulf/warewulf/releases/download/v4.4.0/warewulf-4.4.0-1.git_afcdb21.suse.lp153.x86_64.rpm + +Compiled Source code +==================== + +Before you build the Warewulf source code you will first need to +install the build dependencies: + +* ``make``: This should be available via your Linux distribution's + package manager (e.g. ``dnf install make``) +* ``go``: Golang is also available on most current Linux + distributions, but if you wish to install the most recent version, + you can find that here: `https://golang.org/dl/ + `_ +* Depending on your Linux Distribution, you may need to install other + development packages. Typically it is recommended to install the + entire development group like ``dnf groupinstall "Development + Tools"`` + +Once these dependencies are installed, you can obtain and build the +source code as follows: + +Release Tarball +--------------- + +The Warewulf project releases source distributions alongside its +binary RPMs. You can obtain them from the `GitHub releases`_ page. + +Select the version you wish to install and download the tarball to any +location on the server, then follow these directions making the +appropriate substitutions: + +.. code-block:: bash + + VERSION=4.4.0 + curl -LO https://github.com/hpcng/warewulf/releases/download/v${VERSION}/warewulf-${VERSION}.tar.gz + tar -xf warewulf-${VERSION}.tar.gz + cd warewulf-${VERSION} + make all && sudo make install + +Git +--- + +Warewulf is developed in GitHub, a source code management platform +that allows collaborative development and revision control. From the +Git repository, you can download different versions of the project +either from tags or branches. By default, when you go to the GitHub +page, you will find the default branch entitled ``development``. The +``development`` branch is where most of the active development occurs, +so if you want to obtain the latest and greatest version of Warewulf, +this is where to go. But be forewarned, using a snapshot from +``development`` is not guaranteed to be stable or generally supported +for production. + +Alternatively, the ``main`` branch is more stable and is used as a +staging area for pending releases. + +If you are building for production, it is best to download a release +tarball from the main site, the GitHub releases page, or from a Git +tag. + +.. code-block:: bash + + git clone https://github.com/hpcng/warewulf.git + cd warewulf + git checkout development # or switch to a tag like 'v4.4.0' + make all && sudo make install + +Runtime Dependencies +-------------------- + +In Warewulf's default configuration, it will require some operating +system provided services. Generally these are provided by your +installation vendor and can be installed over the network. + +These are the services you will need to install: + +* ``dhcp-server`` +* ``tftp-server`` +* ``nfs-utils`` + +If you are using an Enterprise Linux compatible distribution you can +install them with ``yum install dhcp-server tftp-server nfs-utils``. diff --git a/static/docs/v4.5.x/_sources/contents/introduction.rst.txt b/static/docs/v4.5.x/_sources/contents/introduction.rst.txt new file mode 100644 index 00000000..fa57791d --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/introduction.rst.txt @@ -0,0 +1,75 @@ +============ +Introduction +============ + +The Warewulf Vision +=================== + +Warewulf has had a number of iterations over the last 20 years, but +its design tenets have always remained the same: a simple, scalable, +stateless (however some versions were able to provision stateful), and +very flexible operating system provisioning system for all types of +clusters. This is an overview of how Warewulf works. + +About Warewulf +============== + +Warewulf is an operating system provisioning platform for Linux that +is designed to produce secure, scalable, turnkey cluster deployments +that maintain flexibility and simplicity. + +Since its initial release in 2001, Warewulf has become the most +popular open source and vendor-agnostic provisioning system within the +global HPC community. Warewulf is known for its massive scalability +and simple management of stateless (disk optional) provisioning. + +Warewulf leverages a simple administrative model centralizing +administration around virtual node images which are used to provision +out to the cluster nodes. This means you can have hundreds or +thousands of cluster nodes all booting and running on the same, +identical virtual node file system image. As of Warewulf v4, the +virtual node image is a standard container image which means all +compute resources within a cluster can be managed using any existing +container tooling and/or CI pipelines that are being used. This can be +as simple as DockerHub or your own private GitLab CI infrastructure. + +With this architecture, Warewulf combines the best of High Performance +Computing (HPC), Cloud, Hyperscale, and Enterprise deployment +principals to create and maintain large scalable stateless clusters. + +While Warewulf's roots are in HPC, it has been used for many different +types of tasks and use cases. Everything from clustered web servers, +to rendering farms, and even Kubernetes and cloud deployments, +Warewulf brings benefit in experience of general operating system +management at scale. + +Features +======== + +* **Lightweight**: Warewulf provisions stateless operating system + images and then gets out of the way. There should be no underlying + system dependencies or changes to the provisioned cluster node + operating systems. + +* **Simple**: Warewulf is used by hobbyists, researchers, scientists, + engineers and systems administrators because it is easy, + lightweight, and simple. + +* **Flexible**: Warewulf is highly flexible and can address the needs + of any environment-- from a computer lab with graphical + workstations, to under-the-desk clusters, to massive supercomputing + centers providing traditional HPC capabilities to thousands of + users. + +* **Agnostic**: From the Linux distribution of choice to the + underlying hardware, Warewulf is agnostic and standards + compliant. From ARM to x86, Atos to Dell, Debian, SUSE, Rocky, + CentOS, and RHEL, Warewulf can do it all. + +* **Secure**: Warewulf is the only stateless provisioning system that + will support SELinux out of the box. Just enable your node operating + system container to support SELinux, and Warewulf do the rest! + +* **Open Source**: For the last 20 years, Warewulf has remained open + source and continues to be the golden standard for cluster + provisioning. diff --git a/static/docs/v4.5.x/_sources/contents/ipmi.rst.txt b/static/docs/v4.5.x/_sources/contents/ipmi.rst.txt new file mode 100644 index 00000000..43083206 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/ipmi.rst.txt @@ -0,0 +1,183 @@ +==== +IPMI +==== + +It is possible to control the power or connect a console to your nodes +being managed by Warewulf by connecting to the BMC through the use of +IPMI. We will discuss how to set this up below. + +IPMI Settings +============= + +The common settings for the IPMI interfaces on all nodes can be set on +a Profile level. The only field that would need to be assigned to each +individual node would be the IP address. + +The settings are only written to the IPMI interface if ``--ipmiwrite`` +is set to `true`. The write process happens at every boot of the node +through the script ``/warewulf/init.d/50-ipmi`` in the **system** +overlay. + +If an individual node has different settings, you can set the IPMI +settings for that specific node, overriding the default settings. + +Here is a table outlining the fields on a Profile and Node which is +the same as the parameter that can be used when running ``wwctl +profile set`` or ``wwctl node set``. + ++----------------------+---------+------+--------------------+---------------+ +| Parameter | Profile | Node | Valid Values | Default Value | ++======================+=========+======+====================+===============+ +| ``--ipmiaddr`` | false | true | | | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipminetmask`` | true | true | | | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmiport`` | true | true | | 623 | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmigateway`` | true | true | | | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmiuser`` | true | true | | | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmipass`` | true | true | | | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmiinterface`` | true | true | 'lan' or 'lanplus' | lan | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmiwrite`` | true | true | true or false | false | ++----------------------+---------+------+--------------------+---------------+ +| ``--ipmiescapechar`` | true | true | single character | ~ | ++----------------------+---------+------+--------------------+---------------+ + + +Reviewing Settings +================== + +There are multiple ways to review the IPMI settings. They can be +reviewed from a Profile level, all the way down to a specific Node. + +Profile View +------------ + +.. code-block:: console + + # wwctl profile list -a + PROFILE FIELD PROFILE VALUE + ===================================================================================== + default Id -- default + default comment -- This profile is automatically included for each node + default cluster -- -- + default container -- sle-micro-5.3 + default ipxe -- -- + default runtime -- -- + default wwinit -- -- + default root -- -- + default discoverable -- -- + default init -- -- + default asset -- -- + default profile -- -- + default default:type -- -- + default default:onboot -- -- + default default:netdev -- -- + default default:hwaddr -- -- + default default:ipaddr -- -- + default default:ipaddr6 -- -- + default default:netmask -- -- + default default:gateway -- -- + default default:mtu -- -- + default default:primary -- -- + + +Node View +--------- + +.. code-block:: console + + # wwctl node list -a n001 + NODE FIELD PROFILE VALUE + ===================================================================================== + n001 Id -- n001 + n001 comment default This profile is automatically included for each node + n001 cluster -- -- + n001 container default sle-micro-5.3 + n001 ipxe -- (default) + n001 runtime -- (generic) + n001 wwinit -- (wwinit) + n001 root -- (initramfs) + n001 discoverable -- -- + n001 init -- (/sbin/init) + n001 asset -- -- + n001 kerneloverride -- tw + n001 kernelargs -- (quiet crashkernel=no vga=791 net.naming-scheme=v238) + n001 ipmiaddr -- -- + n001 ipminetmask -- -- + n001 ipmiport -- -- + n001 ipmigateway -- -- + n001 ipmiuser -- -- + n001 ipmipass -- -- + n001 ipmiinterface -- -- + n001 ipmiwrite -- -- + n001 ipmiescapechar -- -- + n001 profile -- default + n001 default:type -- (ethernet) + n001 default:onboot -- -- + n001 default:netdev -- eth0 + n001 default:hwaddr -- 11:22:33:44:55:66 + n001 default:ipaddr -- 10.0.2.1 + n001 default:ipaddr6 -- -- + n001 default:netmask -- 255.255.252.0 + n001 default:gateway -- -- + n001 default:mtu -- -- + n001 default:primary -- true + +Review Only IPMI Settings +------------------------- + +The above views show you everything that is set on a Profile or Node +level. That is a lot of detail. If you want to view key IPMI connecton +details for a node or all nodes, you can do the following. + +.. code-block:: console + + # wwctl node list -i + NODE NAME IPMI IPADDR IPMI PORT IPMI USERNAME IPMI INTERFACE + ================================================================================================== + n001 192.168.1.11 -- hwadmin -- + n002 192.168.1.12 -- hwadmin -- + n003 192.168.1.13 -- hwadmin -- + n004 192.168.1.14 -- hwadmin -- + + +Power Commands +============== + +The ``power`` command can be used to manage the current power state of +your nodes through IPMI. + +``wwctl power [command]`` where ``[command]`` is one of: + +cycle + Turns the power off and then on + +off + Turns the power off + +on + Turns the power on + +reset + Issues a reset + +soft + Shutdown gracefully + +status + Shows current power status + +Console +======= + +If your node is setup to use serial over lan (SOL), Warewulf can +connect a console to the node. + +.. code-block:: console + + # wwctl node console n001 diff --git a/static/docs/v4.5.x/_sources/contents/kernel.rst.txt b/static/docs/v4.5.x/_sources/contents/kernel.rst.txt new file mode 100644 index 00000000..a2eb1715 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/kernel.rst.txt @@ -0,0 +1,73 @@ +================= +Kernel Management +================= + +Node Kernels +============ + +Warewulf nodes require a Linux kernel to boot. There are multiple ways +to do this, but the default and easiest way is to install the kernel +you wish to use for a particular container into the container. + +Warewulf will locate the kernel automatically within the container and +by default use that kernel for any node configured to use that +container image. + +You can see what kernel is included in a container by using the +``wwctl container list`` command: + +.. code-block:: console + + # wwctl container list + CONTAINER NAME NODES KERNEL VERSION CREATION TIME MODIFICATION TIME SIZE + alpine 0 05 Jun 23 20:02 MDT 05 Jun 23 20:02 MDT 17.9 MiB + rocky-8 1 4.18.0-372.13.1.el8_6.x86_64 17 Jan 23 23:48 MST 06 Apr 23 09:40 MDT 2.4 GiB + +Here you will notice the alpine contianer that was imported has no +kernel within it, and the rocky container includes a kernel. + +This model was introduced in Warewulf v4.3. Previously, Warewulf +managed the kernel and the container separately, which made it hard to +build and distribute containers that have custom drivers and/or +configurations included (e.g. OFED, GPUs, etc.). + +Kernel Overrides +================ + +It is still possible to specify a kernel for a container if it doesn't +include it's own kernel, or if you wish to override the default kernel +by using the ``kernel override`` capability. + +You can specify this option with the ``--kerneloverride`` option to +``wwctl node set`` or ``wwctl profile set`` commands. + +In this case you will also need to import a kernel specifically into +Warewulf for this purpose using the ``wwctl kernel import`` command as +follows: + +.. code-block:: console + + # wwctl kernel import $(uname -r) + 4.18.0-305.3.1.el8_4.x86_64: Done + +This process will import not only the kernel image itself, but also +all of the kernel modules and firmware associated with this kernel. + +Listing All Imported Kernels +---------------------------- + +Once the kernel has been imported, you can list them all with the +following command: + +.. code-block:: console + + # wwctl kernel list + VNFS NAME NODES + 4.18.0-305.3.1.el8_4.x86_64 0 + + # wwctl kernel list + KERNEL NAME KERNEL VERSION NODES + 4.18.0-305.3.1.el8_4.x86_64 0 + +Once a kernel has been imported you can configure it to boot compute +nodes. diff --git a/static/docs/v4.5.x/_sources/contents/nodeconfig.rst.txt b/static/docs/v4.5.x/_sources/contents/nodeconfig.rst.txt new file mode 100644 index 00000000..539b4aef --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/nodeconfig.rst.txt @@ -0,0 +1,286 @@ +================== +Node Configuration +================== + +The Node Configuration DB +========================= + +As mentioned in the :doc:`Warewulf Configuration ` +section, node configs are persisted to the ``nodes.conf`` YAML file, +but generally it is best not to edit this file directly (however that +is supported, it is just prone to errors). + +This method of using a YAML configuration file as a backend datastore +is both scalable and very lightweight. We've tested this out to over +10,000 node entries which yielded update latencies under 1 second, +which we felt was both tolerable and advantageous. + +Adding a New Node +================= + +Creating a new node is as simple as running the following command: + +.. code-block:: console + + # wwctl node add n001 -I 10.0.2.1 + Added node: n001 + +Adding several nodes +-------------------- + +Several nodes can be added with a single command if a node range is +given. An additional IP address will incremented. So the command + +.. code-block:: console + + # wwctl node add n00[2-4] -I 10.0.2.2 + Added node: n002 + Added node: n003 + Added node: n004 + + # wwctl node list -n n00[1-4] + NODE NAME NAME HWADDR IPADDR GATEWAY DEVICE + n001 default -- 10.0.2.1 -- (eth0) + n002 default -- 10.0.2.2 -- (eth0) + n003 default -- 10.0.2.3 -- (eth0) + n004 default -- 10.0.2.4 -- (eth0) + +has added 4 nodes with the incremented IP addresses. + +Node Names +---------- + +For small clusters, you can use simple names (e.g. ``n0000``); but for +larger, more complicated clusters that are comprised of multiple +clusters and roles it is highly recommended to use node names that +include a cluster descriptor. In Warewulf, this is generally done by +using a domain name (e.g. ``n001.cluster01``). Warewulf will +automatically assume that the domain is the equivalent of the cluster +name. + +This also means that you can address groups of nodes by the cluster +descriptor with globs. For example, you are able to refer to all nodes +in "cluster01" with the following string: ``*.cluster01`` which is +valuable for other ``wwctl`` commands. + +Listing Nodes +============= + +Once you have configured one or more nodes, you can list them and +their attributes as follows: + +.. code-block:: console + + # wwctl node list + NODE NAME PROFILES NETWORK + n001 default + +You can also see the node's full attribute list by specifying the +``-a`` option (all): + +.. code-block:: console + + # wwctl node list -a n001 + NODE FIELD PROFILE VALUE + n001 Id -- n001 + n001 comment default This profile is automatically included for each node + n001 cluster -- -- + n001 container default sle-micro-5.3 + n001 ipxe -- (default) + n001 runtime -- (generic) + n001 wwinit -- (wwinit) + n001 root -- (initramfs) + n001 discoverable -- -- + n001 init -- (/sbin/init) + n001 asset -- -- + n001 kerneloverride -- -- + n001 kernelargs -- (quiet crashkernel=no vga=791 net.naming-scheme=v238) + n001 ipmiaddr -- -- + n001 ipminetmask -- -- + n001 ipmiport -- -- + n001 ipmigateway -- -- + n001 ipmiuser -- -- + n001 ipmipass -- -- + n001 ipmiinterface -- -- + n001 ipmiwrite -- -- + n001 profile -- default + n001 default:type -- (ethernet) + n001 default:onboot -- -- + n001 default:netdev -- (eth0) + n001 default:hwaddr -- -- + n001 default:ipaddr -- 172.16.1.11 + n001 default:ipaddr6 -- -- + n001 default:netmask -- (255.255.255.0) + n001 default:gateway -- -- + n001 default:mtu -- -- + n001 default:primary -- true + +.. note:: + + The attribute values in parenthesis are default values and can be + overridden in the next section, granted, the default values are + generally usable. + +Setting Node Attributes +======================= + +In the above output we can see that there is no kernel or container +defined for this node. To provision a node, the minimum requirements +are a kernel and container, and for that node to be useful, we will +also need to configure the network so the nodes are reachable after +they boot. + +Node configurations are set using the ``wwctl node set`` command. To +see a list of all configuration attributes, use the command ``wwctl +node set --help``. + +Configuring the Node's Container Image +====================================== + +.. code-block:: console + + # wwctl node set --container rocky-8 n001 + Are you sure you want to modify 1 nodes(s): y + +And you can check that the container name is set for ``n001``: + +.. code-block:: console + + # wwctl node list -a n001 | grep Container + n0000 Container -- rocky-8 + +Configuring the Node's Kernel +----------------------------- + +While the recommended method for assigning a kernel in v4.3 and beyond +is to include it in the container / node image, a kernel can still be +specified as an override at the node or profile. To illustrate this, +we import the most recent kernel from a openSUSE Tumbleweed release. + +.. code-block:: console + + # wwctl container import docker://registry.opensuse.org/science/warewulf/tumbleweed/containerfile/kernel:latest tw + # wwctl kernel import -DC tw + # wwctl kernel list + KERNEL NAME KERNEL VERSION NODES + tw 6.1.10-1-default 0 + # wwctl node set --kerneloverride tw n001 + Are you sure you want to modify 1 nodes(s): y + + # wwctl node list -a n001 | grep kerneloverride + n001 kerneloverride -- tw + +Configuring the Node's Network +------------------------------ + +To configure the network, we have to pick a network device name and +provide the network information as follows: + +.. code-block:: console + + # wwctl node set --netdev eth0 --hwaddr 11:22:33:44:55:66 --ipaddr 10.0.2.1 --netmask 255.255.252.0 n001 + Are you sure you want to modify 1 nodes(s): y + +You can now see that the node contains configuration attributes for +container, kernel, and network: + +.. code-block:: console + + # wwctl node list -a n001 + NODE FIELD PROFILE VALUE + n001 Id -- n001 + n001 comment default This profile is automatically included for each node + n001 cluster -- -- + n001 container default sle-micro-5.3 + n001 ipxe -- (default) + n001 runtime -- (generic) + n001 wwinit -- (wwinit) + n001 root -- (initramfs) + n001 discoverable -- -- + n001 init -- (/sbin/init) + n001 asset -- -- + n001 kerneloverride -- tw + n001 kernelargs -- (quiet crashkernel=no vga=791 net.naming-scheme=v238) + n001 ipmiaddr -- -- + n001 ipminetmask -- -- + n001 ipmiport -- -- + n001 ipmigateway -- -- + n001 ipmiuser -- -- + n001 ipmipass -- -- + n001 ipmiinterface -- -- + n001 ipmiwrite -- -- + n001 profile -- default + n001 default:type -- (ethernet) + n001 default:onboot -- -- + n001 default:netdev -- eth0 + n001 default:hwaddr -- 11:22:33:44:55:66 + n001 default:ipaddr -- 10.0.2.1 + n001 default:ipaddr6 -- -- + n001 default:netmask -- 255.255.252.0 + n001 default:gateway -- -- + n001 default:mtu -- -- + n001 default:primary -- true + + # wwctl node set --cluster cluster01 n001 + Are you sure you want to modify 1 nodes(s): y + + # wwctl node list -a n001 | grep cluster + n001 cluster -- cluster01 + + +To configure a bonded (link aggreagtion) network interface the following commands can be used: + +.. code-block:: console + + # wwctl node set --netname=bond0_member_1 --netdev=eth2 --type=bond-slave n001 + # wwctl node set --netname=bond0_member_2 --netdev=eth3 --type=bond-slave n001 + # wwctl node set --netname=bond0 --netdev=bond0 --onboot=true --type=bond --ipaddr 10.0.3.1 --netmask=255.255.255.0 --mtu=9000 n001 + +Note: the netnames of the member interterfaces need to match the "netname" of the bonded interface until the first "_" (in the example bond0) + + +Additional networks +------------------- + +Additional networks for the node can also be configured. +You will have provide all the necessary network information. + +.. code-block:: shell + + wwctl node set \ + --netdev ib0 \ + --hwaddr aa:bb:cc:dd:ee:ff \ + --ipaddr 10.0.20.1 \ + --netmask 255.255.252.0 \ + --netname iband \ + --type infiniband \ + n001 + + +Node Discovery +-------------- + +The hwaddr of a node can be automatically discovered by setting +``--discoverable`` on a node. If a node attempts to provision against +Warewulf using an interface that is unknown to Warewulf, that address +is associated with the first discoverable node. (Multiple discoverable +nodes are sorted lexically, first by cluster, then by ID.) + +Once a node has been discovered its "discoverable" flag is +automatically cleared. + +Un-setting Node Attributes +========================== + +If you wish to ``unset`` a particular value, set the value to +``UNDEF``. For example: + +And to unset this configuration attribute: + +.. code-block:: console + + # wwctl node set --cluster UNDEF n001 + Are you sure you want to modify 1 nodes(s): y + + # wwctl node list -a n001 | grep Cluster + n001 Cluster -- -- diff --git a/static/docs/v4.5.x/_sources/contents/overlays.rst.txt b/static/docs/v4.5.x/_sources/contents/overlays.rst.txt new file mode 100644 index 00000000..cd1fe5be --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/overlays.rst.txt @@ -0,0 +1,256 @@ +================= +Warewulf Overlays +================= + +So at this point, we have discussed how Warewulf is designed to +scalably provision and manage thousands of cluster nodes by utilizing +identical stateless boot images. And there-in lies a problem to +solve. If these boot images are completely identical, then how do we +configure things like hostnames? IP addresses? Or any other node +specific custom configurations? + +While some of this can be managed by services like DHCP, and other +bits by configuration management, which can absolutely be done with +Warewulf and many people choose to do, these are heavy-weight +solutions to a simple problem to solve. + +Warewulf solves this with overlays and uses overlays in different ways +through the provisioning process. A node or profile can configure an +overlay in two different ways: + +* An overlay can be configured to run during boot as part of the + ``wwinit`` process. These overlays are called **system overlay** or + **wwinit overlays**. +* An overlay can be configured to run periodically while the system is + running. These overlays are called **runtime overlays** or **generic + overlays**. + +The default profile has both a **wwinit** and a **runtime** overlay +configured. + +Overlays are compiled for each compute node individually. + +Defined Overlays +================ + +System or wwinit overlay +------------------------ + +This overlay contains all the nesscesary scripts to provision a +Warewulf node. It is available before the ``systemd`` or other init is +called and contains all configurations which are needed to bring up +the compute node. It is not updated during run time. Besides the +network configurations for + +* wicked +* NetworkManager +* EL legacy network scripts + +it also contains udev rules, which will set the interface name of the +first network device to ``eth0``. Before the ``systemd`` init is +called, the overlay loops through the scripts in +``/wwinit/warwulf/init.d/*`` which will setup + +* Ipmi +* wwclient +* selinux + +Runtime Overlay or generic Overlay +---------------------------------- + +The runtime overlay is updated by the ``wwclient`` service on a +regular basis (by default, once per minute). In the standard +configuration it includes updates for ``/etc/passwd``, ``/etc/group`` +and ``/etc/hosts``. Additionally the ``authorized_keys`` file of the +root user is updated. It is recommended to use this overlay for +dynamic configuration files like ``slurm.conf``. Once the system is +provisioned and booted, the ``wwclient`` program (which is provisioned +as part of the ``wwinit`` system overlay) will continuously update the +node with updates in the runtime overlay. + +Host Overlay +------------ + +Configuration files used for the configuration of the Warewulf host / +server are stored in the **host** overlay. Unlike other overlays, it +*must* have the name ``host``. Existing files on the host are copied +to backup files with a ``wwbackup`` suffix at the first +run. (Subsequent use of the host overlay won't overwrite existing +``wwbackup`` files.) + +The following services get configuration files via the host overlay: + +* ssh keys are created with the scrips ``ssh_setup.sh`` and + ``ssh_setup.csh`` +* hosts entries are created by manipulating ``/etc/hosts`` with the + template ``hosts.ww`` +* nfs kernel server receives its exports from the template + ``exports.ww`` +* the dhcpd service is configured with ``dhcpd.conf.ww`` + +Combining Overlays +================== + +When changing the overlays, it is recommended not to change them, but +to add the changed files to a new overlay and combine them in the +configuration. This is possible as the configuration fields for the +**wwinit** and **runtime** overlays are lists and can contain several +overlays. As an example for this, we will overwrite the +``/etc/issue`` file from the **wwinit** overlay. For this we will +create a new overlay called welcome and import the file ``/etc/issue`` +from the host to it. This overlay is then combined with the existing +**wwinit** overlay. + +.. code-block:: console + + # wwctl overlay create welcome + # wwctl overlay mkdir welcome /etc + # wwctl overlay import welcome /etc/issue + # wwctl profile set default --wwinit=wwinit,welcome + ? Are you sure you want to modify 1 profile(s)? [y/N] y + # wwctl profile list default -a |grep welcome + default SystemOverlay wwinit,welcome + +Templates +========= + +Templates allow you to create dynamic content such that the files +downloaded for each node will be customized for that node. Templates +allow you to insert everything from variables, to including files from +the control node, as well as conditional content and loops. + +Warewulf uses the ``text/template`` engine to facilitate implementing +dynamic content in a simple and standardized manner. + +All template files will end with the suffix of ``.ww``. That tells +Warewulf that when building a file, that it should parse that file as +a template. When it does that, the resulting file is static and can +have node customizations that are obtained from the node configuration +attributes. + +.. note:: + + When the file is persisted within the built overlay, the ``.ww`` + will be dropped, so ``/etc/hosts.ww`` will end up being + ``/etc/hosts``. + +Using Overlays +============== + +Warewulf includes a command group for manipulating overlays (``wwctl +overlay``). With this you can add, edit, remove, change ownership, +permissions, etc. + +.. + note:: + There is no possibility to delete files with an overlay! + +Build +----- + +.. code-block:: console + + wwctl overlay build [-H,--hosts|-N,--nodes|-o,--output directory|-O,--overlay-name] nodepattern + +Without any arguments the command will interpret the templates for all +overlays for every compute node and also all the templates in the host +overlay. For every overlay of the compute nodes a gzip compressed cpio +archive is created. The range of the nodes can be restricted as the +last argument. With the ``-H`` flag only the host overlay is +built. With the ``-N`` flag only compute node overlays are +built. Specific overlays can be selected with ``-O`` flag. For +debugging purposes the templates can be written to a directory given +via the ``-o`` flag. + +By default Warewulf will build/update and cache overlays as needed +(configurable in the ``warewulf.conf``). + +Chmod +----- + +.. code-block:: console + + wwctl overlay chmod overlay-name filename mode + +This subcommand changes the permissions of a single file within an +overlay. You can use any mode format supported by the chmod command. + +Chown +----- + +.. code-block:: console + + wwctl overlay chown overlay-name filename UID [GID] + +With this command you can change the ownership of a file within a +given overlay to the user specified by UID. Optionally, it will also +change group ownership to GID. + +Create +------ + +.. code-block:: console + + wwctl overlay create overlay-name + +This command creates a new empty overlay with the given name. + +Delete +------ + +.. code-block:: console + + wwctl overlay delete [-f,--force] overlay-name [File [File ...]] + +Either the given overlay is deleted (must be empty or use the +``--force`` flag) or the specified file within the overlay is +deleted. With the ``--parents`` flag the directory of the deleted file +is also removed if no other file is in the directory. + +Edit +---- +.. code-block:: console + + wwctl overlay edit [--mode,-m MODE|--parents,-p] overlay-name file + +Use this command to edit an existing or a new file in the given +overlay. If a the new file ends with a ``.ww`` suffix an example +template header is added to the file. With the ``--parents`` flag +necessary parent directories for a new file are created. + +Import +------ +.. code-block:: console + + wwctl overlay import [--mode,-m|--noupdate,-n] overlay-name file-name [new-file-name] + +The given file is imported to the overlay. If no new-file-name is +given, the file will be placed in the overlay at the same path as on +the host. With the ``--noupdate`` flag you can block the rebuild of +the overlays. + +List +---- + +.. code-block:: console + + wwctl overlay list [--all,-a|--long,-l] [overlay-name] + +With this command all existing overlays and files in them can be +listed. Without any option only the overlay names and their number of +files are listed. With the ``--all`` switch also the every file is +shown. The ``--long`` option will also display the permissions, UID, +and GID of each file. + +Show +---- + +.. code-block:: console + + wwctl overlay show [--quiet,-q|--render,-r nodename] overlay-name file + +The content of the file for the given overlay is displayed with this +command. With the ``--render`` option a template is rendered as it +will be rendered for the given node. The node name is a mandatory +argument to the ``--render`` flag. Additional information for the file +can be suppressed with the ``--quiet`` option. diff --git a/static/docs/v4.5.x/_sources/contents/profiles.rst.txt b/static/docs/v4.5.x/_sources/contents/profiles.rst.txt new file mode 100644 index 00000000..ba790e1d --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/profiles.rst.txt @@ -0,0 +1,195 @@ +============= +Node Profiles +============= + +Profiles provide a way to scalably group node configurations +together. Instead of redundant configurations for each node, you can +put that into a profile and the nodes will inherit these +configurations. This is very handy if you have groups of node specific +customizations. For example, a few hundred nodes that are running a +particular container or kernel, and another group of nodes that are +running a different kernel or container. + +Any node configuration attributes can be applied to a profile, but +there are always going to be some node configurations which must be +specific to a node, like a network HW/MAC address or an IP address. + +An Introduction To Profiles +=========================== + +Every new node is automatically added to a profile called +``default``. You can view the configuration attributes of this profile +by using the ``wwctl profile list`` command. Like the ``wwctl node +list`` command, this will provide a summary, but you can see **all** +configuration attributes by using the ``--all`` or ``-a`` flag as +follows: + +.. code-block:: console + + # wwctl profile list + PROFILE NAME COMMENT/DESCRIPTION + default This profile is automatically included for each node + +And with the ``-a`` flag: + +.. code-block:: console + + # wwctl profile list -a + PROFILE FIELD PROFILE VALUE + default Id -- default + default Comment -- This profile is automatically included for each node + default Cluster -- -- + default Container -- -- + default Kernel -- -- + default KernelArgs -- -- + default Init -- -- + default Root -- -- + default RuntimeOverlay -- -- + default SystemOverlay -- -- + default Ipxe -- -- + default IpmiIpaddr -- -- + default IpmiNetmask -- -- + default IpmiPort -- -- + default IpmiGateway -- -- + default IpmiUserName -- -- + default IpmiInterface -- -- + +As you can see here, there is only one attribute set by default in +this profile, and that is the "Comment" field. That Comment is +inherited by any nodes that are configured to use this profile. So if +we look at the node we configured in the last section, we can see that +configuration attribute there: + +.. code-block:: console + + # wwctl node list -a | head -n 5 + NODE FIELD PROFILE VALUE + n0000 Id -- n0000 + n0000 Comment default This profile is automatically included for each node + n0000 Cluster -- -- + +Here you can see that the "Comment" attribute was inherited by this +node, and it also provides you with the information of which profile +this attribute was inherited from. This is very useful information as +nodes can be part of multiple profiles with inheritance being +cascading. + +Multiple Profiles +================= + +For demonstration purposes, let's create another profile and +demonstrate how to use this second profile. + +.. code-block:: console + + # wwctl profile add test_profile + # wwctl profile list + PROFILE NAME COMMENT/DESCRIPTION + default This profile is automatically included for each node + test_profile -- + +Now that we've created a new profile, let's create a configuration +attribute in this profile: + +.. code-block:: console + + # wwctl profile set --cluster cluster01 test_profile + ? Are you sure you want to modify 1 profile(s)? [y/N] y + + # wwctl profile list -a test_profile | grep Cluster + test_profile Cluster cluster01 + +Lastly we just need to configure this profile to our node(s): + +.. code-block:: console + + # wwctl node set --addprofile test_profile n0000 + Are you sure you want to modify 1 nodes(s): y + +And you can now verify that the node has both profile configurations: + +.. code-block:: console + + # wwctl node list -a | head -n 6 + NODE FIELD PROFILE VALUE + n0000 Id -- n0000 + n0000 Comment default This profile is automatically included for each node + n0000 Cluster test_profile cluster01 + n0000 Profiles -- default,test_profile + +Cascading Profiles +================== + +In the previous example, we set a single node to have two profile +configurations. We can also overwrite configurations as follows: + +.. code-block:: console + + # wwctl profile set --comment "test comment" test_profile + Are you sure you want to modify 1 profile(s): y + + # wwctl node list -a | head -n 6 + NODE FIELD PROFILE VALUE + n0000 Id -- n0000 + n0000 Comment test_profile test comment + n0000 Cluster test_profile cluster01 + n0000 Profiles -- default,test_profile + +And if we delete the superseded profile attribute from +``test_profile`` we can now see the previous configuration: + +.. code-block:: console + + # wwctl profile set --comment UNDEF test_profile + Are you sure you want to modify 1 profile(s): y + + # wwctl node list -a | head -n 6 + NODE FIELD PROFILE VALUE + n0000 Id -- n0000 + n0000 Comment default This profile is automatically included for each node + n0000 Cluster test_profile cluster01 + n0000 Profiles -- default,test_profile + +This is a very useful feature for dealing with many groups of cluster +nodes and/or testing new configurations on smaller subsets of cluster +nodes. For example, you can use this method to run a different kernel +on only a subset or group of cluster nodes without changing any other +node attributes. + +Overriding Profiles +=================== + +All profile configurations can be overwritten by a node configuration +as can be seen here: + +.. code-block:: console + + # wwctl node set --comment "This value takes precedent" n0000 + Are you sure you want to modify 1 nodes(s): y + + # wwctl node list -a | head -n 6 + NODE FIELD PROFILE VALUE + n0000 Id -- n0000 + n0000 Comment SUPERSEDED This value takes precedent + n0000 Cluster test_profile cluster01 + n0000 Profiles -- default,test_profile + +How To Use Profiles Effectively +=============================== + +There are a lot of ways to use profiles to facilitate the management +of large cluster node attributes, but there is nothing inherent in the +design of Warewulf that requires use of them for anything. It is +completely reasonable to not use profiles at all to help with node +configuration attributes. + +But if you do wish to use profiles, the best way to use them is to +manage "fixed" configurations of groups of cluster nodes. For example, +if you have multiple sub-clusters in your cluster, it might be +advantageous to have a ``cluster_name`` profile which includes things +like network configurations, and/or a specific kernel, container, boot +arguments, etc. + +Node specific information, like HW/MAC addresses and IP addresses +should always be put in a node configuration rather than a profile +configuration. diff --git a/static/docs/v4.5.x/_sources/contents/provisioning.rst.txt b/static/docs/v4.5.x/_sources/contents/provisioning.rst.txt new file mode 100644 index 00000000..58a708db --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/provisioning.rst.txt @@ -0,0 +1,100 @@ +================= +Node Provisioning +================= + +Once the nodes are configured in Warewulf, they are ready to boot. + +Node Hardware Setup +=================== + +The only thing that Warewulf requires to provision is that the node is +set to PXE boot. You may need to change the boot order if there is a +local disk present and bootable. This is a configuration change you +will have to make in the BIOS of the cluster node. + +Each vendor does this differently and as a result we won't go into the +setup specifics here and if you can not find information on how to PXE +boot your nodes, please contact your hardware vendor support. + +.. note:: + + If you find that you are going to use Warewulf, or any other + cluster provisioning tool, it is very helpful to require that + hardware vendors preconfigure your cluster nodes with values of + your choosing, and ask them to provide a text file that includes + all of the HW/MAC addresses of the compute nodes in the order they + are racked (which most creditable vendors will do). You can also + ask them to certify their computing stack for the operating system + you wish to use and the provisioning system. This helps hardware + vendors to ensure their stack works with open source projects like + Warewulf, Debian, OpenSuSE, and Rocky Linux. + +The Provisioning Process +======================== + +When the cluster node boots, the following order of operations will +occur: + +#. BIOS: + #. The system BIOS will bootstrap the initialization of the + hardware + #. The network card will register its option ROM into the BIOS + #. The BIOS will run through all of its functions and finish with + boot devices + #. The boot devices are attempted in order + #. When it gets to the network boot device, PXE is run from the + firmware on the network card +#. PXE: + #. PXE will request a BOOTP/DHCP address on the network + #. The Warewulf controller's DHCP server will respond with a + network configuration and filename to try and boot + #. PXE will attempt to download the filename referred to in the + DHCP response via TFTP + #. The downloaded file will execute an iPXE stack which will reach + out to the Warewulf server for it's configuration +#. Bootstrap: + #. The Warewulf server will generate the iPXE configuration which + will include directions of what else is necessary to download + and how to boot. + #. The kernel, container image, kernel modules, and system overlay + are all downloaded over REST HTTP from the Warewulf Server + #. iPXE executes the kernel and processes the overlays to provide + a unified root file system + #. Warewulf bootstraps the initialization of cluster node's + operating system + #. File System (re)configuration + #. SELinux + #. ``wwclient`` is called as a background daemon and sleeps until network is ready + #. The Warewulf bootstrap execs the container's ``/sbin/init`` +#. Container: + #. The container now boots exactly as any operating system would + expect + + +Node status +======================== +During the whole provisioning process of your nodes, you can check their status +through the following command : + +.. code-block:: console + + # wwctl node status + NODENAME STAGE SENT LASTSEEN (s) + ================================================================================ + c001 RUNTIME_OVERLAY generic.img.gz 16 + + +For each node, there is 4 different stages : + +* **IPXE** +* **KERNEL** +* **SYSTEM_OVERLAY** +* **RUNTIME_OVERLAY** + +Those stages are directly linked to the The Provisioning Process section and are provided +by the wwclient + +Thanks to ``wwctl node status`` command, you can also check your communication between +the warewulf client and server. +Depending on your warewulf version, you should see a reset of the last seen counter every 1 minute due to the +warewulf runtime overlay update. diff --git a/static/docs/v4.5.x/_sources/contents/security.rst.txt b/static/docs/v4.5.x/_sources/contents/security.rst.txt new file mode 100644 index 00000000..a53d5dac --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/security.rst.txt @@ -0,0 +1,93 @@ +======== +Security +======== + +Historically, most HPC clusters utilize a security model that is "hard +on the exterior and soft and gushy on the interior". It is not that a +user has free roam once logged in, but rather we tend to rely on just +simple POSIX security models on the inside. For example, one of the +common practices is to completely disable SELinux on a new cluster +setup. Just kill it because it gets in the way. + +For that reason, most critical HPC clusters leverage VPNs and/or +bastion hosts with multi-factor authentication (MFA) to help secure it +on the outside. But even with MFA and secure ssh connections through a +bastion host, it is still possible for malicious users to gain access +to these systems. Security being like layers of an onion is accurate, +but on an HPC system, those layers are predominately on the outside of +the cluster, not the inside. + +Warewulf was written and designed from the ground up to go a bit +further. And while certain parallelization and high performance +library capabilities still require lowering the security threshold, +Warewulf strives to not be a blocker here. + +SELinux +======= + +The Warewulf server itself was developed with SELinux enabled in +"targeted" and "enforcing" mode and with the firewall active. + +Additionally, the provisioning process fully supports SELinux by +default. In previous versions you had to enable a switch to support +SELinux, but in Warewulf v4 and above, it is always enabled, but you +do have to make some configuration changes. + +#. The first thing to do is to change the provision "Root" option. By + default this is ``initramfs`` which means, take whatever file + system the kernel hands us. By default this is a ``ramfs`` type + file system (however this may not always be the case) and this + format does not support extended file attributes which are required + for SELinux. Instead you must configure Warewulf to use ``tmpfs`` + for the provisioning file system. That change is made like: ``$ + sudo wwctl profile set --root tmpfs default``. + +#. That is all you have to do to ensure that Warewulf will probably + support SELinux. Once that is done, you just need to enable SELinux + in ``/etc/sysconfig/selinux`` and install the appropriate profiles + into the container. + +Provisioning Security +===================== + +Provisioning in generally is known to be rather "insecure" because +when a user lands on a compute node, there is generally nothing +stopping them from spoofing a provision request and downloading the +provisioned raw materials for inspection. + +In Warewulf there are ways multiple to secure the provisioning process: + +#. The provisioning connections and transfers are not secure due to + not being able to manage a secure root of trust through a PXE + process. The best way to secure the provisioning process is to + enact a vLAN used specifically for provisioning. Warewulf supports + this but you must consult your switch documentation and features to + implement a default vLAN for provisioning and ensure that the + runtime operating system is configured for a different tagged vLAN + once booted. + +#. Warewulf will leverage hardware "asset tags" which almost all + vendors support. It is a configurable string that is configured in + firmware and accessible only via root or physical access. During + provisioning (as well as post provisioning via ``wwclient``) + Warewulf, can use the asset tag as a secure token. If you have + setup your hardware with an asset tag, you simply need to tell + Warewulf what that asset tag is. When the asset tag is defined in + Warewulf (``wwctl node set --assetkey "..."``), it will only + provision and communicate with requests from that system matching + that asset tag. + +#. When the nodes are booted via `shim` and `grub` Secure Boot can be + enabled. This means that the nodes only boot the kernel which is + provided by the distributor and also custom complied modules can't + be loaded. + +Summary +======= + +Warewulf does not limit the security posture of a cluster at all, and +perhaps it increases it as not all provisioners work with firewalls +and SELinux enabled and enforcing. But even with that, cluster +security is always up to the system manager and organizational +policies. Our job is just to ensure that we don't limit those policies +in any way. diff --git a/static/docs/v4.5.x/_sources/contents/setup.rst.txt b/static/docs/v4.5.x/_sources/contents/setup.rst.txt new file mode 100644 index 00000000..1c11f03d --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/setup.rst.txt @@ -0,0 +1,184 @@ +==================== +Control Server Setup +==================== + +Operating System Installation +============================= + +Warewulf has almost no predetermined or required configurations aside +from a base architecture networking layout. Install your Linux +distribution of choice as you would like, but do pay attention to the +cluster's private network configuration. + +Network +======= + +A clustered resource depends on a private management network. This +network can be either persistent (it is always "up" even after +provisioning) to temporary which might only be used for provisioning +and/or out of band system control and management e.g. IPMI). + +It is important for this management network to be private to the +compute resource because Warewulf requires network services on that +network which may conflict with services on the production/public +network (e.g. DHCP). It is also important from a security perspective +as the management network for typical HPC systems have an implied +trust level associated with it and generally there is no firewalling +or network monitoring occurring on these networks. + +Usually, the control node is "dual homed" which means it has at least +two interface cards, one connected to the private cluster network and +one dedicated to the public network (as the figure above +demonstrates). + +.. note:: + + It is possible to omit the public network interface with a reverse + NAT. Warewulf can operate in this configuration but it extends + beyond the scope of this documentation. + +Many clusters have more than one private network. This is common for +performance critical HPC clusters that implement a high speed and low +latency network like InfiniBand. In this case, this network is used +for high speed data transfers for inter-process communication between +compute nodes and file system IO. + +Warewulf will need to be configured to use the private cluster +management network. Warewulf will use this network for booting the +nodes over PXE. There are three network protocols used to accomplish +this DHCP/BOOT, TFTP, and HTTP on port ``9873``. Warewulf will use the +operating system's provided version of DHCP (ISC-DHCP) and TFTP for +the PXE bootstrap to iPXE, and then iPXE will use Warewulf's internal +HTTP services to transfer the larger files for provisioning. + +Addressing +========== + +The addressing scheme of your private cluster network is 100% up to +the system integrator, but for large clusters, many organizations like +to organize the address allocations. Below is a recommended IP +addressing scheme which we will use for the rest of this document. + +* ``10.0.0.1``: Private network address IP +* ``255.255.252.0``: Private network subnet mask (``10.0.0.0/22``) + +Here is an example of how the cluster's address can be divided for a +255 node cluster: + +* ``10.0.0.1 - 10.0.0.255``: Cluster infrastructure including this + host, schedulers, file systems, routers, switches, etc. +* ``10.0.1.1 - 10.0.1.255``: DHCP range for booting nodes +* ``10.0.2.1 - 10.0.2.255``: Static node addresses +* ``10.0.3.1 - 10.0.3.255``: IPMI and/or out of band addresses for the + compute nodes + +Multiple networks +================= + +It is possible to configure several networks not just for the nodes but also for the management of ``dhcpd`` and ``tftp``. +There are two ways to achive this: + +1. Add the networks to the templates of ``dhcpd`` and/or the ``dnsmasq`` template directly. +2. Add the networks to a dummy node and change the templates of ``dhcp`` and ``dnsmasq`` accordingly. + +As the first solution is trivial only the second way is described in the following lines. + +As first the first step, add the dummy node. + +.. code-block:: shell + + wwctl node add deliverynet + +Now you will have to add the delivery networks to this node. + +.. code-block:: shell + + wwctl node set \ + --ipaddr 10.0.20.250 \ + --netmask 255.255.255.0 \ + --netname deliver1 \ + --nettagadd network=10.0.20.0,dynstart=10.10.20.10,dynend=10.10.20.50 \ + deliverynet + + wwctl node set \ + --ipaddr 10.0.30.250 \ + --netmask 255.255.255.0 \ + --netname deliver2 \ + --nettagadd network=10.0.30.0,dynstart=10.10.30.10,dynend=10.10.30.50 \ + deliverynet + +The ip address is used as the network address of host in the delivery network and an additional tags is used for definition of the network itself and the dynamic dhcp range. +You can check the result with ``wwctl node list``. + +.. code-block:: console + + # wwctl node list -a deliverynet + NODE FIELD PROFILE VALUE + deliverynet Id -- deliverynet + deliverynet Comment default This profile is automatically included for each node + deliverynet ContainerName default leap15.5 + deliverynet Ipxe -- (default) + deliverynet RuntimeOverlay -- (generic) + deliverynet SystemOverlay -- (wwinit) + deliverynet Root -- (initramfs) + deliverynet Init -- (/sbin/init) + deliverynet Kernel.Args -- (quiet crashkernel=no vga=791 net.naming-scheme=v238) + deliverynet Profiles -- default + deliverynet PrimaryNetDev -- (deliver1) + deliverynet NetDevs[deliver2].Type -- (ethernet) + deliverynet NetDevs[deliver2].OnBoot -- (true) + deliverynet NetDevs[deliver2].Ipaddr -- 10.0.30.250 + deliverynet NetDevs[deliver2].Netmask -- 255.255.255.0 + deliverynet NetDevs[deliver2].Tags[dynend] -- 10.10.30.50 + deliverynet NetDevs[deliver2].Tags[dynstart] -- 10.10.30.10 + deliverynet NetDevs[deliver2].Tags[network] -- 10.0.30.0 + deliverynet NetDevs[deliver1].Type -- (ethernet) + deliverynet NetDevs[deliver1].OnBoot -- (true) + deliverynet NetDevs[deliver1].Ipaddr -- 10.0.20.250 + deliverynet NetDevs[deliver1].Netmask -- 255.255.255.0 + deliverynet NetDevs[deliver1].Primary -- (true) + deliverynet NetDevs[deliver1].Tags[network] -- 10.0.20.0 + deliverynet NetDevs[deliver1].Tags[dynend] -- 10.10.20.50 + deliverynet NetDevs[deliver1].Tags[dynstart] -- 10.10.20.10 + +Now the templates of ``dhcpd`` and/or ``dnsmasq`` must be modified. +You can edit the configuration files. + +.. code-block:: shell + + wwctl overlay edit host etc/dhcpd.conf.ww + wwctl overlay edit host etc/dnsmasq.d/ww4-hosts.ww + +For the ``dhcp`` template you should add following lines + +.. code-block:: + + {{/* multiple networks */}} + {{- range $node := $.AllNodes}} + {{- if eq $node.Id.Get "deliverynet" }} + {{- range $netname, $netdev := $node.NetDevs}} + # network {{ $netname }} + subnet {{$netdev.Tags.network.Get}} netmask {{$netdev.Netmask.Get}} { + max-lease-time 120; + range {{$netdev.Tags.dynstart.Get}} {{$netdev.Tags.dynend.Get}}; + next-server {{$netdev.Ipaddr.Get}}; + } + {{- end }} + {{- end }} + {{- end }} + +and for the ``dnsmasq`` the following lines should be added + +.. code-block:: + + {{/* multiple networks */}} + {{- range $node := $.AllNodes}} + {{- if eq $node.Id.Get "deliverynet" }} + {{- range $netname, $netdev := $node.NetDevs}} + # network {{ $netname }} + dhcp-range={{$netdev.Tags.dynstart.Get}},{{$netdev.Tags.dynend.Get}},{{$netdev.Netmask.Get}},6h + {{- end }} + {{- end }} + {{- end }} + +Note that the ``{{- if eq $node.Id.Get "deliverynet" }}`` is used to identify the dummy host which carries the network information. diff --git a/static/docs/v4.5.x/_sources/contents/stateless.rst.txt b/static/docs/v4.5.x/_sources/contents/stateless.rst.txt new file mode 100644 index 00000000..28b19307 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/stateless.rst.txt @@ -0,0 +1,85 @@ +====================== +Stateless Provisioning +====================== + +Why is Provisioning Important +============================= + +Clusters are pools of servers bundled together to do a particular job +or set of jobs. While there are a number of different use cases for +clustering today, Warewulf was originally designed out of necessity. + +Back in 2000, when Linux clustering was growing up for HPC, the issues +of scale became apparent. Of course in HPC, there are many scalability +factors which needed to be overcome as we continued to scale up +clusters. Pretty early on was the "administrative scaling" which is +the factor that full time systems administrators could only maintain +so many servers. While homogeneous configurations were able to help +that, we still had the problem that every installed server became a +point of administration, version drift, and debugging. The larger the +cluster, the harder this problem was to solve. + +Warewulf was created to help with exactly this. + +Provisioning Overview +===================== + +Provisioning in this definition is the process of putting an operating +system onto a system. There are many ways to provision operating +system images, from copying hard drives, to scripted installs, to +automated installs. There are many valuable tools to facilitate this +and they all helped to solve this problem. + +In a cluster environment, this means one could group all of the nodes +together, to be installed in bulk. Previous to cluster provisioning +system administrators would go around to each cluster node, and +install it from scratch, with an ISO or USB thumb drive. This +obviously is not scalable. But being able to automatically install +hundreds or thousands of computers in parallel and automate the +management of these systems completely changed the paradigm. + +There were several cluster provision and management toolkits already +available when Warewulf was created and while these tools absolutely +helped, there was even more optimization to be had. + +Why Stateless Provisioning +========================== + +The next step past automated installs is to just skip the installation +completely; boot directly into the runtime operating system without +ever doing an installation. + +This is Warewulf. + +Stateless provisioning is realizing you never have to install another +compute node. Think of it like booting a LiveOS or LiveISO on nodes +over the network. This means that no node individually is a point of +system administration, but rather the entire cluster is administrated +as a single unit. + +If all cluster nodes are booting the same OS image (or set of OS +images), then any individual nodes that have problems is +hardware. Debugging software and doing system administration in single +points within a cluster is not needed. There is no version drift, +because it is not possible for nodes to fall out of sync. Every reboot +makes it exactly the same as its neighbors. + +Warewulf provisions the operating system by default to system +memory. There is no need for hard drives with Warewulf. + +Previous versions of Warewulf had the ability to write the operating +system to hard disk as well as do hybrid provisioning (the core +operating system in memory, other pieces overlaid over NFS) but these +have been obsoleted in Warewulf v4 as there are easier ways to +accomplish the same thing (e.g. use of swap space). + +.. note:: + + If you wish to provision to the hard drive, we might add that + feature back based on user requests but in the mean time, you may + wish to look at an automated or scripted installation platform + instead of a cluster provisioning system. + +In our experience, the Warewulf provisioning model is by far the most +advantageous, simplest, and most flexible and scalable cluster +provisioning platform available. diff --git a/static/docs/v4.5.x/_sources/contents/templating.rst.txt b/static/docs/v4.5.x/_sources/contents/templating.rst.txt new file mode 100644 index 00000000..11543834 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/templating.rst.txt @@ -0,0 +1,226 @@ +========== +Templating +========== + +Warewulf uses the ``text/template`` engine to convert dynamic content +into static content and auto-populate files with the appropriate data +on demand. + +In Warewulf, you can find templates both for the provisioning services +(e.g. ``/etc/warewulf/ipxe/``, ``/etc/warewulf/dhcp/``, and +``/etc/warewulf/hosts.tmpl``) as well as within the runtime and system +overlays. + +(more documentation coming soon) + +Examples +======== + +Comment +------- + +.. code-block:: + + {{ /* This comment won't show up in file, but an empty line /* }} + {{ /* No empty line, line break removed at end of this line /* -}} + {{- /* No empty line, line break removed at front of this line /* }} + +Range +----- + +iterate over elements of an array + +.. code-block:: + + {{ range $devname, $netdev := .NetDevs }} + # netdev = {{ $netdev.Hwaddr }} + {{ end }} + +Increment Variable In Loop +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +iterate over elements of an array and increment ``i`` each loop cycle + +.. code-block:: + + {{ $i := 0 }} + {{ range $devname, $netdev := .NetDevs }} + # netdev{{$i}} = {{ $netdev.Hwaddr }} + {{ $i = inc $i }} + {{ end }} + +Decrement +^^^^^^^^^ + +iterate over elements of an array and decrement ``i`` each loop cycle + +.. code-block:: + + {{ $i := 10 }} + {{ range $devname, $netdev := .NetDevs }} + # netdev{{$i}} = {{ $netdev.Hwaddr }} + {{ $i = dec $i }} + {{ end }} + +Access Tag +---------- + +Acces the value of an individual tag ``foo`` + +.. code-block:: + + foo: {{ index .Tags "foo" }} + {{ if eq (index .Tags "foo") "baar" -}} + foo: {{ index .Tags "foo" }} + {{ end -}} + +Create Multiple Files +--------------------- + +The following template will create a file called +``ifcfg-NETWORKNAME.xml`` for every network present on the node + +.. code-block:: + + {{- $host := .BuildHost }} + {{- $time := .BuildTime }} + {{- $source := .BuildSource }} + {{range $devname, $netdev := .NetDevs -}} + {{- $filename := print "ifcfg-" $devname ".xml" }} + {{- file $filename }} + + + {{$netdev.Device}} + {{ if $netdev.Type -}} + {{ $netdev.Type }} + {{ end -}} + + boot + + + + + true + true + + +
+ {{$netdev.IpCIDR}} +
+ {{ if $netdev.Gateway -}} + + + {{$netdev.Gateway}} + + + {{ end -}} +
+ + true + prefer-public + false + + {{ if $netdev.Ipaddr6 -}} + +
+ {{ $netdev.Ipaddr6 }} +
+
+ {{ end -}} +
+ {{ end -}} + +Special Commands +---------------- + +Include +^^^^^^^ + +A file from the host can be include with following template + +.. code-block:: + + {{ Include file }} + +IncludeFrom +^^^^^^^^^^^ + +With following snippet a file from a given container can be included + +.. code-block:: + + {{ IncludeFrom container file }} + +IncludeBlock +^^^^^^^^^^^^ + +Includes a file up to the line where a abort string is found. This is +useful, e.g., for the hosts file, which can have local modifications +which are not controlled by warewulf. For this example the abort +string is "# Do not edit after this line" + +.. code-block:: + + {{ IncludeBlock "/etc/hosts" "# Do not edit after this line" }} + # This block is autogenerated by warewulf + # Host: {{.BuildHost}} + # Time: {{.BuildTime}} + # Source: {{.BuildSource}} + + + # Warewulf Server + {{$.Ipaddr}} warewulf {{$.BuildHost}} + + {{- range $node := $.AllNodes}} {{/* for each node */}} + # Entry for {{$node.Id.Get}} + {{- range $devname, $netdev := $node.NetDevs}} {{/* for each network device on the node */}} + {{- if $netdev.Ipaddr.Defined}} {{/* if we have an ip address on this network device */}} + {{- /* emit the node name as hostname if this is the primary */}} + {{$netdev.Ipaddr.Get}} {{$node.Id.Get}}-{{$devname}} + {{- if $netdev.Device.Defined}} {{$node.Id.Get}}-{{$netdev.Device.Get}}{{end}} + {{- if $netdev.Primary.GetB}} {{$node.Id.Get}}{{end}} + {{- end}} {{/* end if ip */}} + {{- end}} {{/* end for each network device */}} + {{- end}} {{/* end for each node */}} + +Abort +^^^^^ +If ``{{ abort }}`` is found in a template, the resulting file isn't written. + +Nobackup +^^^^^^^^ + +If a file exists on the target, a backup file is written with the +suffix ``.wwbackup``. This only happens for the ``host`` overlay, as +e.g. the ``/etc/hosts`` exists on the host. If this is not the +intended behavior, the ``{{ nobackup }}`` flag can be added to a +template. + +Split +^^^^^ + +A given string can be split into substrings. + +.. code-block:: + + {{ $x := "a:b:c" -}} + {{ $y := (split $x ":") -}} + {{ range $y }} {{.}} {{ end }} + + +Node specific files +------------------- + +Sometimes there is the need to have specific files for every node +which can't be generated by a template. You can include these files +with following template: + +.. code-block:: + + {{- $filename := print "/root/" .Id "-payload" }} + {{ Include $filename }} diff --git a/static/docs/v4.5.x/_sources/contents/wwctl.rst.txt b/static/docs/v4.5.x/_sources/contents/wwctl.rst.txt new file mode 100644 index 00000000..dad05cb8 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contents/wwctl.rst.txt @@ -0,0 +1,33 @@ +============================ +Controlling Warewulf (wwctl) +============================ + +Warewulf's command-line interface is based primarily around the +``wwctl`` command. This command has sub-commands for each major +component of Warewulf's functionality. + +* ``configure`` configures system services that Warewulf depends on +* ``container`` configures containers (node images) +* ``kernel`` configures override kernels +* ``node`` manages nodes in the cluster +* ``profiles`` defines configuration which can be applied to multiple + nodes +* ``overlays`` manages nodes +* ``power`` turns nodes on and off +* ``ssh`` provides basic parallel ssh functionality + +All of these subcommands (and their respective sub-subcommands) have +built-in help with either ``wwctl help`` or ``--help``. + +Hostlists +========= + +Many of the commands (e.g., ``wwctl node list`` support a "hostlist" +syntax for referring to multiple nodes at once. Hostlist expressions +support both ranges and comma-separated numerical lists. + +For example: + +* ``node[1-2]`` expands to ``node1 node2`` +* ``node[1,3]`` expands to ``node1 node3`` +* ``node[1,5-6]`` expands to ``node1 node5 node6`` diff --git a/static/docs/v4.5.x/_sources/contributing/contributing.rst.txt b/static/docs/v4.5.x/_sources/contributing/contributing.rst.txt new file mode 100644 index 00000000..c59aa183 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/contributing.rst.txt @@ -0,0 +1,156 @@ +============ +Contributing +============ + +Warewulf is an open source project, meaning we have the challenge of +limited resources. We are grateful for any support that you can +offer. Helping other users, raising issues, helping write +documentation, or contributing code are all ways to help! + +Join the community +================== + +This is a huge endeavor, and your help would be greatly appreciated! +Post to online communities about Warewulf, and request that your +distribution vendor, service provider, and system administrators +include Warewulf for you! + +Warewulf on Slack +----------------- + +Many members of the Warewulf community, including developers, communicate via Slack. +It's a great place to get help with an issue or talk about how you're using Warewulf. + +`Join the Warewulf Slack Workspace! +`_ + +Raise an Issue +============== + +For general bugs/issues, you can open an issue `at the GitHub repo +`_. + +Contribute to the code +====================== + +We use the traditional `GitHub Flow +`_ to develop. This means +that you fork the main repo, create a new branch to make changes, and +submit a pull request (PR) to the master branch. + +Check out our official `CONTRIBUTING.md +`_ +document, which also includes a `code of conduct +`_. + + +Step 1. Fork the repo +--------------------- + +To contribute to Warewulf, you should obtain a GitHub account and fork +the `Warewulf `_ repository. Once +forked, clone your fork of the repo to your computer. (Obviously, you +should replace ``your-username`` with your GitHub username.) + +.. code-block:: bash + + git clone https://github.com/your-username/warewulf.git + cd warewulf + +Step 2. Checkout a new branch +----------------------------- + +`Branches `_ are a way +of isolating your features from the main branch. Given that we’ve just +cloned the repo, we will probably want to make a new branch from +master in which to work on our new feature. Lets call that branch +``new-feature``: + +.. code-block:: bash + + git checkout master + git checkout -b new-feature + +.. note:: + + You can always check which branch you are in by running ``git + branch``. + +Step 3. Make your changes +------------------------- + +On your new branch, go nuts! Make changes, test them, and when you are +happy commit the changes to the branch: + +.. code-block:: bash + + git add file-changed1 file-changed2... + git commit -m "what changed?" + +This commit message is important - it should describe exactly the +changes that you have made. Good commit messages read like so: + +.. code-block:: bash + + git commit -m "changed function getConfig in functions.go to output csv to fix #2" + git commit -m "updated docs about shell to close #10" + +The tags ``close #10`` and ``fix #2`` are referencing issues that are +posted on the upstream repo where you will direct your pull +request. When your PR is merged into the master branch, these messages +will automatically close the issues, and further, they will link your +commits directly to the issues they intend to fix. This will help +future maintainers understand your contribution, or (hopefully not) +revert the code back to a previous version if necessary. + +Step 4. Push your branch to your fork +------------------------------------- + +When you are done with your commits, you should push your branch to +your fork (and you can also continuously push commits here as you +work): + +.. code-block:: bash + + git push origin new-feature + +Note that you should always check the status of your branches to see +what has been pushed (or not): + +.. code-block:: bash + + git status + +Step 5. Submit a Pull Request +----------------------------- + +Once you have pushed your branch, then you can go to your fork (in the +web GUI on GitHub) and `submit a Pull Request +`_. Regardless +of the name of your branch, your PR should be submitted to the +``main`` branch. Submitting your PR will open a conversation thread +for the maintainers of Warewulf to discuss your contribution. At this +time, the continuous integration that is linked with the code base +will also be executed. If there is an issue, or if the maintainers +suggest changes, you can continue to push commits to your branch and +they will update the Pull Request. + +Step 6. Keep your branch in sync +-------------------------------- + +Cloning the repo will create an exact copy of the Warewulf repository +at that moment. As you work, your branch may become out of date as +others merge changesinto the upstream master. In the event that you +need to update a branch, you will need to follow the next steps: + +.. code-block:: bash + + # add a new remote named "upstream" + git remote add upstream https://github.com/warewulf/warewulf.git + # or another branch to be updated + git checkout master + git pull upstream master + # to update your fork + git push origin master + git checkout new-feature + git merge master diff --git a/static/docs/v4.5.x/_sources/contributing/debugging.rst.txt b/static/docs/v4.5.x/_sources/contributing/debugging.rst.txt new file mode 100644 index 00000000..8d66d36d --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/debugging.rst.txt @@ -0,0 +1,310 @@ +========= +Debugging +========= + +Whether developing a new feature or fixing a bug, using the automated +test suite together with a debugger is a potent combination. This +guide here can't substitute for full documentation on a given +debugger; but it might help you get started debugging Warewulf. + +Validating the code with vet +============================ + +The Warewulf ``Makefile`` includes a ``vet`` target which runs ``go +vet`` on the full codebase. + +.. code-block:: console + + $ make vet + + +Running the full test suite +=========================== + +The Warewulf ``Makefile`` includes a ``test`` target which runs the +full test suite. + +.. code-block:: console + + $ make test + + +Using delve +=========== + +If you have a failing test but you're having trouble tracking down +why, try using a debugger to step through the test. These instructions +use delve. + + +Installing delve +---------------- + +You can install delve as a regular user directly with Go. + +.. code-block:: console + + $ go install github.com/go-delve/delve/cmd/dlv@latest + +The ``dlv`` binary will be installed by default at +``$HOME/go/bin/dlv``. You can, of course, add ``$HOME/go/bin`` to your +path if you prefer. + +.. code-block:: console + + $ PATH=$HOME/go/bin:$PATH + + +Running delve against a specific test +------------------------------------- + +You can use delve to specifically run the test suite and, even more +specifically, a single failing test. In this example delve is +instructed to run the tests for Warewulf's ``node`` package, and +specifically the ``Test_GetAllNodeInfoDefaults`` test. + +.. code-block:: console + + $ dlv test github.com/warewulf/warewulf/internal/pkg/node -- -test.v -test.run Test_GetAllNodeInfoDefaults + Type 'help' for list of commands. + (dlv) break node.Test_GetAllNodeInfoDefaults + Breakpoint 1 set at 0x26c0d0 for github.com/warewulf/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 + +Setting a breakpoint at ``node.Test_GetAllNodeInfoDefaults`` pauses +execution once the test starts, and allows us to ``continue`` through +all the setup prior to that point. + +.. code-block:: console + + (dlv) continue + === RUN Test_GetAllNodeInfoDefaults + > github.com/warewulf/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 (hits goroutine(35):1 total:1) (PC: 0x26c0d0) + 46: assert.Contains(t, nodeYaml.Nodes, "test_node") + 47: assert.Equal(t, "A single node", nodeYaml.Nodes["test_node"].Comment) + 48: } + 49: + 50: + => 51: func Test_GetAllNodeInfoDefaults(t *testing.T) { + 52: file, writeErr := writeTestConfigFile(` + 53: nodes: + 54: test_node: {}`) + 55: if file != nil { + 56: defer os.Remove(file.Name()) + +Helpful commands from here include + +``next`` + + Execute the current line (marked by ``=>``) and proceed to the next + line. + +``step`` + + Execute the current line (marked by ``=>``) and proceed to the next + line, potentially moving into a function call. + +``list`` + + Display a contextual Go code listing, marking the next instruction. + +``locals`` + + Display all local variables in the current scope. + +``print`` + + Display (in detail) the value of a single variable from the current + scope. + +Read about other commands available within delve using the ``help`` +command. + + +Example debugging session +------------------------- + +.. code-block:: console + + $ ~/go/bin/dlv test github.com/warewulf/warewulf/internal/pkg/node -- -test.v -test.run Test_GetAllNodeInfoDefaults + Type 'help' for list of commands. + + (dlv) break node.Test_GetAllNodeInfoDefaults + Breakpoint 1 set at 0x26c0d0 for github.com/warewulf/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 + + (dlv) break nodeinfo.go:417 + Breakpoint 2 set at 0x267f18 for github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:417 + + (dlv) continue + === RUN Test_GetAllNodeInfoDefaults + > github.com/warewulf/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 (hits goroutine(19):1 total:1) (PC: 0x26c0d0) + 46: assert.Contains(t, nodeYaml.Nodes, "test_node") + 47: assert.Equal(t, "A single node", nodeYaml.Nodes["test_node"].Comment) + 48: } + 49: + 50: + => 51: func Test_GetAllNodeInfoDefaults(t *testing.T) { + 52: file, writeErr := writeTestConfigFile(` + 53: nodes: + 54: test_node: {}`) + 55: if file != nil { + 56: defer os.Remove(file.Name()) + + (dlv) continue + WARN : Error reading UNDEF/warewulf/defaults.conf: open UNDEF/warewulf/defaults.conf: no such file or directory + > github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:417 (hits goroutine(19):1 total:1) (PC: 0x267f18) + 412: defaultNodeConf.NetDevs = nil + 413: nodeInfo.SetDefFrom(defaultNodeConf) + 414: } + 415: + 416: // Load normal attributes + => 417: if nodeConf != nil { + 418: // If no profiles are included, automatically include the + 419: // default profile. + 420: if len(nodeConf.Profiles) == 0 { + 421: nodeInfo.Profiles.SetSlice([]string{"default"}) + 422: } else { + + (dlv) next + > github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:420 (PC: 0x267f24) + 415: + 416: // Load normal attributes + 417: if nodeConf != nil { + 418: // If no profiles are included, automatically include the + 419: // default profile. + => 420: if len(nodeConf.Profiles) == 0 { + 421: nodeInfo.Profiles.SetSlice([]string{"default"}) + 422: } else { + 423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles) + 424: } + 425: + + (dlv) next + > github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:421 (PC: 0x267f3c) + 416: // Load normal attributes + 417: if nodeConf != nil { + 418: // If no profiles are included, automatically include the + 419: // default profile. + 420: if len(nodeConf.Profiles) == 0 { + => 421: nodeInfo.Profiles.SetSlice([]string{"default"}) + 422: } else { + 423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles) + 424: } + 425: + 426: nodeInfo.SetFrom(nodeConf) + + (dlv) next + > github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:426 (PC: 0x267fec) + 421: nodeInfo.Profiles.SetSlice([]string{"default"}) + 422: } else { + 423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles) + 424: } + 425: + => 426: nodeInfo.SetFrom(nodeConf) + 427: } + 428: + 429: // Load default attributes for each NetDev + 430: if defaultNetDevConf != nil { + 431: for _, netdev := range nodeInfo.NetDevs { + + (dlv) next + > github.com/warewulf/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:430 (PC: 0x268000) + 425: + 426: nodeInfo.SetFrom(nodeConf) + 427: } + 428: + 429: // Load default attributes for each NetDev + => 430: if defaultNetDevConf != nil { + 431: for _, netdev := range nodeInfo.NetDevs { + 432: netdev.SetDefFrom(defaultNetDevConf) + 433: } + 434: } + 435: + + (dlv) print nodeInfo + github.com/warewulf/warewulf/internal/pkg/node.NodeInfo { + Id: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 1, cap: 1, [ + "test_node", + ], + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + Comment: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + ClusterName: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + ContainerName: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + Ipxe: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, ["default"],}, + RuntimeOverlay: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, ["generic"],}, + SystemOverlay: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, ["wwinit"],}, + Root: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, [ + "initramfs", + ],}, + Discoverable: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + Init: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, [ + "/sbin/init", + ],}, + AssetKey: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + Kernel: *github.com/warewulf/warewulf/internal/pkg/node.KernelEntry { + Override: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x4000158370), + Args: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001583c8),}, + Ipmi: *github.com/warewulf/warewulf/internal/pkg/node.IpmiEntry { + Ipaddr: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6600), + Netmask: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6658), + Port: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b66b0), + Gateway: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6708), + UserName: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6760), + Password: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b67b8), + Interface: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6810), + Write: (*"github.com/warewulf/warewulf/internal/pkg/node.Entry")(0x40001b6868), + Tags: map[string]*github.com/warewulf/warewulf/internal/pkg/node.Entry [],}, + Profiles: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 1, cap: 1, ["default"], + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 1, cap: 1, ["default"],}, + PrimaryNetDev: github.com/warewulf/warewulf/internal/pkg/node.Entry { + value: []string len: 0, cap: 0, nil, + altvalue: []string len: 0, cap: 0, nil, + from: "", + def: []string len: 0, cap: 0, nil,}, + NetDevs: map[string]*github.com/warewulf/warewulf/internal/pkg/node.NetDevEntry [], + Tags: map[string]*github.com/warewulf/warewulf/internal/pkg/node.Entry [],} diff --git a/static/docs/v4.5.x/_sources/contributing/development-environment-kvm.rst.txt b/static/docs/v4.5.x/_sources/contributing/development-environment-kvm.rst.txt new file mode 100644 index 00000000..c35ce668 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/development-environment-kvm.rst.txt @@ -0,0 +1,128 @@ +============================= +Development Environment (KVM) +============================= + +Create CentOS 7 development virtual machine under KVM +===================================================== + +.. code-block:: bash + + # KVM is running on server called master1 which is not my desktop + ssh -X master1 + + # On master1 server + wget -P /global/downloads/centos http://mirror.mobap.edu/centos/7.8.2003/isos/x86_64/CentOS-7-x86_64-Everything-2003.iso + + qemu-img create -o preallocation=metadata -f qcow2 /global/images/centos-7.qcow2 32G + + # install wwdev Centos 7 development VM + sudo virt-install --virt-type kvm --name centos7-wwdev --ram 8192 \ + --disk /global/images/centos-7.qcow2,format=qcow2 \ + --network network=default \ + --graphics vnc,listen=0.0.0.0 --noautoconsole \ + --os-type=linux --os-variant=rhel7.0 \ + --location=/global/downloads/centos/CentOS-7-x86_64-Everything-2003.iso + + # Complete installation using virt-manager + + # To start virt-manager on non-local server + ssh -X master1 + + sudo -E virt-manager + + # Login to VM and install @development group and go language + ssh root@wwdev + + # Disable selinux by modifying /etc/sysconfig/selinux + vi /etc/sysconfig/selinux + + SELINUX=disabled + + # disable firewall + systemctl stop firewalld + systemctl disable firewalld + +Turn off default network dhcp on server master1 +=============================================== + +.. code-block:: bash + + # shutdown all VMs + sudo virsh net-destroy default + + sudo virsh net-edit default + + # remove dhcp lines from XML + + sudo virsh net-start default + +Build and install Warewulf on wwdev +=================================== + +.. code-block:: + + ssh wwdev + + # Fedora prerequisites + sudo dnf -y install tftp-server tftp + sudo dnf -y install dhcp + sudo dnf -y install ipmitool + sudo dnf install singularity + sudo dnf install gpgme-devel + sudo dnf install libassuan.x86_64 libassuan-devel.x86_64 + sudo dnf golang + sudo dnf nfs-utils + + # Centos prerequisites + sudo yum -y install tftp-server tftp + sudo yum -y install dhcp + sudo yum -y install ipmitool + sudo yum install http://repo.ctrliq.com/packages/rhel7/ctrl-release.rpm + sudo yum install singularityplus + sudo yum install gpgme-devel + sudo yum install libassuan.x86_64 libassuan-devel.x86_64 + sudo yum install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm + sudo yum install golang + sudo yum install nfs-utils + + # Install Warewulf and dependencies + git clone https://github.com/warewulf/warewulf.git + cd warewulf + + make all + sudo make install + + # Configure the controller + Edit the file /etc/warewulf/warewulf.conf and ensure that you've ser the approprite configuration parameters + + # Configure system service automatically + sudo wwctl configure dhcp # Create the default dhcpd.conf file and start/enable service + sudo wwctl configure tftp # Install the base tftp/PXE boot files and start/enable service + sudo wwctl configure nfs # Configure the exports and create an fstab in the default system overlay + sudo wwctl configure ssh # Build the basic ssh keys to be included by the default system overlay + + # Pull and build the VNFS container and kernel + sudo wwctl container import docker://ghcr.io/warewulf/warewulf-centos:7 centos-7 --setdefault + sudo wwctl kernel import build $(uname -r) --setdefault + + # Set up the default node profile + sudo wwctl profile set default -K $(uname -r) -C centos-7 + sudo wwctl profile set default --netdev eth0 -M WW_server_subnet_mask -G WW_server_ip + sudo wwctl profile list + + # Add a node and build node specific overlays + sudo wwctl node add n0000.cluster --netdev eth0 -I n0000_ip --discoverable + sudo wwctl node list -a n0000 + + # Review Warewulf overlays + sudo wwctl overlay list -l + sudo wwctl overlay list -ls + sudo wwctl overlay edit default /etc/hello_world.ww + sudo wwctl overlay build -a + + # Start the Warewulf daemon + sudo wwctl ready + sudo wwctl server start + sudo wwctl server status + +Boot your node and watch the bash and the output of the Warewulfd process diff --git a/static/docs/v4.5.x/_sources/contributing/development-environment-vagrant.rst.txt b/static/docs/v4.5.x/_sources/contributing/development-environment-vagrant.rst.txt new file mode 100644 index 00000000..4a26a31b --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/development-environment-vagrant.rst.txt @@ -0,0 +1,276 @@ +================================= +Development Environment (Vagrant) +================================= + +Create Rocky Linux 9 virtual machine for Warewulf testbed using Vagrant + + +Host system requirements +======================== + +#. CPU supports H/W virtualization. +#. KVM kernel module available and loaded. + + +CPU H/W Virtualization support +------------------------------ + +Check CPU virtualization capability using following command. +If your system has Intel CPU, you will see :code:`Intel VT` here, and if your system has AMD CPU, you will see :code:`AMD-V` here. + +.. code-block:: bash + + lscpu | grep Virtualization + Virtualization: AMD-V + Virtualization type: full + + +KVM kernel module +----------------- + +.. code-block:: bash + + lsmod | grep kvm + ccp 118784 1 kvm_amd + kvm 1105920 1 kvm_amd + irqbypass 16384 1 kvm + + +Setup development environment on Rocky Linux 9 +============================================== + +Install QEMU, libvirt +--------------------- + +.. code-block:: bash + + # Install packages + sudo dnf install -y libvirt qemu-kvm \ + libguestfs virtio-win guestfs-tools libguestfs-inspect-icons virt-win-reg \ + virt-install virt-top + + # Enable and start libvirtd + sudo systemctl enable --now libvirtd + + # Add user to libvirt group + sudo usermod -aG libvirt rocky + + +Install Cockpit (Optional) +-------------------------- + +.. code-block:: bash + + # Install packages + sudo dnf install -y cockpit cockpit-machines + + # Enable and start cockpit (http://localhost:9090) + sudo systemctl enable --now cockpit.socket + + +Install Vagrant, vagrant-libvirt plug-in and vagrant-reload plug-in +------------------------------------------------------------------- + +.. code-block:: bash + + sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo + sudo dnf install -y vagrant + + sudo dnf group install -y "Development tools" + sudo dnf config-manager --set-enabled crb + sudo dnf install -y libvirt-devel + + vagrant plugin install vagrant-libvirt + vagrant plugin install vagrant-reload + + +Vagrant box and Vagrantfile for Warewulf sandbox +================================================ + +Create Rocky Linux 9.2 vagrant box +---------------------------------- + +.. code-block:: bash + + cat << 'EOF' > box-metadata.json + { + "name" : "rockylinux/9", + "description" : "Rocky Linux 9 2.0.0", + "versions" : [ + { + "version" : "2.0.0-20230513.0", + "providers" : [ + { + "name" : "libvirt", + "url" : "https://dl.rockylinux.org/pub/rocky/9.2/images/x86_64/Rocky-9-Vagrant-Libvirt-9.2-20230513.0.x86_64.box" + } + ] + } + ] + } + EOF + + vagrant box add box-metadata.json + + +Vagrantfile +----------- + +.. code-block:: bash + + mkdir -p ~/warewulf-sandbox + cd ~/warewulf-sandbox + + cat << 'EOF' > Vagrantfile + Vagrant.configure("2") do |config| + number_of_node = ENV["NODES"] || 2 + branch = ENV["BRANCH"] || "v4.4.0" + + config.vm.define :head do |head| + head.vm.box = "rockylinux/9" + head.vm.box_version = "2.0.0-20230513.0" + head.vm.hostname = "warewulf" + + head.vm.network "private_network", + ip: "192.168.200.254", + netmask: "255.255.255.0", + libvirt__network_name: "pxe", + libvirt__dhcp_enabled: false + + head.vm.synced_folder ".", "/vagrant", type: "nfs", nfs_version: 4, nfs_udp: false + + head.vm.provider :libvirt do |libvirt| + libvirt.cpu_mode = "host-passthrough" + libvirt.memory = '8192' + libvirt.cpus = '2' + libvirt.machine_virtual_size = 40 + end + + head.vm.provision "shell", inline: <<-SHELL + dnf install -y cloud-utils-growpart + growpart /dev/vda 5 + xfs_growfs /dev/vda5 + SHELL + + head.vm.provision "shell", inline: <<-SHELL + dnf groupinstall -y "Development Tools" + dnf install -y epel-release + dnf config-manager --set-enabled crb + dnf install -y golang tftp-server dhcp-server nfs-utils gpgme-devel libassuan-devel + + cd /tmp + git clone https://github.com/warewulf/warewulf.git + cd warewulf + git checkout v4.4.0 + make clean defaults \ + PREFIX=/usr \ + BINDIR=/usr/bin \ + SYSCONFDIR=/etc \ + DATADIR=/usr/share \ + LOCALSTATEDIR=/var/lib \ + SHAREDSTATEDIR=/var/lib \ + MANDIR=/usr/share/man \ + INFODIR=/usr/share/info \ + DOCDIR=/usr/share/doc \ + SRVDIR=/var/lib \ + TFTPDIR=/var/lib/tftpboot \ + SYSTEMDDIR=/usr/lib/systemd/system \ + BASHCOMPDIR=/etc/bash_completion.d/ \ + FIREWALLDDIR=/usr/lib/firewalld/services \ + WWCLIENTDIR=/warewulf + make all + make install + + systemctl disable --now firewalld + + sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config + SHELL + + head.vm.provision "reload" + + head.vm.provision "shell", inline: <<-SHELL + cat << 'CONF' | sudo tee /etc/warewulf/warewulf.conf + WW_INTERNAL: 45 + ipaddr: 192.168.200.254 + netmask: 255.255.255.0 + network: 192.168.200.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd + tftp: + enabled: true + systemd name: tftp + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + CONF + + sed -i 's@ExecStart=/usr/bin/wwctl server start@ExecStart=/usr/bin/wwctl server start -d -v@' /usr/lib/systemd/system/warewulfd.service + systemctl enable --now warewulfd + + wwctl configure --all + + wwctl container import docker://ghcr.io/warewulf/warewulf-rockylinux:9 rocky-9 + wwctl profile set --yes --container rocky-9 "default" + wwctl profile set --yes --netdev eth1 --netmask 255.255.255.0 --gateway 192.168.200.254 "default" + + wwctl node add n0001.cluster -I 192.168.200.101 --discoverable true + wwctl node add n0002.cluster -I 192.168.200.102 --discoverable true + SHELL + end + + (1..number_of_node).each do |i| + config.vm.define :"n000#{i}", autostart: false do |node| + node.vm.hostname = "n000#{i}" + node.vm.network "private_network", + libvirt__network_name: "pxe" + + node.vm.provider :libvirt do |compute| + compute.cpu_mode = 'host-passthrough' + compute.memory = '8192' + compute.cpus = '2' + boot_network = {'network' => 'pxe'} + compute.boot boot_network + end + end + end + end + EOF + + +Spin up head node +================= + +.. code-block:: bash + + vagrant up + + +Spin up compute nodes +===================== + +.. code-block:: bash + + vagrant up n0001 + + # Wait until n0001 becomes ready + + vagrant up n0002 diff --git a/static/docs/v4.5.x/_sources/contributing/development-environment-vbox.rst.txt b/static/docs/v4.5.x/_sources/contributing/development-environment-vbox.rst.txt new file mode 100644 index 00000000..d960e407 --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/development-environment-vbox.rst.txt @@ -0,0 +1,161 @@ +==================================== +Development Environment (VirtualBox) +==================================== + +I have VirtualBox running on my desktop. + +1. Create a NAT Network (a private vlan) to be used for the Warewlf + Server and compute nodes inside the VirtualBox. Make sure to + turnoff DHCP service within this NAT Network. + +.. code-block:: console + + # On the host with VirtualBox execute below. In my example using 10.0.8.0/24 as the private vlan for my experiment with Warewulf + + VBoxManage natnetwork add --netname wwnatnetwork --network "10.0.8.0/24" --enable --dhcp off + +2. Create a Centos 7 development Virtual machine (wwdev) to be used as + the Warewulf Server. Enable two Network adapters one with a + standard NAT and SSH port mapping such that you can access this VM + from the host machine. Assign the second network adapter to the NAT + Network created in step #1. Assign sufficient memory (e.g: 4GB) to + the VM. + +.. code-block:: console + + # Download a Centos7 or SL7 ISO and mount it to the optical drive to boot and install OS for the wwdev VM. + # Attach Network adapter #1 of the wwdev VM to the standard NAT via VM Settings -> Network option. + # By default VirtualBox puts the Network Adapter into 10.0.2.0/24 network and assigns 10.0.2.15 IP address. + + # Also add a rule to the port forwarding table under the standard NAT configuration to allow SSH + # from localhost (127.0.0.1) some high port e.g 2222 to the guest IP 10.0.2.15 port 22 such that + # you can SSH from your host/desktop to the wwdev VM. + + # Next attach the second Network adapter #2 to the NAT Network and you should be able to choose + # the 'wwnatnetwork' created above in step #1 from the drop down list. + +3. Build and install Warewulf on wwdev + +.. code-block:: + + # Login to wwdev VM and install @development group and go language + + ssh localhost -p 2222 #(should prompt for a user account password on wwdev VM) + + # Disable selinux by modifying /etc/sysconfig/selinux + vi /etc/sysconfig/selinux + + SELINUX=disabled + + # Disable firewall + systemctl stop firewalld + systemctl disable firewalld + + # Centos prerequisites + sudo yum -y install tftp-server tftp + sudo yum -y install dhcp + sudo yum -y install ipmitool + sudo yum install http://repo.ctrliq.com/packages/rhel7/ctrl-release.rpm + sudo yum install singularityplus + sudo yum install gpgme-devel + sudo yum install libassuan.x86_64 libassuan-devel.x86_64 + + # Upgrade git to v2+ + sudo yum install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm + sudo yum install git + sudo yum install golang + sudo yum install nfs-utils + + # Install Warewulf and dependencies + git clone https://github.com/warewulf/warewulf.git + cd warewulf + + make all + sudo make install + + # Static assign an IP to adapter #2 which is in the wwnatnetwork. + $ Edit the file /etc/sysconfig/networking-scripts/ifcfg-enp0s9 # adapter name at the end might be different for you + # Add lines like to below to assign an ip in 10.0.8.0/24 wwnatnetwork, I choose 10.0.8.4 + BOOTPROTO=static + ONBOOT=yes + NAME=enp0s9 + DEVICE=enp0s9 + IPADDR=10.0.8.4 + NETMASK=255.255.255.0 + GATEWAY=10.0.8.1 + # Bring the enp0s9 interface online and verify ip assignment + + # Configure the Warewulf controller + $ Edit the file /etc/warewulf/warewulf.conf and ensure that you've set the approprite configuration parameters. + # My conf file looks like below: + ipaddr: 10.0.8.4 + netmask: 255.255.255.0 + warewulf: + port: 9873 + secure: true + update interval: 60 + dhcp: + enabled: true + range start: 10.0.8.150 + range end: 10.0.8.200 + template: default + systemd name: dhcpd + tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp + nfs: + systemd name: nfs-server + exports: + - /home + - /var/warewulf + + # Configure system service automatically + sudo wwctl configure dhcp --persist # Create the default dhcpd.conf file and start/enable service + sudo wwctl configure tftp --persist # Install the base tftp/PXE boot files and start/enable service + sudo wwctl configure nfs --persist # Configure the exports and create an fstab in the default system overlay + sudo wwctl configure ssh --persist # Build the basic ssh keys to be included by the default system overlay + + # Pull and build the VNFS container and kernel + sudo wwctl container import docker://ghcr.io/warewulf/warewulf-centos:7 centos-7 --setdefault + sudo wwctl kernel import build $(uname -r) --setdefault + + # Set up the default node profile + sudo wwctl profile set default -K $(uname -r) -C centos-7 + sudo wwctl profile set default --netdev eth0 -M 255.255.255.0 -G 10.0.8.4 + sudo wwctl profile list + + # Add a node and build node specific overlays + # IP address of my nodes start from 150 as set in the warewulf.conf file above + sudo wwctl node add n0000.cluster --netdev eth0 -I 10.0.8.150 --discoverable + sudo wwctl node list -a n0000 + + # Review Warewulf overlays + sudo wwctl overlay list -l + sudo wwctl overlay list -ls + sudo wwctl overlay edit default /etc/hello_world.ww + sudo wwctl overlay build -a + + # Start the Warewulf daemon + sudo wwctl ready + sudo wwctl server start + sudo wwctl server status + +4. Create a new guest VM instance inside the VirtualBox to be the + Warewulf client/compute node. Under the system configuration make + sure to select the optical and network options only for the boot + order. The default iPXE used by VirtualBox does not come with + bzImage capability which is needed for Warewulf. Download the + ipxe.iso available at ipxe.org and mount the ipxe.iso to the + optical drive. Enable one Network adapter for this VM and assign it + to the NAT Network created in step #1 above. + +.. code-block:: console + + # Download ipxe.so available at http://boot.ipxe.org/ipxe.iso + # VM Settings -> System disable Floppy, Hard Disk from Boot order. Enable Optical and Network options. + # VM Settings -> Storage and mount the above download ipxe.so to the Optical Drive. + # VM Settings -> Network Enable adapter #1, attach to 'Nat Network' and choose 'wwnatnetwork' from the drop down list. + +Boot your node and watch the console and the output of the Warewulfd +process. diff --git a/static/docs/v4.5.x/_sources/contributing/documentation.rst.txt b/static/docs/v4.5.x/_sources/contributing/documentation.rst.txt new file mode 100644 index 00000000..17100d9b --- /dev/null +++ b/static/docs/v4.5.x/_sources/contributing/documentation.rst.txt @@ -0,0 +1,22 @@ +============= +Documentation +============= + +We (like almost all open source software providers) have a +documentation dilemma… We tend to focus on the code features and +functionality before working on documentation. And there is very good +reason for this: we want to share the love so nobody feels left out! + +You can contribute to the documentation by `raising an issue to +suggest an improvement +`_ or by sending a +`pull request `_ on +`our repository `_. + +The current documentation is generated with `Docusaurus +`_. + +For more information on using Git and GitHub to create a pull request +suggesting additions and edits to the docs, see the `section on +contributing to the code `_. The procedure is identical +for contributions to the documentation and the code base. diff --git a/static/docs/v4.5.x/_sources/index.rst.txt b/static/docs/v4.5.x/_sources/index.rst.txt new file mode 100644 index 00000000..f59944dd --- /dev/null +++ b/static/docs/v4.5.x/_sources/index.rst.txt @@ -0,0 +1,59 @@ +========== +User Guide +========== + +Welcome to the Warewulf User Guide! + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + Introduction + Background + Stateless Provisioning + Control Server Setup + Warewulf Installation + Warewulf Configuration + Controlling Warewulf (wwctl) + Warewulf Initialization + Container Management + Kernel Management + Boot Management + Node Configuration + Node Profiles + Warewulf Overlays + Node Provisioning + IPMI + Disk Management + Security + Templating + dnsmasq + +.. toctree:: + :maxdepth: 2 + :caption: Quickstart + + EL8 (Rocky Linux and RHEL) + EL9 (Rocky Linux and RHEL) + openSUSE Leap and SLES 15 + Debian 12 + + +.. toctree:: + :maxdepth: 2 + :caption: Contributing + + Contributing + Debugging + Documentation + Development Environment (Vagrant) + Development Environment (KVM) + Development Environment (VirtualBox) + Glossary + +.. toctree:: + :maxdepth: 2 + :caption: Reference + :glob: + + reference/* diff --git a/static/docs/v4.5.x/_sources/quickstart/debian12.rst.txt b/static/docs/v4.5.x/_sources/quickstart/debian12.rst.txt new file mode 100644 index 00000000..59ece3f9 --- /dev/null +++ b/static/docs/v4.5.x/_sources/quickstart/debian12.rst.txt @@ -0,0 +1,210 @@ +===================================== +Debian 12 Quickstart +===================================== + + +Install the basic services +========================== + +.. code-block:: bash + + sudo apt install firewalld nfs-kernel-server tftpd-hpa isc-dhcp-server + + +.. note:: + + If you get an error message concerning *isc-dhcp-server.service* you + probably need to configure the network intarface that isc-dhcp-server + will listen to. Run ``sudo dpkg-reconfigure isc-dhcp-server`` and enter + the name of your cluster's private network interface (e.g. enp2s0). After that, you might also need to run ``sudo systemctl enable isc-dhcp-server``. + + + +Install Warewulf and dependencies +================================= + + +.. code-block:: bash + + sudo apt install build-essential curl unzip + + sudo apt install git golang libnfs-utils libgpgme-dev libassuan-dev + + + mkdir ~/git + cd ~/git + git clone https://github.com/warewulf/warewulf.git + cd warewulf + git checkout main # or switch to a tag like 'v4.4.0' + make all && sudo make install + + + +Configure firewalld +=================== + +Restart firewalld to register the added service file, add the service +to the default zone, and reload. + +.. code-block:: bash + + sudo systemctl restart firewalld + sudo firewall-cmd --permanent --add-service warewulf + sudo firewall-cmd --permanent --add-service nfs + sudo firewall-cmd --permanent --add-service tftp + sudo firewall-cmd --reload + +Configure the controller +======================== + +Edit the file ``/etc/warewulf/warewulf.conf`` and ensure that you've +set the appropriate configuration parameters. Here are some of the +defaults for reference assuming that ``192.168.200.1`` is the IP +address of your cluster's private network interface: + +.. code-block:: yaml + + WW_INTERNAL: 45 + ipaddr: 192.168.200.1 + netmask: 255.255.255.0 + network: 192.168.200.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: isc-dhcp-server + tftp: + enabled: true + systemd name: tftpd-hpa + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + +.. note:: + + The DHCP range ends at ``192.168.200.99`` and as you will see + below, the first node static IP address (post boot) is configured + to ``192.168.200.100``. + +Start and enable the Warewulf service +===================================== + +.. code-block:: bash + + # Start and enable the warewulfd service + sudo systemctl enable --now warewulfd + +Configure system services automatically +======================================= + +There are a number of services and configurations that Warewulf relies +on to operate. If you wish to configure all services, you can do so +individually (omitting the ``--all``) will print a help and usage +instructions. + +.. code-block:: bash + + sudo wwctl configure --all + +.. note:: + + If you just installed the system fresh and have SELinux enforcing, + you may need to reboot the system at this stage to properly set the + contexts of the TFTP contents. After rebooting, you might also need + to run ``$ sudo restorecon -Rv /var/lib/tftpboot/`` if there are + errors with TFTP still. + +Pull and build the VNFS container (including the kernel) +======================================================== + +This will pull a basic VNFS container from Docker Hub and import the +default running kernel from the controller node and set both in the +"default" node profile. + +.. code-block:: bash + + wwctl container import docker://ghcr.io/warewulf/warewulf-debian:12.0 debian-12.0 + + +Set up the default node profile +=============================== + +Node configurations can be set via node profiles. Each node by default +is configured to be part of the ``default`` node profile, so any +changes you make to that profile will affect all nodes. + +The following command will set the container we just imported above to +the ``default`` node profile: + +.. code-block:: bash + + sudo wwctl profile set --yes --container debian-12.0 "default" + + +Next we set some default networking configurations for the first +ethernet device. On modern Linux distributions, the name of the device +is not critical, as it will be setup according to the HW +address. Because all nodes will share the netmask and gateway +configuration, we can set them in the default profile as follows: + +.. code-block:: bash + + sudo wwctl profile set --yes --netdev eth0 --netmask 255.255.255.0 --gateway 192.168.200.1 "default" + +Once those configurations have been set, you can view the changes by +listing the profiles as follows: + +.. code-block:: bash + + sudo wwctl profile list -a + +Add a node +========== + +Adding nodes can be done while setting configurations in one +command. Here we are setting the IP address of ``eth0`` and setting +this node to be discoverable, which will then automatically have the +HW address added to the configuration as the node boots. + +Node names must be unique. If you have node groups and/or multiple +clusters, designate them using dot notation. + +Note that the full node configuration comes from both cascading +profiles and node configurations which always supersede profile +configurations. + +.. code-block:: bash + + sudo wwctl node add n0000.cluster --ipaddr 192.168.200.100 --discoverable true + +At this point you can view the basic configuration of this node by +typing the following: + +.. code-block:: bash + + sudo wwctl node list -a n0000.cluster + +To make node changes effective, it is a good practice to update warewulf +overlays with the following command: + +.. code-block:: bash + + sudo wwctl overlay build + +Now, turn on your compute node and watch it boot! diff --git a/static/docs/v4.5.x/_sources/quickstart/el8.rst.txt b/static/docs/v4.5.x/_sources/quickstart/el8.rst.txt new file mode 100644 index 00000000..5a9f2eb2 --- /dev/null +++ b/static/docs/v4.5.x/_sources/quickstart/el8.rst.txt @@ -0,0 +1,199 @@ +===================================== +EL8 Quickstart (Rocky Linux and RHEL) +===================================== + +Install Warewulf and dependencies +================================= + +.. code-block:: bash + + sudo dnf groupinstall "Development Tools" + sudo dnf install epel-release + sudo dnf config-manager --set-enabled powertools + sudo dnf install golang tftp-server dhcp-server nfs-utils gpgme-devel libassuan-devel + + git clone https://github.com/warewulf/warewulf.git + cd warewulf + make clean defaults \ + PREFIX=/usr \ + BINDIR=/usr/bin \ + SYSCONFDIR=/etc \ + DATADIR=/usr/share \ + LOCALSTATEDIR=/var/lib \ + SHAREDSTATEDIR=/var/lib \ + MANDIR=/usr/share/man \ + INFODIR=/usr/share/info \ + DOCDIR=/usr/share/doc \ + SRVDIR=/var/lib \ + TFTPDIR=/var/lib/tftpboot \ + SYSTEMDDIR=/usr/lib/systemd/system \ + BASHCOMPDIR=/etc/bash_completion.d/ \ + FIREWALLDDIR=/usr/lib/firewalld/services \ + WWCLIENTDIR=/warewulf + make all + sudo make install + +Configure firewalld +=================== + +Restart firewalld to register the added service file, add the service +to the default zone, and reload. + +.. code-block:: bash + + sudo systemctl restart firewalld + sudo firewall-cmd --permanent --add-service warewulf + sudo firewall-cmd --permanent --add-service nfs + sudo firewall-cmd --permanent --add-service tftp + sudo firewall-cmd --reload + +Configure the controller +======================== + +Edit the file ``/etc/warewulf/warewulf.conf`` and ensure that you've +set the appropriate configuration parameters. Here are some of the +defaults for reference assuming that ``192.168.200.1`` is the IP +address of your cluster's private network interface: + +.. code-block:: yaml + + WW_INTERNAL: 45 + ipaddr: 192.168.200.1 + netmask: 255.255.255.0 + network: 192.168.200.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd + tftp: + enabled: true + systemd name: tftp + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true + +.. note:: + + The DHCP range ends at ``192.168.200.99`` and as you will see + below, the first node static IP address (post boot) is configured + to ``192.168.200.100``. + +Start and enable the Warewulf service +===================================== + +.. code-block:: bash + + # Start and enable the warewulfd service + sudo systemctl enable --now warewulfd + +Configure system services automatically +======================================= + +There are a number of services and configurations that Warewulf relies +on to operate. If you wish to configure all services, you can do so +individually (omitting the ``--all``) will print a help and usage +instructions. + +.. code-block:: bash + + sudo wwctl configure --all + +.. note:: + + If you just installed the system fresh and have SELinux enforcing, + you may need to reboot the system at this stage to properly set the + contexts of the TFTP contents. After rebooting, you might also need + to run ``$ sudo restorecon -Rv /var/lib/tftpboot/`` if there are + errors with TFTP still. + +Pull and build the VNFS container (including the kernel) +======================================================== + +This will pull a basic VNFS container from Docker Hub and import the +default running kernel from the controller node and set both in the +"default" node profile. + +.. code-block:: bash + + sudo wwctl container import docker://ghcr.io/warewulf/warewulf-rockylinux:8 rocky-8 + + +Set up the default node profile +=============================== + +Node configurations can be set via node profiles. Each node by default +is configured to be part of the ``default`` node profile, so any +changes you make to that profile will affect all nodes. + +The following command will set the container we just imported above to +the ``default`` node profile: + +.. code-block:: bash + + sudo wwctl profile set --yes --container rocky-8 "default" + +Next we set some default networking configurations for the first +ethernet device. On modern Linux distributions, the name of the device +is not critical, as it will be setup according to the HW +address. Because all nodes will share the netmask and gateway +configuration, we can set them in the default profile as follows: + +.. code-block:: bash + + sudo wwctl profile set --yes --netdev eth0 --netmask 255.255.255.0 --gateway 192.168.200.1 "default" + +Once those configurations have been set, you can view the changes by +listing the profiles as follows: + +.. code-block:: bash + + sudo wwctl profile list -a + +Add a node +========== + +Adding nodes can be done while setting configurations in one +command. Here we are setting the IP address of ``eth0`` and setting +this node to be discoverable, which will then automatically have the +HW address added to the configuration as the node boots. + +Node names must be unique. If you have node groups and/or multiple +clusters, designate them using dot notation. + +Note that the full node configuration comes from both cascading +profiles and node configurations which always supersede profile +configurations. + +.. code-block:: bash + + sudo wwctl node add n0000.cluster --ipaddr 192.168.200.100 --discoverable true + +At this point you can view the basic configuration of this node by +typing the following: + +.. code-block:: bash + + sudo wwctl node list -a n0000.cluster + +Turn on your compute node and watch it boot! diff --git a/static/docs/v4.5.x/_sources/quickstart/el9.rst.txt b/static/docs/v4.5.x/_sources/quickstart/el9.rst.txt new file mode 100644 index 00000000..dddd8f3f --- /dev/null +++ b/static/docs/v4.5.x/_sources/quickstart/el9.rst.txt @@ -0,0 +1,199 @@ +===================================== +EL9 Quickstart (Rocky Linux and RHEL) +===================================== + +Install Warewulf and dependencies +================================= + +.. code-block:: bash + + sudo dnf groupinstall "Development Tools" + sudo dnf install epel-release + sudo dnf config-manager --set-enabled crb + sudo dnf install golang tftp-server dhcp-server nfs-utils gpgme-devel libassuan-devel + + git clone https://github.com/warewulf/warewulf.git + cd warewulf + make clean defaults \ + PREFIX=/usr \ + BINDIR=/usr/bin \ + SYSCONFDIR=/etc \ + DATADIR=/usr/share \ + LOCALSTATEDIR=/var/lib \ + SHAREDSTATEDIR=/var/lib \ + MANDIR=/usr/share/man \ + INFODIR=/usr/share/info \ + DOCDIR=/usr/share/doc \ + SRVDIR=/var/lib \ + TFTPDIR=/var/lib/tftpboot \ + SYSTEMDDIR=/usr/lib/systemd/system \ + BASHCOMPDIR=/etc/bash_completion.d/ \ + FIREWALLDDIR=/usr/lib/firewalld/services \ + WWCLIENTDIR=/warewulf + make all + sudo make install + +Configure firewalld +=================== + +Restart firewalld to register the added service file, add the service +to the default zone, and reload. + +.. code-block:: bash + + sudo systemctl restart firewalld + sudo firewall-cmd --permanent --add-service warewulf + sudo firewall-cmd --permanent --add-service nfs + sudo firewall-cmd --permanent --add-service tftp + sudo firewall-cmd --reload + +Configure the controller +======================== + +Edit the file ``/etc/warewulf/warewulf.conf`` and ensure that you've +set the appropriate configuration parameters. Here are some of the +defaults for reference assuming that ``192.168.200.1`` is the IP +address of your cluster's private network interface: + +.. code-block:: yaml + + WW_INTERNAL: 45 + ipaddr: 192.168.200.1 + netmask: 255.255.255.0 + network: 192.168.200.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd + tftp: + enabled: true + systemd name: tftp + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true + +.. note:: + + The DHCP range ends at ``192.168.200.99`` and as you will see + below, the first node static IP address (post boot) is configured + to ``192.168.200.100``. + +Start and enable the Warewulf service +===================================== + +.. code-block:: bash + + # Start and enable the warewulfd service + sudo systemctl enable --now warewulfd + +Configure system services automatically +======================================= + +There are a number of services and configurations that Warewulf relies +on to operate. If you wish to configure all services, you can do so +individually (omitting the ``--all``) will print a help and usage +instructions. + +.. code-block:: bash + + sudo wwctl configure --all + +.. note:: + + If you just installed the system fresh and have SELinux enforcing, + you may need to reboot the system at this stage to properly set the + contexts of the TFTP contents. After rebooting, you might also need + to run ``$ sudo restorecon -Rv /var/lib/tftpboot/`` if there are + errors with TFTP still. + +Pull and build the VNFS container (including the kernel) +======================================================== + +This will pull a basic VNFS container from Docker Hub and import the +default running kernel from the controller node and set both in the +"default" node profile. + +.. code-block:: bash + + sudo wwctl container import docker://ghcr.io/warewulf/warewulf-rockylinux:9 rocky-9 + + +Set up the default node profile +=============================== + +Node configurations can be set via node profiles. Each node by default +is configured to be part of the ``default`` node profile, so any +changes you make to that profile will affect all nodes. + +The following command will set the container we just imported above to +the ``default`` node profile: + +.. code-block:: bash + + sudo wwctl profile set --yes --container rocky-9 "default" + +Next we set some default networking configurations for the first +ethernet device. On modern Linux distributions, the name of the device +is not critical, as it will be setup according to the HW +address. Because all nodes will share the netmask and gateway +configuration, we can set them in the default profile as follows: + +.. code-block:: bash + + sudo wwctl profile set --yes --netdev eth0 --netmask 255.255.255.0 --gateway 192.168.200.1 "default" + +Once those configurations have been set, you can view the changes by +listing the profiles as follows: + +.. code-block:: bash + + sudo wwctl profile list -a + +Add a node +========== + +Adding nodes can be done while setting configurations in one +command. Here we are setting the IP address of ``eth0`` and setting +this node to be discoverable, which will then automatically have the +HW address added to the configuration as the node boots. + +Node names must be unique. If you have node groups and/or multiple +clusters, designate them using dot notation. + +Note that the full node configuration comes from both cascading +profiles and node configurations which always supersede profile +configurations. + +.. code-block:: bash + + sudo wwctl node add n0000.cluster --ipaddr 192.168.200.100 --discoverable true + +At this point you can view the basic configuration of this node by +typing the following: + +.. code-block:: bash + + sudo wwctl node list -a n0000.cluster + +Turn on your compute node and watch it boot! diff --git a/static/docs/v4.5.x/_sources/quickstart/suse15.rst.txt b/static/docs/v4.5.x/_sources/quickstart/suse15.rst.txt new file mode 100644 index 00000000..bb15b7a8 --- /dev/null +++ b/static/docs/v4.5.x/_sources/quickstart/suse15.rst.txt @@ -0,0 +1,204 @@ +==================================== +openSUSE Leap and SLES 15 Quickstart +==================================== + +Install Warewulf and dependencies +================================= + +.. code-block:: bash + + sudo zypper install -t pattern devel_basis + sudo zypper install go + sudo zypper install tftp dhcp-server nfs-kernel-server + + sudo systemctl stop firewalld + sudo systemctl disable firewalld + + git clone https://github.com/warewulf/warewulf.git + cd warewulf + PREFIX=/usr SYSCONFDIR=/etc TFTPDIR=/srv/tftproot LOCALSTATEDIR=/var/lib make clean defaults + make all + sudo make install + +The standard configuration template for the dhcpd service is installed +at the wrong location, you have to fix this with + +.. code-block:: bash + + mv /var/lib/warewulf/overlays/host/etc/dhcp/dhcpd.conf.ww /var/lib/warewulf/overlays/host/etc/dhcpd.conf.ww + +Install Warewulf from the open build service +============================================ + +You can also just install the 'warewulf4' package with ``zypper`` from +the openbuild service. Up to date versions are available on the devel +project + +``https://build.opensuse.org/project/show/network:cluster`` + +Configure the controller +======================== + +Edit the file ``/etc/warewulf/warewulf.conf`` and ensure that you've +set the appropriate configuration paramaters. Here are some of the +defaults for reference assuming that ``192.168.200.1`` is the IP +address of your cluster's private network interface: + +.. code-block:: yaml + + WW_INTERNAL: 45 + ipaddr: 192.168.200.1 + netmask: 255.255.255.0 + network: 192.168.200.0 + warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd + tftp: + enabled: true + systemd name: tftp + nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server + container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true + +.. note:: + + The DHCP range ends at ``192.168.200.99`` and as you will see + below, the first node static IP address (post boot) is configured + to ``192.168.200.100``. + +Start and enable the Warewulf service +===================================== + +.. code-block:: bash + + # Start and enable the warewulfd service + sudo systemctl enable --now warewulfd + +Configure system services automatically +======================================= + +There are a number of services and configurations that Warewulf relies +on to operate. If you wish to configure all services, you can do so +individually (omitting the ``--all``) will print a help and usage +instructions. + +.. note:: + + If the ``dhcpd`` service was not used before you will have to add + the interface on which the cluster network is running to the + ``DHCP_INTERFACE`` in the file ``/etc/sysconfig/dhcpd``. + +.. code-block:: bash + + sudo wwctl configure --all + +Pull and build the VNFS container and kernel +============================================ + +This will pull a basic VNFS container from Docker Hub and import the +default running kernel from the controller node and set both in the +"default" node profile. + +.. code-block:: bash + + $ sudo wwctl container import docker://registry.opensuse.org/science/warewulf/leap-15.4/containers/kernel:latest leap15.4 --setdefault + +Set up the default node profile +=============================== + +The ``--setdefault`` arguments above will automatically set those +entries in the default profile, but if you wanted to set them by hand +to something different, you can do the following: + +.. code-block:: bash + + sudo wwctl profile set -y -C leap15.4 + +Next we set some default networking configurations for the first +ethernet device. On modern Linux distributions, the name of the device +is not critical, as it will be setup according to the HW +address. Because all nodes will share the netmask and gateway +configuration, we can set them in the default profile as follows: + +.. code-block:: bash + + sudo wwctl profile set -y default --netname default --netmask 255.255.255.0 --gateway 192.168.200.1 + sudo wwctl profile list -a + +Add a node +========== + +Adding nodes can be done while setting configurations in one +command. Here we are setting the IP address of ``eth0`` and setting +this node to be discoverable, which will then automatically have the +HW address added to the configuration as the node boots. + +Node names must be unique. If you have node groups and/or multiple +clusters, designate them using dot notation. + +Note that the full node configuration comes from both cascading +profiles and node configurations which always supersede profile +configurations. + +.. code-block:: bash + + sudo wwctl node add n0000.cluster --netdev eth0 --ipaddr 192.168.200.100 --discoverable true + sudo wwctl node list -a n0000.cluster + +Warewulf Overlays +================= + +There are two types of overlays: system and runtime overlays. + +System overlays are provisioned to the node before ``/sbin/init`` is +called. This enables us to prepopulate node configurations with +content that is node specific like networking and service +configurations. + +Runtime overlays are provisioned after the node has booted and +periodically during the normal runtime of the node. Because these +overlays are provisioned at periodic intervals, they are very useful +for content that changes, like users and groups. + +Overlays are generated from a template structure that is viewed using +the ``wwctl overlay`` commands. Files that end in the ``.ww`` suffix +are templates and abide by standard text/template rules. This supports +loops, arrays, variables, and functions making overlays extremely +flexible. + +All overlays are compiled before being provisioned. This accelerates +the provisioning process because there is less to do when nodes are +being managed at scale. + +Here are some of the common ``overlay`` commands: + +.. code-block:: bash + + sudo wwctl overlay list -l + sudo wwctl overlay list -ls + sudo wwctl overlay edit default /etc/hello_world.ww + sudo wwctl overlay build -a + +Boot your compute node and watch it boot! diff --git a/static/docs/v4.5.x/_static/_sphinx_javascript_frameworks_compat.js b/static/docs/v4.5.x/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/static/docs/v4.5.x/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/static/docs/v4.5.x/_static/basic.css b/static/docs/v4.5.x/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/static/docs/v4.5.x/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/css/badge_only.css b/static/docs/v4.5.x/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/static/docs/v4.5.x/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff2 b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff2 b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.eot b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.svg b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.ttf b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff2 b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff b/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff2 b/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff b/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff2 b/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-bold.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff b/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff2 b/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff b/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff differ diff --git a/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff2 b/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/static/docs/v4.5.x/_static/css/fonts/lato-normal.woff2 differ diff --git a/static/docs/v4.5.x/_static/css/theme.css b/static/docs/v4.5.x/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/static/docs/v4.5.x/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/doctools.js b/static/docs/v4.5.x/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/static/docs/v4.5.x/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/static/docs/v4.5.x/_static/documentation_options.js b/static/docs/v4.5.x/_static/documentation_options.js new file mode 100644 index 00000000..31e37a50 --- /dev/null +++ b/static/docs/v4.5.x/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: 'main', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/favicon.png b/static/docs/v4.5.x/_static/favicon.png new file mode 100644 index 00000000..6c0cf440 Binary files /dev/null and b/static/docs/v4.5.x/_static/favicon.png differ diff --git a/static/docs/v4.5.x/_static/file.png b/static/docs/v4.5.x/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/static/docs/v4.5.x/_static/file.png differ diff --git a/static/docs/v4.5.x/_static/graphviz.css b/static/docs/v4.5.x/_static/graphviz.css new file mode 100644 index 00000000..8d81c02e --- /dev/null +++ b/static/docs/v4.5.x/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/static/docs/v4.5.x/_static/jquery.js b/static/docs/v4.5.x/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/static/docs/v4.5.x/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/js/html5shiv.min.js b/static/docs/v4.5.x/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/static/docs/v4.5.x/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/js/theme.js b/static/docs/v4.5.x/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/static/docs/v4.5.x/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/static/docs/v4.5.x/_static/logo.png b/static/docs/v4.5.x/_static/logo.png new file mode 100644 index 00000000..c929038b Binary files /dev/null and b/static/docs/v4.5.x/_static/logo.png differ diff --git a/static/docs/v4.5.x/_static/minus.png b/static/docs/v4.5.x/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/static/docs/v4.5.x/_static/minus.png differ diff --git a/static/docs/v4.5.x/_static/plus.png b/static/docs/v4.5.x/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/static/docs/v4.5.x/_static/plus.png differ diff --git a/static/docs/v4.5.x/_static/pygments.css b/static/docs/v4.5.x/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/static/docs/v4.5.x/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/static/docs/v4.5.x/_static/searchtools.js b/static/docs/v4.5.x/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/static/docs/v4.5.x/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/static/docs/v4.5.x/_static/sphinx_highlight.js b/static/docs/v4.5.x/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/static/docs/v4.5.x/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/static/docs/v4.5.x/contents/background.html b/static/docs/v4.5.x/contents/background.html new file mode 100644 index 00000000..e6e2ade5 --- /dev/null +++ b/static/docs/v4.5.x/contents/background.html @@ -0,0 +1,176 @@ + + + + + + + Background — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/boot-management.html b/static/docs/v4.5.x/contents/boot-management.html new file mode 100644 index 00000000..a24a7b7a --- /dev/null +++ b/static/docs/v4.5.x/contents/boot-management.html @@ -0,0 +1,265 @@ + + + + + + + Boot Management — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/configuration.html b/static/docs/v4.5.x/contents/configuration.html new file mode 100644 index 00000000..0df7d9b2 --- /dev/null +++ b/static/docs/v4.5.x/contents/configuration.html @@ -0,0 +1,313 @@ + + + + + + + Warewulf Configuration — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/containers.html b/static/docs/v4.5.x/contents/containers.html new file mode 100644 index 00000000..e8ecd7f6 --- /dev/null +++ b/static/docs/v4.5.x/contents/containers.html @@ -0,0 +1,474 @@ + + + + + + + Container Management — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/disks.html b/static/docs/v4.5.x/contents/disks.html new file mode 100644 index 00000000..ef746e2f --- /dev/null +++ b/static/docs/v4.5.x/contents/disks.html @@ -0,0 +1,252 @@ + + + + + + + Disk Management — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/dnsmasq.html b/static/docs/v4.5.x/contents/dnsmasq.html new file mode 100644 index 00000000..a7b4dca9 --- /dev/null +++ b/static/docs/v4.5.x/contents/dnsmasq.html @@ -0,0 +1,201 @@ + + + + + + + Dnsmasq — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/glossary.html b/static/docs/v4.5.x/contents/glossary.html new file mode 100644 index 00000000..59398899 --- /dev/null +++ b/static/docs/v4.5.x/contents/glossary.html @@ -0,0 +1,174 @@ + + + + + + + Glossary — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/initialization.html b/static/docs/v4.5.x/contents/initialization.html new file mode 100644 index 00000000..e9d2b67a --- /dev/null +++ b/static/docs/v4.5.x/contents/initialization.html @@ -0,0 +1,215 @@ + + + + + + + Warewulf Initialization — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/installation.html b/static/docs/v4.5.x/contents/installation.html new file mode 100644 index 00000000..e07fbd90 --- /dev/null +++ b/static/docs/v4.5.x/contents/installation.html @@ -0,0 +1,253 @@ + + + + + + + Warewulf Installation — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/introduction.html b/static/docs/v4.5.x/contents/introduction.html new file mode 100644 index 00000000..492f3812 --- /dev/null +++ b/static/docs/v4.5.x/contents/introduction.html @@ -0,0 +1,217 @@ + + + + + + + Introduction — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/ipmi.html b/static/docs/v4.5.x/contents/ipmi.html new file mode 100644 index 00000000..648ab831 --- /dev/null +++ b/static/docs/v4.5.x/contents/ipmi.html @@ -0,0 +1,364 @@ + + + + + + + IPMI — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/kernel.html b/static/docs/v4.5.x/contents/kernel.html new file mode 100644 index 00000000..ffb13c7c --- /dev/null +++ b/static/docs/v4.5.x/contents/kernel.html @@ -0,0 +1,213 @@ + + + + + + + Kernel Management — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/nodeconfig.html b/static/docs/v4.5.x/contents/nodeconfig.html new file mode 100644 index 00000000..44a3d3cb --- /dev/null +++ b/static/docs/v4.5.x/contents/nodeconfig.html @@ -0,0 +1,414 @@ + + + + + + + Node Configuration — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/overlays.html b/static/docs/v4.5.x/contents/overlays.html new file mode 100644 index 00000000..5171a657 --- /dev/null +++ b/static/docs/v4.5.x/contents/overlays.html @@ -0,0 +1,392 @@ + + + + + + + Warewulf Overlays — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/profiles.html b/static/docs/v4.5.x/contents/profiles.html new file mode 100644 index 00000000..48ec8a4a --- /dev/null +++ b/static/docs/v4.5.x/contents/profiles.html @@ -0,0 +1,322 @@ + + + + + + + Node Profiles — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/provisioning.html b/static/docs/v4.5.x/contents/provisioning.html new file mode 100644 index 00000000..0eca6278 --- /dev/null +++ b/static/docs/v4.5.x/contents/provisioning.html @@ -0,0 +1,264 @@ + + + + + + + Node Provisioning — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/security.html b/static/docs/v4.5.x/contents/security.html new file mode 100644 index 00000000..2fb8a624 --- /dev/null +++ b/static/docs/v4.5.x/contents/security.html @@ -0,0 +1,236 @@ + + + + + + + Security — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/setup.html b/static/docs/v4.5.x/contents/setup.html new file mode 100644 index 00000000..d87e9c5e --- /dev/null +++ b/static/docs/v4.5.x/contents/setup.html @@ -0,0 +1,317 @@ + + + + + + + Control Server Setup — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/stateless.html b/static/docs/v4.5.x/contents/stateless.html new file mode 100644 index 00000000..f0ec8c9a --- /dev/null +++ b/static/docs/v4.5.x/contents/stateless.html @@ -0,0 +1,224 @@ + + + + + + + Stateless Provisioning — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/templating.html b/static/docs/v4.5.x/contents/templating.html new file mode 100644 index 00000000..7de0f51a --- /dev/null +++ b/static/docs/v4.5.x/contents/templating.html @@ -0,0 +1,370 @@ + + + + + + + Templating — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contents/wwctl.html b/static/docs/v4.5.x/contents/wwctl.html new file mode 100644 index 00000000..d9235f9a --- /dev/null +++ b/static/docs/v4.5.x/contents/wwctl.html @@ -0,0 +1,181 @@ + + + + + + + Controlling Warewulf (wwctl) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/contributing.html b/static/docs/v4.5.x/contributing/contributing.html new file mode 100644 index 00000000..41a6d21b --- /dev/null +++ b/static/docs/v4.5.x/contributing/contributing.html @@ -0,0 +1,289 @@ + + + + + + + Contributing — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/debugging.html b/static/docs/v4.5.x/contributing/debugging.html new file mode 100644 index 00000000..27b1f07b --- /dev/null +++ b/static/docs/v4.5.x/contributing/debugging.html @@ -0,0 +1,445 @@ + + + + + + + Debugging — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/development-environment-kvm.html b/static/docs/v4.5.x/contributing/development-environment-kvm.html new file mode 100644 index 00000000..93f58252 --- /dev/null +++ b/static/docs/v4.5.x/contributing/development-environment-kvm.html @@ -0,0 +1,276 @@ + + + + + + + Development Environment (KVM) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/development-environment-vagrant.html b/static/docs/v4.5.x/contributing/development-environment-vagrant.html new file mode 100644 index 00000000..0cd072ee --- /dev/null +++ b/static/docs/v4.5.x/contributing/development-environment-vagrant.html @@ -0,0 +1,423 @@ + + + + + + + Development Environment (Vagrant) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/development-environment-vbox.html b/static/docs/v4.5.x/contributing/development-environment-vbox.html new file mode 100644 index 00000000..64ed04a5 --- /dev/null +++ b/static/docs/v4.5.x/contributing/development-environment-vbox.html @@ -0,0 +1,306 @@ + + + + + + + Development Environment (VirtualBox) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/contributing/documentation.html b/static/docs/v4.5.x/contributing/documentation.html new file mode 100644 index 00000000..822363af --- /dev/null +++ b/static/docs/v4.5.x/contributing/documentation.html @@ -0,0 +1,163 @@ + + + + + + + Documentation — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/genindex.html b/static/docs/v4.5.x/genindex.html new file mode 100644 index 00000000..3da8103a --- /dev/null +++ b/static/docs/v4.5.x/genindex.html @@ -0,0 +1,147 @@ + + + + + + Index — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/index.html b/static/docs/v4.5.x/index.html new file mode 100644 index 00000000..e1b2b75e --- /dev/null +++ b/static/docs/v4.5.x/index.html @@ -0,0 +1,362 @@ + + + + + + + User Guide — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/objects.inv b/static/docs/v4.5.x/objects.inv new file mode 100644 index 00000000..83221aae Binary files /dev/null and b/static/docs/v4.5.x/objects.inv differ diff --git a/static/docs/v4.5.x/quickstart/debian12.html b/static/docs/v4.5.x/quickstart/debian12.html new file mode 100644 index 00000000..5bdf2820 --- /dev/null +++ b/static/docs/v4.5.x/quickstart/debian12.html @@ -0,0 +1,332 @@ + + + + + + + Debian 12 Quickstart — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/quickstart/el8.html b/static/docs/v4.5.x/quickstart/el8.html new file mode 100644 index 00000000..ea09f547 --- /dev/null +++ b/static/docs/v4.5.x/quickstart/el8.html @@ -0,0 +1,331 @@ + + + + + + + EL8 Quickstart (Rocky Linux and RHEL) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/quickstart/el9.html b/static/docs/v4.5.x/quickstart/el9.html new file mode 100644 index 00000000..75a4ef49 --- /dev/null +++ b/static/docs/v4.5.x/quickstart/el9.html @@ -0,0 +1,331 @@ + + + + + + + EL9 Quickstart (Rocky Linux and RHEL) — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/quickstart/suse15.html b/static/docs/v4.5.x/quickstart/suse15.html new file mode 100644 index 00000000..d055d664 --- /dev/null +++ b/static/docs/v4.5.x/quickstart/suse15.html @@ -0,0 +1,334 @@ + + + + + + + openSUSE Leap and SLES 15 Quickstart — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/search.html b/static/docs/v4.5.x/search.html new file mode 100644 index 00000000..ebdcdaad --- /dev/null +++ b/static/docs/v4.5.x/search.html @@ -0,0 +1,161 @@ + + + + + + Search — Warewulf User Guide main documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/docs/v4.5.x/searchindex.js b/static/docs/v4.5.x/searchindex.js new file mode 100644 index 00000000..90216991 --- /dev/null +++ b/static/docs/v4.5.x/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["contents/background", "contents/boot-management", "contents/configuration", "contents/containers", "contents/disks", "contents/dnsmasq", "contents/glossary", "contents/initialization", "contents/installation", "contents/introduction", "contents/ipmi", "contents/kernel", "contents/nodeconfig", "contents/overlays", "contents/profiles", "contents/provisioning", "contents/security", "contents/setup", "contents/stateless", "contents/templating", "contents/wwctl", "contributing/contributing", "contributing/debugging", "contributing/development-environment-kvm", "contributing/development-environment-vagrant", "contributing/development-environment-vbox", "contributing/documentation", "index", "quickstart/debian12", "quickstart/el8", "quickstart/el9", "quickstart/suse15"], "filenames": ["contents/background.rst", "contents/boot-management.rst", "contents/configuration.rst", "contents/containers.rst", "contents/disks.rst", "contents/dnsmasq.rst", "contents/glossary.rst", "contents/initialization.rst", "contents/installation.rst", "contents/introduction.rst", "contents/ipmi.rst", "contents/kernel.rst", "contents/nodeconfig.rst", "contents/overlays.rst", "contents/profiles.rst", "contents/provisioning.rst", "contents/security.rst", "contents/setup.rst", "contents/stateless.rst", "contents/templating.rst", "contents/wwctl.rst", "contributing/contributing.rst", "contributing/debugging.rst", "contributing/development-environment-kvm.rst", "contributing/development-environment-vagrant.rst", "contributing/development-environment-vbox.rst", "contributing/documentation.rst", "index.rst", "quickstart/debian12.rst", "quickstart/el8.rst", "quickstart/el9.rst", "quickstart/suse15.rst"], "titles": ["Background", "Boot Management", "Warewulf Configuration", "Container Management", "Disk Management", "Dnsmasq", "Glossary", "Warewulf Initialization", "Warewulf Installation", "Introduction", "IPMI", "Kernel Management", "Node Configuration", "Warewulf Overlays", "Node Profiles", "Node Provisioning", "Security", "Control Server Setup", "Stateless Provisioning", "Templating", "Controlling Warewulf (wwctl)", "Contributing", "Debugging", "Development Environment (KVM)", "Development Environment (Vagrant)", "Development Environment (VirtualBox)", "Documentation", "User Guide", "Debian 12 Quickstart", "EL8 Quickstart (Rocky Linux and RHEL)", "EL9 Quickstart (Rocky Linux and RHEL)", "openSUSE Leap and SLES 15 Quickstart"], "terms": {"warewulf": [0, 1, 3, 4, 5, 6, 10, 11, 12, 14, 15, 16, 17, 18, 19, 22, 25, 27], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "base": [0, 3, 7, 17, 18, 20, 21, 23, 25, 26], "design": [0, 9, 13, 14, 16, 18, 28, 29, 30, 31], "origin": [0, 2, 18, 19, 21], "beowulf": 0, "cluster": [0, 2, 3, 6, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 23, 24, 25, 28, 29, 30, 31], "thu": [0, 3], "name": [0, 2, 3, 5, 10, 11, 13, 14, 17, 19, 21, 22, 23, 24, 25, 28, 29, 30, 31], "soft": [0, 10, 16], "ware": 0, "implement": [0, 3, 13, 16, 17, 27], "beo": 0, "wulf": 0, "The": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 13, 16, 17, 18, 19, 21, 22, 25, 26, 27, 28, 29, 30, 31], "wa": [0, 4, 11, 12, 14, 16, 18, 31], "develop": [0, 8, 16, 21, 22, 27, 29, 30], "1996": 0, "dr": 0, "thoma": 0, "sterl": 0, "donald": 0, "becker": 0, "nasa": 0, "architectur": [0, 3, 9, 17], "defin": [0, 2, 3, 12, 16, 19, 20, 24, 27], "group": [0, 3, 8, 12, 13, 14, 18, 23, 24, 25, 28, 29, 30, 31], "similar": [0, 2, 3], "comput": [0, 2, 3, 6, 9, 11, 13, 15, 16, 17, 18, 21, 25, 27, 28, 29, 30, 31], "worker": [0, 6], "node": [0, 1, 3, 4, 6, 7, 9, 13, 16, 17, 18, 20, 22, 23, 25, 27], "all": [0, 2, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "connect": [0, 2, 10, 16, 17], "togeth": [0, 3, 14, 18, 22], "us": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31], "standard": [0, 3, 6, 9, 13, 25, 31], "commod": 0, "equip": 0, "privat": [0, 2, 9, 17, 25, 28, 29, 30, 31], "network": [0, 1, 2, 8, 13, 14, 15, 18, 19, 24, 25, 27, 28, 29, 30, 31], "segment": 0, "control": [0, 2, 3, 4, 6, 7, 8, 10, 13, 15, 19, 23, 25, 27], "histor": [0, 6, 16], "refer": [0, 12, 15, 20, 28, 29, 30, 31], "master": [0, 3, 6, 21], "head": [0, 6, 14, 27], "dual": [0, 17], "home": [0, 2, 17, 22, 24, 25, 28, 29, 30, 31], "ha": [0, 1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 17, 20, 21, 24, 31], "two": [0, 3, 13, 14, 17, 25, 31], "interfac": [0, 2, 10, 12, 13, 17, 19, 20, 22, 25, 28, 29, 30, 31], "card": [0, 15, 17], "one": [0, 3, 10, 12, 14, 16, 17, 18, 25, 28, 29, 30, 31], "attach": [0, 25], "upstream": [0, 21], "public": [0, 3, 17, 19], "other": [0, 2, 3, 7, 8, 12, 13, 14, 15, 18, 21, 22], "which": [0, 1, 2, 3, 4, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 28, 29, 30, 31], "seen": [0, 14, 15], "figur": [0, 17], "below": [0, 10, 17, 25, 28, 29, 30, 31], "thi": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 28, 29, 30, 31], "simpl": [0, 9, 12, 13, 16], "topologi": 0, "foundat": 0, "creat": [0, 4, 5, 7, 9, 12, 14, 18, 21, 25, 26, 27], "everi": [0, 1, 3, 4, 10, 13, 14, 15, 18, 19], "scalabl": [0, 9, 12, 13, 14, 18], "hpc": [0, 3, 9, 16, 17, 18], "resourc": [0, 6, 9, 17, 21], "even": [0, 3, 9, 16, 17, 18, 22], "todai": [0, 18], "almost": [0, 3, 16, 17, 26], "30": [0, 17], "year": [0, 3, 9], "after": [0, 3, 4, 5, 12, 17, 19, 28, 29, 30, 31], "incept": [0, 3], "baselin": 0, "tradit": [0, 9, 21], "system": [0, 1, 2, 3, 4, 6, 8, 9, 10, 15, 16, 18, 19, 20, 21, 23, 25, 27], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 28, 29, 30, 31], "built": [0, 2, 3, 13, 20], "consider": [0, 27], "work": [0, 3, 4, 9, 15, 16, 21, 26], "type": [0, 2, 6, 9, 10, 12, 16, 17, 19, 22, 23, 24, 28, 29, 30, 31], "storag": [0, 6, 25, 27], "schedul": [0, 17], "manag": [0, 2, 6, 8, 9, 10, 13, 14, 16, 17, 18, 20, 23, 24, 27, 29, 30, 31], "monitor": [0, 17], "interact": [0, 3], "etc": [0, 2, 3, 4, 5, 6, 7, 11, 13, 14, 16, 17, 19, 23, 24, 25, 28, 29, 30, 31], "For": [0, 2, 3, 9, 12, 13, 14, 15, 16, 17, 19, 20, 21, 26], "smaller": [0, 14], "much": 0, "requir": [0, 2, 3, 8, 11, 12, 14, 15, 16, 17, 27], "can": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 25, 26, 28, 29, 30, 31], "from": [0, 1, 2, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 27, 28, 29, 30], "singl": [0, 1, 3, 4, 10, 12, 13, 14, 18, 22], "scale": [0, 9, 18, 31], "mai": [0, 2, 3, 4, 7, 8, 15, 16, 17, 18, 21, 28, 29, 30], "need": [0, 1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 25, 28, 29, 30], "have": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 28, 29, 30, 31], "dedic": [0, 17], "differ": [0, 3, 8, 9, 10, 13, 14, 15, 16, 18, 25, 31], "servic": [0, 2, 4, 5, 8, 13, 17, 19, 20, 21, 23, 24, 25, 27], "easili": [0, 4], "capabl": [0, 9, 11, 16, 24, 25], "build": [0, 2, 5, 8, 11, 25, 27], "turnkei": [0, 9], "giant": 0, "massiv": [0, 9], "complex": 0, "multi": [0, 16], "purpos": [0, 2, 3, 11, 13, 14], "through": [0, 10, 13, 15, 16, 22], "next": [0, 4, 12, 17, 18, 21, 22, 25, 28, 29, 30, 31], "gener": [0, 2, 3, 8, 9, 10, 12, 15, 16, 17, 19, 21, 22, 26, 31], "platform": [0, 3, 4, 8, 9, 18], "anytim": 0, "your": [0, 2, 8, 9, 10, 14, 15, 16, 17, 22, 23, 24, 25, 28, 29, 30, 31], "tool": [0, 8, 9, 15, 18, 24, 27, 29, 30], "default": [1, 3, 5, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 22, 24, 25, 27], "As": [1, 3, 4, 5, 9, 12, 13, 14, 17, 21], "tech": 1, "preview": 1, "support": [1, 3, 4, 8, 9, 12, 13, 15, 16, 20, 21, 31], "also": [1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15, 16, 17, 21, 25, 28, 29, 30, 31], "avail": [1, 3, 4, 8, 13, 18, 22, 24, 25, 31], "add": [1, 4, 12, 13, 14, 17, 18, 21, 22, 23, 24, 25, 27], "bootload": 1, "replac": [1, 21], "technologi": 1, "instead": [1, 4, 5, 14, 16, 18], "starter": 1, "combin": [1, 5, 9, 22, 27], "advantag": [1, 12, 14, 18], "That": [1, 10, 13, 14, 16], "mean": [1, 3, 9, 12, 16, 17, 18, 21], "onli": [1, 2, 3, 4, 9, 11, 13, 14, 15, 16, 17, 18, 19, 25], "sign": 1, "kernel": [1, 2, 3, 6, 13, 14, 15, 16, 17, 20, 22, 23, 25, 27], "distribut": [1, 2, 3, 4, 8, 9, 11, 17, 21, 28, 29, 30, 31], "huge": [1, 21], "benefit": [1, 9], "some": [1, 2, 3, 8, 9, 13, 14, 16, 25, 28, 29, 30, 31], "scenario": 1, "In": [1, 2, 3, 5, 8, 11, 12, 13, 14, 16, 17, 18, 21, 22, 25], "order": [1, 3, 5, 15, 25], "enabl": [1, 2, 4, 5, 7, 9, 16, 19, 23, 24, 25, 27], "method": [1, 8, 12, 14], "conf": [1, 3, 5, 7, 12, 13, 17, 22, 23, 24, 25, 27, 28, 29, 30, 31], "known": [1, 9, 16], "server": [1, 2, 3, 5, 7, 8, 9, 13, 15, 16, 18, 19, 24, 25, 27, 28, 29, 30, 31], "host": [1, 2, 5, 7, 16, 17, 19, 25, 27, 28, 29, 30, 31], "If": [1, 2, 3, 4, 7, 8, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 28, 29, 30, 31], "step": [1, 3, 17, 18, 22, 25], "signatur": [1, 3], "check": [1, 3, 4, 7, 12, 15, 17, 21, 24], "process": [1, 2, 3, 4, 8, 10, 11, 13, 16, 17, 18, 23, 25, 27, 31], "fail": [1, 4, 22], "typic": [1, 2, 3, 6, 8, 17], "includ": [1, 5, 10, 11, 12, 13, 14, 15, 17, 21, 22, 23, 25, 27], "kei": [1, 7, 10, 13, 23, 25], "oper": [1, 2, 3, 7, 8, 9, 15, 16, 18, 27, 28, 29, 30, 31], "each": [1, 4, 10, 12, 13, 14, 15, 17, 18, 19, 20, 22, 24, 28, 29, 30], "separ": [1, 11, 20], "execut": [1, 3, 15, 21, 22, 25], "extract": 1, "binari": [1, 4, 7, 22, 27], "contain": [1, 2, 4, 6, 9, 10, 11, 13, 14, 15, 16, 19, 20, 22, 23, 24, 25, 27], "unknown": [1, 12], "t": [1, 3, 4, 5, 11, 13, 15, 16, 19, 22, 31], "identifi": [1, 4, 17], "dure": [1, 2, 13, 15, 16, 31], "tftp": [1, 2, 5, 7, 8, 15, 17, 23, 24, 25, 28, 29, 30, 31], "phase": 1, "run": [1, 2, 3, 5, 7, 9, 10, 12, 13, 14, 15, 21, 23, 25, 27, 28, 29, 30, 31], "must": [1, 2, 3, 4, 5, 13, 14, 16, 17, 28, 29, 30, 31], "wwctl": [1, 2, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 23, 24, 25, 27, 28, 29, 30, 31], "shell": [1, 2, 3, 7, 21, 24], "leap15": [1, 17, 31], "5": [1, 3, 10, 12, 14, 17, 20, 24], "zypper": [1, 4, 5, 8, 31], "grub2": 1, "rocky9": 1, "dnf": [1, 3, 4, 8, 23, 24, 29, 30], "x64": 1, "x86_64": [1, 8, 11, 23, 24, 25], "These": [1, 2, 4, 8, 13, 22], "packag": [1, 3, 8, 22, 23, 24, 25, 31], "discoveri": 1, "modern": [1, 3, 28, 29, 30, 31], "possibl": [1, 3, 4, 5, 10, 11, 13, 16, 17, 18], "directli": [1, 2, 3, 4, 12, 15, 17, 18, 21, 22], "per": [1, 2, 7, 13], "flow": [1, 21], "diagram": 1, "follow": [1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 17, 19, 21, 24, 28, 29, 30, 31], "deliv": [1, 3], "initi": [1, 9, 15, 27], "via": [1, 2, 3, 5, 7, 8, 13, 15, 16, 21, 25, 28, 29, 30], "taken": 1, "": [1, 2, 3, 6, 7, 8, 9, 11, 13, 14, 15, 17, 20, 21, 22, 24, 27, 28, 29, 30, 31], "assign": [1, 10, 12, 25], "instal": [2, 3, 4, 7, 11, 16, 18, 25, 27], "put": [2, 14, 18, 25], "file": [2, 4, 5, 6, 7, 9, 12, 13, 15, 16, 17, 21, 22, 23, 25, 28, 29, 30, 31], "you": [2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31], "find": [2, 4, 8, 15, 19], "primari": [2, 10, 12, 17, 19], "exist": [2, 3, 4, 9, 13, 19], "current": [2, 3, 4, 8, 10, 22, 26], "version": [2, 3, 8, 9, 11, 12, 15, 16, 17, 18, 21, 24, 31], "4": [2, 3, 8, 11, 12, 15, 24, 25, 28, 31], "0": [2, 3, 8, 10, 11, 12, 17, 19, 22, 23, 24, 25, 28, 29, 30, 31], "ww_intern": [2, 24, 28, 29, 30, 31], "45": [2, 24, 28, 29, 30, 31], "ipaddr": [2, 10, 12, 17, 19, 22, 24, 25, 28, 29, 30, 31], "10": [2, 10, 12, 17, 19, 21, 25], "1": [2, 4, 8, 10, 11, 12, 13, 14, 15, 17, 20, 22, 23, 24, 25, 28, 29, 30, 31], "netmask": [2, 10, 12, 17, 22, 24, 25, 28, 29, 30, 31], "255": [2, 10, 12, 17, 24, 25, 28, 29, 30, 31], "252": [2, 10, 12, 17], "port": [2, 10, 17, 22, 24, 25, 28, 29, 30, 31], "9873": [2, 17, 24, 25, 28, 29, 30, 31], "secur": [2, 3, 9, 17, 24, 25, 27, 28, 29, 30, 31], "fals": [2, 10, 19, 24, 28, 29, 30, 31], "updat": [2, 3, 7, 12, 13, 15, 21, 24, 25, 28, 29, 30, 31], "interv": [2, 24, 25, 28, 29, 30, 31], "60": [2, 24, 25, 28, 29, 30, 31], "autobuild": [2, 24, 28, 29, 30, 31], "overlai": [2, 4, 5, 6, 7, 10, 15, 17, 19, 20, 23, 24, 25, 27, 28, 29, 30], "true": [2, 3, 4, 10, 12, 17, 19, 24, 25, 28, 29, 30, 31], "syslog": [2, 24, 28, 29, 30, 31], "dhcp": [2, 5, 7, 8, 13, 15, 17, 19, 24, 25, 27, 28, 29, 30, 31], "rang": [2, 3, 12, 13, 17, 20, 22, 24, 25, 28, 29, 30, 31], "start": [2, 3, 7, 22, 23, 24, 25, 27], "end": [2, 13, 17, 19, 24, 25, 28, 29, 30, 31], "systemd": [2, 3, 4, 5, 7, 13, 24, 25, 28, 29, 30, 31], "dhcpd": [2, 5, 7, 13, 17, 23, 24, 25, 29, 30, 31], "nf": [2, 3, 7, 8, 13, 18, 23, 24, 25, 28, 29, 30, 31], "export": [2, 3, 7, 13, 23, 24, 25, 28, 29, 30, 31], "path": [2, 3, 4, 13, 22, 24, 28, 29, 30, 31], "option": [2, 4, 5, 9, 11, 12, 13, 15, 16, 25, 28, 29, 30, 31], "rw": [2, 24, 28, 29, 30, 31], "sync": [2, 3, 18, 24, 28, 29, 30, 31], "mount": [2, 3, 4, 24, 25, 28, 29, 30, 31], "opt": [2, 24, 28, 29, 30, 31], "ro": [2, 24, 28, 29, 30, 31], "no_root_squash": [2, 24, 28, 29, 30, 31], "sourc": [2, 3, 9, 15, 19, 21, 26, 27, 29, 30, 31], "resolv": [2, 3, 7, 29, 30, 31], "dest": [2, 29, 30, 31], "readonli": [2, 29, 30, 31], "leav": 2, "long": [2, 13], "set": [2, 3, 4, 11, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 27], "appropri": [2, 6, 7, 8, 16, 19, 28, 29, 30, 31], "inform": [2, 3, 4, 12, 13, 14, 15, 17, 26], "specif": [2, 3, 4, 10, 11, 13, 14, 15, 16, 23, 25, 31], "match": [2, 3, 4, 12, 16], "ip": [2, 10, 12, 13, 14, 17, 19, 24, 25, 28, 29, 30, 31], "address": [2, 3, 9, 10, 12, 13, 14, 15, 19, 25, 27, 28, 29, 30, 31], "subnet": [2, 17], "mask": [2, 17], "abov": [2, 3, 10, 12, 16, 17, 25, 28, 29, 30, 31], "outsid": [2, 16], "failur": 2, "occur": [2, 8, 15, 17], "specifi": [2, 4, 5, 11, 12, 13], "want": [2, 3, 8, 10, 12, 13, 14, 21, 26, 31], "usual": [2, 17], "touch": 2, "thei": [2, 3, 10, 12, 15, 18, 21, 31], "explain": 2, "disabl": [2, 3, 5, 16, 23, 24, 25, 31], "so": [2, 3, 4, 7, 8, 12, 13, 14, 18, 21, 25, 26, 28, 29, 30, 31], "we": [2, 3, 6, 10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 26, 28, 29, 30, 31], "ve": [2, 3, 12, 14, 21, 23, 25, 28, 29, 30, 31], "test": [2, 3, 12, 14, 21, 27], "chang": [2, 5, 9, 13, 14, 15, 16, 17, 18, 27, 28, 29, 30, 31], "web": [2, 9, 21], "listen": [2, 23, 28], "It": [2, 3, 4, 10, 11, 13, 14, 16, 17, 21], "recommend": [2, 4, 8, 12, 13, 17], "misalign": 2, "expect": [2, 3, 4, 15], "how": [2, 3, 9, 10, 13, 15, 17, 21, 27], "contact": [2, 15], "when": [2, 3, 8, 10, 13, 15, 16, 18, 21, 31], "limit": [2, 3, 16, 21], "respond": [2, 15], "runtim": [2, 3, 10, 12, 15, 16, 18, 19, 31], "request": [2, 15, 16, 18, 26], "privileg": 2, "prevent": [2, 3], "non": [2, 23], "root": [2, 3, 4, 7, 9, 10, 12, 13, 14, 15, 16, 17, 19, 22, 23], "user": [2, 3, 7, 9, 13, 16, 18, 21, 22, 24, 25, 31], "sensit": [2, 3], "wwclient": [2, 13, 15, 16], "tcp": 2, "987": 2, "rebuild": [2, 3, 13], "reboot": [2, 3, 18, 28, 29, 30], "them": [2, 3, 7, 8, 11, 12, 13, 14, 15, 16, 21, 28, 29, 30, 31], "frequenc": 2, "second": [2, 12, 14, 17, 25], "client": [2, 3, 15, 25], "fetch": 2, "determin": 2, "whether": [2, 4, 22], "automat": [2, 3, 10, 11, 12, 14, 17, 18, 21, 22, 23, 25, 27], "rebuilt": [2, 3], "e": [2, 3, 8, 11, 12, 17, 18, 19, 20, 23, 25, 28], "g": [2, 3, 8, 11, 12, 17, 18, 19, 20, 23, 25, 28], "an": [2, 3, 4, 6, 8, 9, 10, 12, 13, 15, 16, 17, 18, 19, 23, 25, 26, 27, 28], "underli": [2, 4, 9], "special": 2, "appli": [2, 14, 20], "depend": [2, 4, 7, 9, 15, 17, 20, 23, 25, 27], "log": [2, 3, 4, 16], "go": [2, 8, 14, 15, 16, 18, 21, 22, 23, 25, 31], "written": [2, 7, 10, 13, 16, 19], "var": [2, 7, 24, 25, 28, 29, 30, 31], "warewulfd": [2, 7, 23, 24, 25, 28, 29, 30, 31], "up": [2, 3, 10, 13, 16, 17, 18, 19, 23, 25, 27], "exec": [2, 3, 15], "allow": [2, 3, 8, 13, 22, 25], "environ": [2, 3, 9, 18, 27], "prior": [2, 3, 22], "deploy": [2, 9], "databas": [2, 3], "flat": 2, "text": [2, 13, 15, 19, 31], "yaml": [2, 12], "command": [2, 3, 4, 5, 7, 11, 12, 13, 14, 15, 20, 22, 24, 27, 28, 29, 30, 31], "site": [2, 8], "infrastructur": [2, 9, 17], "being": [2, 3, 6, 9, 10, 13, 14, 16, 18, 31], "veri": [2, 9, 12, 14, 15, 26, 31], "light": 2, "weight": [2, 3, 13], "make": [2, 4, 5, 8, 15, 16, 18, 22, 23, 24, 25, 27, 28, 29, 30, 31], "easi": [2, 7, 9], "matter": 2, "what": [2, 11, 15, 16, 21], "paradigm": [2, 18], "document": [2, 16, 17, 19, 21, 22, 27], "detail": [2, 3, 10, 22], "format": [2, 4, 6, 13, 16, 23], "edit": [2, 12, 17, 19, 23, 25, 26, 28, 29, 30, 31], "time": [2, 3, 11, 13, 17, 18, 19, 21], "first": [2, 8, 12, 13, 16, 17, 28, 29, 30, 31], "attempt": [2, 7, 12, 15], "doe": [2, 3, 4, 13, 15, 16, 25], "alreadi": [2, 18], "valu": [2, 10, 12, 14, 15, 17, 19, 22], "none": 2, "exampl": [2, 3, 6, 12, 13, 14, 16, 17, 20, 25, 27], "respect": [2, 20], "defaultnod": 2, "devic": [2, 3, 4, 12, 13, 15, 19, 25, 28, 29, 30, 31], "dummi": [2, 17], "compil": [2, 13, 27, 31], "wwinit": [2, 4, 10, 12, 17, 22], "arg": [2, 17, 22], "quiet": [2, 10, 12, 13, 17], "crashkernel": [2, 10, 12, 17], "vga": [2, 10, 12, 17], "791": [2, 10, 12, 17], "net": [2, 3, 10, 12, 17, 23], "scheme": [2, 10, 12, 17], "v238": [2, 10, 12, 17], "init": [2, 10, 12, 13, 14, 15, 17, 22, 31], "sbin": [2, 10, 12, 15, 17, 22, 31], "initramf": [2, 6, 10, 12, 16, 17, 22], "ipx": [2, 3, 7, 10, 12, 14, 15, 17, 19, 22, 25, 27], "templat": [2, 3, 4, 5, 6, 7, 17, 25, 27, 31], "profil": [2, 4, 7, 11, 12, 13, 16, 17, 20, 22, 23, 24, 25, 27], "eth0": [2, 10, 12, 13, 23, 25, 28, 29, 30, 31], "ethernet": [2, 10, 12, 17, 28, 29, 30, 31], "There": [2, 3, 8, 9, 10, 11, 14, 17, 18, 28, 29, 30, 31], "should": [2, 3, 4, 7, 8, 9, 13, 14, 15, 17, 21, 25], "never": [2, 18], "local": [2, 15, 19, 22, 23], "paramet": [2, 10, 23, 25, 28, 29, 30], "either": [2, 5, 8, 13, 17, 20], "sinc": [3, 9], "over": [3, 8, 9, 10, 12, 15, 17, 18, 19], "20": [3, 9, 11, 12, 17], "ago": 3, "model": [3, 9, 11, 16, 18], "virtual": [3, 6, 9, 25, 27], "vnf": [3, 6, 11, 23, 25, 27], "imag": [3, 4, 6, 9, 11, 13, 15, 18, 20, 23, 24, 27], "golden": [3, 9], "except": [3, 4], "within": [3, 9, 11, 13, 18, 19, 22, 25], "directori": [3, 7, 13, 22, 27], "chroot": [3, 6], "hindsight": 3, "been": [3, 6, 7, 9, 11, 12, 18, 21, 28, 29, 30], "along": 3, "buzzword": 3, "just": [3, 9, 12, 14, 16, 17, 18, 21, 28, 29, 30, 31], "didn": [3, 4], "last": [3, 4, 9, 13, 14, 15], "6": [3, 12, 14, 20], "enterpris": [3, 8, 9], "lot": [3, 10, 14], "around": [3, 9, 18, 20], "v4": [3, 8, 9, 11, 12, 16, 18, 24, 28], "now": [3, 5, 7, 12, 14, 15, 17, 24, 28, 29, 30, 31], "integr": [3, 6, 17, 21], "ecosystem": 3, "facilit": [3, 13, 14, 18], "leverag": [3, 9, 16], "ani": [3, 6, 7, 8, 9, 11, 13, 14, 15, 16, 18, 21, 28, 29, 30], "wai": [3, 9, 10, 11, 13, 14, 16, 17, 18, 21], "still": [3, 11, 12, 16, 18, 28, 29, 30], "own": [3, 9, 11], "befor": [3, 4, 5, 8, 13, 26, 31], "understand": [3, 21], "while": [3, 9, 12, 13, 16, 18, 28, 29, 30, 31], "absolut": [3, 4, 13, 18], "provis": [3, 6, 9, 12, 13, 17, 19, 24, 27, 31], "bare": 3, "metal": [3, 4], "boot": [3, 4, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 23, 24, 25, 27, 28, 29, 30, 31], "entir": [3, 8, 18], "memori": [3, 18, 24, 25], "retain": 3, "about": [3, 21, 22, 27], "docker": [3, 6, 12, 23, 24, 25, 28, 29, 30, 31], "probabl": [3, 16, 21, 28], "most": [3, 8, 9, 12, 15, 16, 18], "recogniz": 3, "anoth": [3, 14, 18, 21], "gain": [3, 16], "traction": 3, "rhel": [3, 9, 23, 24, 25, 27], "util": [3, 8, 13, 16, 23, 24, 25, 28, 29, 30], "later": 3, "oci": [3, 6], "compliant": [3, 9], "here": [3, 7, 8, 10, 11, 14, 15, 16, 17, 21, 22, 24, 28, 29, 30, 31], "hub": [3, 6, 28, 29, 30, 31], "ghcr": [3, 23, 24, 25, 28, 29, 30], "io": [3, 6, 17, 23, 24, 25, 28, 29, 30], "rockylinux": [3, 24, 29, 30], "8": [3, 11, 12, 23, 25, 29], "rocki": [3, 9, 11, 12, 15, 27], "get": [3, 9, 13, 15, 16, 17, 19, 21, 22, 28], "copi": [3, 13, 18, 21], "blob": [3, 7], "d7f16ed6f451": 3, "done": [3, 11, 12, 13, 16, 21, 28, 29, 30, 31], "config": [3, 4, 12, 19, 24, 29, 30], "da2ca70704": 3, "write": [3, 7, 10, 18, 21, 22], "manifest": 3, "destin": 3, "store": [3, 7, 13], "info": [3, 24, 29, 30], "unpack": 3, "layer": [3, 16], "sha256": 3, "d7f16ed6f45129c7f4adb3773412def4ba2bf9902de42e86e77379a65d90a984": 3, "bootabl": [3, 15], "lighter": 3, "reason": [3, 14, 16, 26], "don": [3, 16], "debian": [3, 9, 15, 27], "properli": [3, 7, 28, 29, 30], "stuck": 3, "mode": [3, 13, 16, 19], "http": [3, 8, 15, 17, 21, 23, 24, 25, 28, 29, 30, 31], "com": [3, 8, 21, 22, 23, 24, 25, 28, 29, 30, 31], "u": [3, 4, 16, 22, 31], "would": [3, 6, 10, 15, 17, 18, 21], "password": [3, 22, 25], "protect": 3, "tl": 3, "do": [3, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 24, 28, 29, 30, 31], "choic": [3, 9, 17], "handl": 3, "credenti": 3, "environment": 3, "variabl": [3, 13, 22, 31], "login": [3, 23, 25], "pleas": [3, 15], "note": [3, 12, 17, 21, 28, 29, 30, 31], "warewulf_oci_usernam": 3, "warewulf_oci_password": 3, "warewulf_oci_nohttp": 3, "privateus": 3, "super": 3, "secret": 3, "token": [3, 16], "privatereg": 3, "share": [3, 24, 26, 28, 29, 30, 31], "show": [3, 10, 19, 31], "bash": [3, 23], "histori": 3, "save": 3, "tar": [3, 8], "archiv": [3, 13], "alpin": [3, 11], "latest": [3, 8, 12, 22, 31], "sandbox": [3, 27], "sudo": [3, 8, 16, 23, 24, 25, 28, 29, 30, 31], "At": [3, 4, 21, 28, 29, 30], "uid": [3, 13], "gid": [3, 13], "mismatch": 3, "print": [3, 19, 22, 28, 29, 30, 31], "out": [3, 9, 12, 15, 17, 18, 21, 26], "warn": [3, 22], "By": [3, 8, 13, 16, 25], "flag": [3, 12, 13, 14, 19], "advis": 3, "try": [3, 4, 15, 22], "syncron": 3, "passwd": [3, 13], "belon": 3, "trigger": 3, "With": [3, 9, 13, 19], "describ": [3, 8, 17, 21], "onc": [3, 7, 8, 11, 12, 13, 15, 16, 20, 21, 22, 28, 29, 30], "configur": [3, 5, 7, 8, 11, 13, 14, 15, 16, 17, 18, 20, 23, 24, 25, 27], "minim": 3, "insid": [3, 16, 25], "bin": [3, 22, 24, 29, 30], "sh": [3, 7, 13], "cat": [3, 24], "releas": [3, 9, 12, 23, 24, 25, 29, 30], "linux": [3, 9, 11, 15, 17, 18, 23, 27, 28, 31], "green": 3, "obsidian": 3, "exit": 3, "skip": [3, 18], "bind": 3, "tmp": [3, 24], "mnt": 3, "both": [3, 4, 12, 13, 14, 19, 20, 28, 29, 30, 31], "target": [3, 4, 16, 19, 22], "why": [3, 22, 27], "locat": [3, 8, 11, 23, 31], "alwai": [3, 9, 14, 16, 17, 21, 28, 29, 30, 31], "present": [3, 15, 19], "empti": [3, 13, 19], "prescrib": 3, "lsb": 3, "hierarchi": 3, "complet": [3, 13, 14, 16, 18, 23], "anyth": [3, 14], "static": [3, 13, 17, 19, 25, 28, 29, 30, 31], "object": [3, 27], "were": [3, 9, 18], "addit": [3, 13, 17, 26], "confirm": 3, "section": [3, 12, 14, 15, 26], "reduc": 3, "unnecessari": 3, "pattern": [3, 5, 31], "read": [3, 21, 22], "itself": [3, 4, 11, 16, 17], "usr": [3, 4, 24, 29, 30, 31], "geoip": 3, "filepath": 3, "script": [3, 10, 13, 18, 25], "container_exit": 3, "re": [3, 4, 5, 7, 15, 21, 22], "final": 3, "deliveri": [3, 17], "remov": [3, 13, 19, 22, 23], "cach": [3, 4, 13], "session": 3, "clean": [3, 24, 29, 30, 31], "repositori": [3, 8, 21, 26], "those": [3, 8, 15, 16, 28, 29, 30, 31], "previou": [3, 14, 16, 18, 21], "did": 3, "rpm": [3, 23, 24, 25, 27], "well": [3, 4, 7, 13, 16, 18, 19], "variant": [3, 23], "bootstrap": [3, 15, 17], "mini": 3, "yum": [3, 8, 23, 25], "someth": [3, 31], "like": [3, 8, 13, 14, 15, 16, 17, 18, 21, 25, 26, 28, 31], "installroot": 3, "newroot": 3, "basesystem": 3, "chkconfig": 3, "coreutil": 3, "e2fsprog": 3, "ethtool": 3, "filesystem": 3, "findutil": 3, "gawk": 3, "grep": [3, 12, 13, 14, 24], "initscript": 3, "iprout": 3, "iputil": 3, "pam": 3, "psmisc": 3, "rsync": 3, "sed": [3, 24], "setup": [3, 7, 10, 13, 16, 22, 27, 28, 29, 30, 31], "shadow": 3, "rsyslog": 3, "tzdata": 3, "word": 3, "zlib": 3, "less": [3, 31], "gzip": [3, 13], "openssh": 3, "dhclient": 3, "pciutil": 3, "vim": 3, "strace": 3, "croni": 3, "crontab": 3, "cpio": [3, 13], "wget": [3, 23], "ipmitool": [3, 23, 25], "networkmanag": [3, 13], "apt": [3, 28], "debootstrap": 3, "stabl": [3, 8], "ftp": 3, "org": [3, 8, 12, 24, 25, 31], "modifi": [3, 12, 13, 14, 17, 23, 25], "new": [3, 13, 14, 16, 22, 25, 27], "containernam": [3, 17, 22], "perform": [3, 9, 16, 17], "intens": 3, "applic": 3, "sever": [3, 4, 13, 17, 18], "recip": 3, "found": [3, 19], "github": [3, 8, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31], "tree": 3, "main": [3, 5, 8, 21, 28], "point": [3, 4, 13, 18, 22, 28, 29, 30], "ad": [3, 4, 13, 14, 17, 19, 27, 28, 29, 30, 31], "post": [3, 16, 21, 28, 29, 30, 31], "epel": [3, 24, 29, 30], "def": [3, 22], "dockerfil": 3, "opensus": [3, 12, 15, 27], "leap": [3, 27], "f": [3, 13, 23], "containerfil": [3, 12], "tag": [3, 8, 16, 17, 21, 22, 28], "ww": [3, 5, 7, 13, 17, 23, 25, 31], "localhost": [3, 24, 25], "o": [3, 13, 18, 22, 23, 25], "quit": 3, "small": [3, 12], "few": [3, 4, 14], "hundr": [3, 9, 14, 18], "megabyt": 3, "grow": [3, 18], "quickli": [3, 7], "larger": [3, 12, 17, 18], "issu": [3, 10, 13, 18, 26, 27], "imped": 3, "than": [3, 14, 17], "gigabyt": 3, "workaround": 3, "circumst": 3, "legaci": [3, 13], "bio": [3, 15], "32": 3, "bit": [3, 13, 16], "cannot": 3, "more": [3, 6, 8, 12, 17, 18, 19, 22, 26], "4gb": [3, 25], "decompress": 3, "compress": [3, 13], "report": 3, "No": [3, 19], "space": [3, 18], "left": [3, 26], "34182006": 3, "best": [3, 8, 9, 12, 14, 16], "switch": [3, 4, 8, 13, 16, 17, 28], "uefi": 3, "64": 3, "significantli": 3, "though": 3, "sometim": [3, 4, 19], "led": 3, "artifici": 3, "due": [3, 15, 16], "integ": 3, "critic": [3, 16, 17, 28, 29, 30, 31], "initrd": 3, "code": [3, 26, 27], "imgextract": 3, "rather": [3, 14, 16, 18], "firmwar": [3, 11, 15, 16], "hole": 3, "featur": [3, 5, 14, 16, 18, 21, 22, 26, 27], "reserv": 3, "1mb": 3, "block": [3, 4, 13, 19], "15mb": 3, "16mb": 3, "interfer": 3, "stateless": [3, 9, 13, 27], "Not": 3, "enough": 3, "error": [3, 7, 12, 22, 28, 29, 30], "container_nam": 3, "duplicated_container_nam": 3, "kind": 3, "look": [3, 14, 18, 25], "canari": 3, "partit": 4, "provid": [4, 8, 9, 12, 14, 15, 16, 17, 20, 21, 24, 26], "structur": [4, 31], "moment": [4, 21], "swap": [4, 18], "scratch": [4, 18, 27], "creation": [4, 11], "sgdisk": 4, "gdisk": 4, "gptfdisk": 4, "inspir": 4, "butan": 4, "where": [4, 8, 10, 19, 21], "list": [4, 10, 14, 17, 20, 22, 23, 25, 27, 28, 29, 30, 31], "hold": 4, "map": [4, 22, 25], "A": [4, 13, 17, 19, 22], "its": [4, 5, 8, 9, 12, 13, 15, 18], "bool": 4, "indic": 4, "tabl": [4, 10, 25], "overwritten": [4, 14], "desir": 4, "label": 4, "number": [4, 9, 13, 18, 28, 29, 30, 31], "omit": [4, 17, 28, 29, 30, 31], "without": [4, 13, 14, 18], "size": [4, 11, 27], "mib": [4, 11], "given": [4, 12, 13, 19, 21, 22], "maximum": 4, "should_exist": 4, "wipe_partition_entri": 4, "prefer": [4, 19, 22], "dev": [4, 24, 28], "partlabel": 4, "valid": [4, 10, 27], "btrf": 4, "ext3": 4, "ext4": 4, "xf": [4, 8], "wipe_filesystem": 4, "wipe": 4, "reli": [4, 16, 28, 29, 30, 31], "dbu": 4, "notif": 4, "necessari": [4, 12, 13, 15, 21], "json": [4, 24], "function": [4, 15, 20, 21, 22, 26, 31], "createignitionjson": 4, "ww4": [4, 5, 17], "call": [4, 6, 13, 14, 15, 19, 21, 22, 23, 31], "take": [4, 14, 16], "unit": [4, 18], "entri": [4, 12, 13, 19, 22, 31], "fstab": [4, 7, 23, 25], "no_auto": 4, "n01": 4, "disknam": 4, "vda": [4, 24], "diskwip": 4, "partnam": 4, "partcreat": 4, "fsname": 4, "fsformat": 4, "fspath": 4, "fswipe": 4, "1gig": 4, "partsiz": 4, "1024": 4, "partnumb": 4, "investig": 4, "log_level": 4, "debug": [4, 13, 18, 27], "rd": 4, "kernelarg": [4, 10, 12, 14], "abl": [4, 9, 12, 16, 18, 25], "verbos": 4, "journalctl": 4, "could": [4, 6, 18], "content": [4, 13, 19, 28, 29, 30, 31], "tinker": 4, "lib": [4, 24, 25, 28, 29, 30, 31], "dracut": 4, "modul": [4, 11, 15, 16], "d": [4, 5, 7, 10, 13, 17, 24, 29, 30], "30ignit": 4, "stage": [4, 8, 15, 28, 29, 30], "stdout": 4, "iter": [4, 9, 19], "until": [4, 12, 15, 24], "sure": [4, 5, 12, 13, 14, 25], "unmount": 4, "partial": 4, "success": 4, "experiment": 5, "isc": [5, 17, 28], "act": 5, "keep": 5, "dir": 5, "systemctl": [5, 7, 23, 24, 25, 28, 29, 30, 31], "stop": [5, 7, 16, 23, 25, 31], "instruct": [5, 22, 28, 29, 30, 31], "doesn": [5, 11], "h": [5, 13], "singular": [6, 23], "maintain": [6, 9, 18, 21], "disk": [6, 9, 15, 18, 23, 25, 27], "bundl": [6, 18], "registeri": 6, "respons": [6, 15], "administr": [6, 9, 18, 21], "feel": [6, 26], "term": 6, "descript": [6, 14, 24], "role": [6, 12], "gpu": [6, 11], "prefix": [6, 24, 29, 30, 31], "readi": [7, 15, 23, 24, 25], "associ": [7, 11, 12, 17], "To": [7, 12, 21, 23, 27, 28], "thing": [7, 13, 14, 15, 16, 18], "restart": [7, 28, 29, 30], "under": [7, 9, 12, 25, 27], "hostfil": 7, "ssh": [7, 13, 16, 20, 23, 25], "passwordless": 7, "addion": 7, "ssh_setup": [7, 13], "csh": [7, 13], "pxe": [7, 15, 16, 17, 23, 24, 25], "watch": [7, 23, 25, 28, 29, 30, 31], "output": [7, 12, 13, 21, 23, 25], "carefulli": 7, "portion": 7, "manual": 7, "regist": [7, 15, 28, 29, 30], "line": [7, 17, 19, 20, 22, 23, 25], "program": [7, 13], "statu": [7, 10, 21, 23, 25, 27], "result": [7, 13, 15, 17, 19], "unexpect": 7, "multipl": [8, 10, 11, 12, 16, 20, 27, 28, 29, 30, 31], "page": 8, "project": [8, 15, 21, 31], "part": [8, 13, 14, 28, 29, 30], "ci": [8, 9], "cd": [8, 21, 23, 24, 25, 28, 29, 30, 31], "obtain": [8, 13, 21], "download": [8, 13, 15, 16, 23, 25], "git_afcdb21": 8, "el8": [8, 27], "suse": [8, 9], "lp153": 8, "golang": [8, 23, 24, 25, 28, 29, 30], "wish": [8, 11, 12, 14, 15, 18, 28, 29, 30, 31], "recent": [8, 12], "dl": [8, 24], "groupinstal": [8, 24, 29, 30], "alongsid": 8, "select": [8, 13, 25], "direct": [8, 15, 21], "substitut": [8, 22], "curl": [8, 28], "lo": 8, "hpcng": 8, "v": [8, 22, 24], "gz": [8, 15], "collabor": 8, "revis": 8, "branch": [8, 24], "entitl": 8, "activ": [8, 16], "greatest": 8, "But": [8, 14, 16, 18], "forewarn": 8, "snapshot": 8, "guarante": 8, "product": [8, 17], "altern": 8, "area": 8, "pend": 8, "clone": [8, 21, 23, 24, 25, 28, 29, 30, 31], "checkout": [8, 24, 28], "vendor": [8, 9, 15, 16, 21], "compat": 8, "had": [9, 16, 18], "tenet": 9, "remain": 9, "same": [9, 10, 13, 18], "howev": [9, 12, 16], "state": [9, 10], "flexibl": [9, 18, 31], "overview": [9, 27], "produc": 9, "simplic": 9, "2001": 9, "becom": [9, 21, 24], "popular": 9, "open": [9, 15, 21, 22, 26, 27], "agnost": 9, "global": [9, 23], "commun": [9, 15, 16, 17, 27], "central": 9, "thousand": [9, 13, 18], "ident": [9, 13, 26], "pipelin": 9, "dockerhub": 9, "gitlab": 9, "high": [9, 16, 17, 25], "cloud": [9, 24], "hyperscal": 9, "princip": 9, "larg": [9, 14, 17], "mani": [9, 13, 14, 17, 18, 20, 21], "task": 9, "case": [9, 11, 16, 17, 18], "everyth": [9, 10, 13, 23], "render": [9, 13], "farm": 9, "kubernet": 9, "bring": [9, 13, 25], "experi": [9, 18, 25], "lightweight": [9, 12], "hobbyist": 9, "research": 9, "scientist": 9, "engin": [9, 13, 19], "becaus": [9, 16, 17, 18, 28, 29, 30, 31], "highli": [9, 12], "lab": 9, "graphic": [9, 23], "workstat": 9, "desk": 9, "supercomput": 9, "center": 9, "hardwar": [9, 16, 18, 27], "arm": 9, "x86": 9, "ato": 9, "dell": 9, "cento": [9, 25, 27], "selinux": [9, 13, 15, 23, 24, 25, 27, 28, 29, 30], "box": [9, 27], "rest": [9, 15, 17], "continu": [9, 13, 18, 21, 22], "bmc": 10, "discuss": [10, 13, 21], "common": [10, 16, 17, 31], "level": [10, 17], "field": [10, 12, 13, 14, 17], "individu": [10, 13, 18, 19, 28, 29, 30, 31], "ipmiwrit": [10, 12], "happen": [10, 19], "50": [10, 17, 22, 24, 28, 29, 30, 31], "overrid": [10, 12, 20, 22, 27], "outlin": 10, "ipmiaddr": [10, 12], "ipminetmask": [10, 12, 14], "ipmiport": [10, 12, 14], "623": 10, "ipmigatewai": [10, 12, 14], "ipmius": [10, 12], "ipmipass": [10, 12], "ipmiinterfac": [10, 12, 14], "lan": 10, "lanplu": 10, "ipmiescapechar": 10, "charact": 10, "down": [10, 22, 25], "id": [10, 12, 14, 17, 19, 22], "comment": [10, 12, 14, 17, 22], "sle": [10, 12, 27], "micro": [10, 12], "3": [10, 11, 12, 17, 20], "discover": [10, 12, 22, 23, 24, 25, 28, 29, 30, 31], "asset": [10, 12, 16], "onboot": [10, 12, 17, 25], "netdev": [10, 12, 17, 19, 22, 23, 24, 25, 28, 29, 30, 31], "hwaddr": [10, 12, 19], "ipaddr6": [10, 12, 19], "gatewai": [10, 12, 19, 22, 24, 25, 28, 29, 30, 31], "mtu": [10, 12], "n001": [10, 12], "kerneloverrid": [10, 11, 12], "tw": [10, 12], "11": [10, 12], "22": [10, 12, 17, 25], "33": [10, 12], "44": [10, 12], "55": [10, 12, 22], "66": [10, 12], "2": [10, 11, 12, 17, 20, 22, 25], "connecton": 10, "usernam": [10, 21, 22], "192": [10, 24, 28, 29, 30, 31], "168": [10, 24, 28, 29, 30, 31], "hwadmin": 10, "n002": [10, 12], "12": [10, 27], "n003": [10, 12], "13": [10, 11], "n004": [10, 12], "14": 10, "cycl": [10, 19], "turn": [10, 20, 27, 28, 29, 30], "off": [10, 20, 25, 27], "reset": [10, 15], "shutdown": [10, 23], "gracefulli": 10, "serial": 10, "sol": 10, "easiest": 11, "particular": [11, 12, 14, 18], "see": [11, 12, 14, 15, 21, 24, 26, 28, 29, 30, 31], "modif": [11, 19], "05": 11, "jun": 11, "23": 11, "02": 11, "mdt": 11, "17": 11, "9": [11, 27, 30], "18": 11, "372": 11, "el8_6": 11, "jan": 11, "48": [11, 22], "mst": 11, "06": 11, "apr": 11, "09": 11, "40": [11, 24], "gib": 11, "notic": 11, "contian": 11, "introduc": 11, "previous": 11, "made": [11, 16, 21], "hard": [11, 16, 18, 25], "custom": [11, 13, 14, 16], "driver": 11, "OFED": 11, "unam": [11, 23, 25], "r": [11, 13, 23, 25], "305": 11, "el8_4": 11, "mention": 12, "persist": [12, 13, 17, 25], "prone": 12, "backend": 12, "datastor": 12, "000": 12, "yield": 12, "latenc": [12, 17], "felt": 12, "toler": 12, "increment": 12, "n00": 12, "n": [12, 13, 14], "n0000": [12, 14, 23, 25, 28, 29, 30, 31], "complic": 12, "compris": 12, "descriptor": 12, "domain": 12, "cluster01": [12, 14], "assum": [12, 28, 29, 30, 31], "equival": 12, "glob": 12, "string": [12, 16, 19, 22], "valuabl": [12, 18], "full": [12, 18, 24, 27, 28, 29, 30, 31], "172": 12, "16": [12, 15], "parenthesi": 12, "overridden": 12, "grant": 12, "usabl": 12, "minimum": 12, "reachabl": 12, "help": [12, 14, 15, 16, 18, 20, 21, 22, 28, 29, 30, 31], "y": [12, 13, 14, 19, 23, 24, 25, 31], "And": [12, 13, 14, 16, 26], "beyond": [12, 17], "illustr": 12, "import": [12, 17, 21, 23, 24, 25, 27, 28, 29, 30, 31], "tumblewe": 12, "registri": [12, 31], "scienc": [12, 31], "dc": 12, "pick": 12, "bond": 12, "link": [12, 15, 19, 21], "aggreagt": 12, "netnam": [12, 17, 25, 31], "bond0_member_1": 12, "eth2": 12, "slave": 12, "bond0_member_2": 12, "eth3": 12, "bond0": 12, "9000": 12, "member": [12, 21], "interterfac": 12, "_": [12, 22], "ib0": 12, "aa": 12, "bb": 12, "cc": 12, "dd": 12, "ee": 12, "ff": 12, "iband": 12, "infiniband": [12, 17], "discov": 12, "against": 12, "sort": 12, "lexic": 12, "clear": 12, "unset": 12, "undef": [12, 14, 22], "li": 13, "problem": [13, 18], "solv": [13, 18], "hostnam": [13, 19, 24], "Or": 13, "peopl": 13, "choos": [13, 15, 25], "heavi": 13, "solut": [13, 17], "period": [13, 31], "nesscesari": 13, "besid": 13, "wick": 13, "el": 13, "udev": 13, "rule": [13, 25, 31], "loop": [13, 31], "warwulf": 13, "ipmi": [13, 17, 22, 27], "regular": [13, 22], "basi": 13, "minut": [13, 15], "addition": [13, 16], "authorized_kei": 13, "dynam": [13, 17, 19], "slurm": 13, "unlik": 13, "backup": [13, 19], "wwbackup": [13, 19], "suffix": [13, 19, 31], "subsequ": 13, "won": [13, 15, 19], "overwrit": [13, 14], "scrip": 13, "manipul": 13, "receiv": 13, "welcom": [13, 27], "mkdir": [13, 24, 28], "systemoverlai": [13, 14, 17, 22], "insert": 13, "condit": 13, "manner": 13, "tell": [13, 16], "pars": 13, "attribut": [13, 14, 16, 22, 27], "drop": [13, 25], "ownership": 13, "permiss": 13, "nodepattern": 13, "argument": [13, 14, 31], "interpret": 13, "restrict": 13, "filenam": [13, 15, 19], "subcommand": [13, 20], "forc": 13, "parent": 13, "m": [13, 21, 23, 25], "p": [13, 23, 24, 25], "header": 13, "noupdat": 13, "place": [13, 21], "l": [13, 23, 25, 31], "shown": 13, "displai": [13, 22], "q": 13, "nodenam": [13, 15], "mandatori": 13, "suppress": 13, "redund": 14, "inherit": 14, "handi": 14, "hw": [14, 15, 28, 29, 30, 31], "mac": [14, 15], "view": [14, 28, 29, 30, 31], "summari": [14, 27], "runtimeoverlai": [14, 17, 22], "ipmiipaddr": 14, "ipmiusernam": 14, "demonstr": [14, 17], "let": [14, 21], "test_profil": 14, "lastli": 14, "our": [14, 16, 18, 21, 26], "addprofil": 14, "verifi": [14, 19, 25], "delet": 14, "supersed": [14, 28, 29, 30, 31], "deal": 14, "subset": 14, "preced": 14, "noth": [14, 16], "inher": 14, "fix": [14, 21, 22, 31], "sub": [14, 20], "might": [14, 17, 18, 22, 25, 28, 29, 30], "cluster_nam": 14, "preconfigur": 15, "ask": 15, "rack": 15, "credit": 15, "certifi": 15, "stack": 15, "ensur": [15, 16, 23, 25, 28, 29, 30, 31], "rom": 15, "finish": 15, "bootp": 15, "reach": 15, "els": [15, 22], "unifi": 15, "background": [15, 27], "daemon": [15, 23, 25], "sleep": 15, "exactli": [15, 18, 21], "whole": 15, "sent": 15, "lastseen": 15, "c001": 15, "runtime_overlai": 15, "img": [15, 23], "system_overlai": 15, "thank": 15, "between": [15, 17], "counter": 15, "exterior": 16, "gushi": 16, "interior": 16, "free": 16, "roam": 16, "tend": [16, 26], "posix": 16, "practic": [16, 28], "kill": 16, "vpn": 16, "bastion": 16, "factor": [16, 18], "authent": 16, "mfa": 16, "malici": 16, "access": [16, 25], "onion": 16, "accur": 16, "predomin": 16, "ground": 16, "further": [16, 21], "certain": 16, "parallel": [16, 18, 20], "librari": 16, "lower": 16, "threshold": 16, "strive": 16, "blocker": 16, "enforc": [16, 24, 28, 29, 30], "firewal": [16, 17, 19, 23, 25, 28, 29, 30], "fulli": 16, "whatev": 16, "hand": [16, 31], "ramf": 16, "extend": [16, 17], "tmpf": 16, "sysconfig": [16, 23, 25, 31], "insecur": 16, "land": 16, "spoof": 16, "raw": 16, "materi": 16, "inspect": [16, 24], "transfer": [16, 17], "trust": [16, 17], "enact": 16, "vlan": [16, 25], "consult": 16, "physic": 16, "simpli": 16, "assetkei": [16, 22], "shim": 16, "grub": [16, 27], "distributor": 16, "compli": 16, "load": [16, 22, 24], "postur": 16, "perhap": 16, "increas": 16, "provision": 16, "organiz": 16, "polici": 16, "job": [16, 18], "predetermin": 17, "asid": 17, "layout": 17, "pai": 17, "attent": 17, "temporari": 17, "band": 17, "conflict": 17, "perspect": 17, "impli": 17, "least": 17, "revers": 17, "nat": [17, 25], "scope": [17, 22], "speed": 17, "low": 17, "data": [17, 19], "inter": 17, "three": 17, "protocol": 17, "accomplish": [17, 18], "intern": [17, 22], "100": [17, 28, 29, 30, 31], "organ": 17, "alloc": 17, "divid": 17, "router": 17, "achiv": 17, "dnsmasq": [17, 27], "accordingli": 17, "trivial": 17, "deliverynet": 17, "250": 17, "deliver1": 17, "nettagadd": 17, "dynstart": 17, "dynend": 17, "deliver2": 17, "definit": [17, 18], "primarynetdev": [17, 22], "allnod": [17, 19], "eq": [17, 19], "max": 17, "leas": 17, "120": 17, "6h": 17, "carri": 17, "pool": 18, "necess": 18, "back": [18, 21], "2000": 18, "becam": 18, "appar": 18, "Of": 18, "cours": [18, 22], "overcom": 18, "pretti": 18, "earli": 18, "homogen": 18, "drift": 18, "harder": 18, "onto": 18, "drive": [18, 25], "autom": [18, 22], "bulk": 18, "iso": [18, 23, 25], "usb": 18, "thumb": 18, "obvious": [18, 21], "toolkit": 18, "optim": 18, "past": 18, "ever": 18, "realiz": 18, "think": 18, "liveo": 18, "liveiso": 18, "softwar": [18, 26], "fall": 18, "neighbor": 18, "abil": 18, "hybrid": 18, "core": 18, "piec": 18, "overlaid": 18, "obsolet": 18, "easier": 18, "far": 18, "simplest": 18, "convert": 19, "auto": 19, "popul": 19, "demand": 19, "tmpl": 19, "come": [19, 25, 28, 29, 30, 31], "soon": 19, "break": [19, 22], "front": 19, "element": 19, "arrai": [19, 31], "devnam": 19, "inc": 19, "dec": 19, "acc": 19, "foo": 19, "index": 19, "baar": 19, "ifcfg": [19, 25], "networknam": 19, "xml": [19, 23], "buildhost": 19, "buildtim": 19, "buildsourc": 19, "autogener": 19, "ipv4": 19, "arp": 19, "ipcidr": 19, "rout": 19, "nexthop": 19, "ipv6": 19, "privaci": 19, "accept": 19, "redirect": 19, "snippet": 19, "emit": 19, "getb": 19, "isn": 19, "intend": [19, 21], "behavior": 19, "substr": 19, "x": [19, 23], "b": [19, 21], "c": [19, 23, 25, 31], "payload": 19, "primarili": 20, "major": 20, "compon": 20, "power": [20, 27], "basic": [20, 23, 25, 27, 29, 30, 31], "syntax": 20, "express": 20, "comma": 20, "numer": 20, "expand": 20, "node1": 20, "node2": 20, "node3": 20, "node5": 20, "node6": 20, "challeng": 21, "grate": 21, "offer": 21, "endeavor": 21, "greatli": 21, "appreci": 21, "onlin": [21, 25], "great": 21, "talk": 21, "workspac": 21, "bug": [21, 22], "pr": 21, "offici": 21, "md": 21, "conduct": 21, "account": [21, 25], "git": [21, 23, 24, 25, 26, 28, 29, 30, 31], "isol": 21, "On": [21, 23, 25, 28, 29, 30, 31], "nut": 21, "happi": 21, "commit": 21, "changed1": 21, "changed2": 21, "messag": [21, 28], "good": [21, 26, 28], "getconfig": 21, "csv": 21, "doc": [21, 24, 26, 29, 30], "close": 21, "referenc": 21, "merg": 21, "futur": 21, "hopefulli": 21, "revert": 21, "gui": 21, "regardless": 21, "convers": 21, "thread": 21, "suggest": [21, 26], "exact": 21, "date": [21, 31], "changesinto": 21, "event": 21, "remot": 21, "debugg": 22, "potent": 22, "guid": 22, "makefil": 22, "codebas": 22, "troubl": 22, "track": 22, "cmd": [22, 28, 29, 30], "dlv": 22, "test_getallnodeinfodefault": 22, "pkg": 22, "breakpoint": 22, "0x26c0d0": 22, "nodeyaml_test": 22, "51": 22, "paus": 22, "hit": 22, "goroutin": 22, "35": 22, "total": 22, "pc": 22, "46": 22, "assert": 22, "nodeyaml": 22, "test_nod": 22, "47": 22, "equal": 22, "49": 22, "func": 22, "52": 22, "writeerr": 22, "writetestconfigfil": 22, "53": 22, "54": 22, "nil": 22, "56": 22, "defer": 22, "mark": 22, "proce": 22, "potenti": 22, "move": 22, "contextu": 22, "nodeinfo": 22, "417": 22, "0x267f18": 22, "newnodeinfo": 22, "19": 22, "412": 22, "defaultnodeconf": 22, "413": 22, "setdeffrom": 22, "414": 22, "415": 22, "416": 22, "normal": [22, 31], "nodeconf": 22, "418": 22, "419": 22, "420": 22, "len": 22, "421": 22, "setslic": 22, "422": 22, "0x267f24": 22, "423": 22, "424": 22, "425": 22, "0x267f3c": 22, "426": 22, "setfrom": 22, "0x267fec": 22, "427": 22, "428": 22, "429": 22, "430": 22, "defaultnetdevconf": 22, "431": 22, "0x268000": 22, "432": 22, "433": 22, "434": 22, "435": 22, "cap": 22, "altvalu": 22, "clusternam": 22, "kernelentri": 22, "0x4000158370": 22, "0x40001583c8": 22, "ipmientri": 22, "0x40001b6600": 22, "0x40001b6658": 22, "0x40001b66b0": 22, "0x40001b6708": 22, "0x40001b6760": 22, "0x40001b67b8": 22, "0x40001b6810": 22, "0x40001b6868": 22, "netdeventri": 22, "my": [23, 25], "desktop": [23, 25], "mirror": 23, "mobap": 23, "edu": 23, "2003": 23, "qemu": 23, "prealloc": 23, "metadata": [23, 24], "qcow2": 23, "32g": 23, "vm": [23, 24, 25], "virt": [23, 24], "centos7": [23, 25], "ram": 23, "8192": [23, 24], "vnc": 23, "noautoconsol": 23, "rhel7": [23, 25], "languag": [23, 25], "vi": [23, 25], "firewalld": [23, 24, 25, 27, 31], "virsh": 23, "destroi": 23, "fedora": 23, "prerequisit": [23, 25], "gpgme": [23, 24, 25, 29, 30], "devel": [23, 24, 25, 29, 30, 31], "libassuan": [23, 24, 25, 28, 29, 30], "repo": [23, 24, 25], "ctrliq": [23, 25], "ctrl": [23, 25], "singularityplu": [23, 25], "endpoint": [23, 25], "ser": 23, "approprit": [23, 25], "pull": [23, 25, 26, 27], "setdefault": [23, 25, 31], "k": [23, 25], "ww_server_subnet_mask": 23, "ww_server_ip": 23, "n0000_ip": 23, "review": [23, 25, 27], "hello_world": [23, 25, 31], "machin": [24, 25, 27], "testb": 24, "intel": 24, "vt": 24, "amd": 24, "lscpu": 24, "lsmod": 24, "ccp": 24, "118784": 24, "kvm_amd": 24, "1105920": 24, "irqbypass": 24, "16384": 24, "libguestf": 24, "virtio": 24, "win": 24, "guestf": 24, "icon": 24, "reg": 24, "top": 24, "libvirtd": 24, "usermod": 24, "ag": 24, "9090": 24, "socket": 24, "hashicorp": 24, "crb": [24, 30], "plugin": 24, "eof": 24, "20230513": 24, "url": 24, "pub": 24, "number_of_nod": 24, "env": 24, "box_vers": 24, "private_network": 24, "200": [24, 25, 28, 29, 30, 31], "254": 24, "libvirt__network_nam": 24, "libvirt__dhcp_en": 24, "synced_fold": 24, "nfs_version": 24, "nfs_udp": 24, "cpu_mod": 24, "passthrough": 24, "machine_virtual_s": 24, "inlin": 24, "growpart": 24, "xfs_growf": 24, "vda5": 24, "bindir": [24, 29, 30], "sysconfdir": [24, 29, 30, 31], "datadir": [24, 29, 30], "localstatedir": [24, 29, 30, 31], "sharedstatedir": [24, 29, 30], "mandir": [24, 29, 30], "man": [24, 29, 30], "infodir": [24, 29, 30], "docdir": [24, 29, 30], "srvdir": [24, 29, 30], "tftpdir": [24, 29, 30, 31], "tftpboot": [24, 25, 28, 29, 30], "systemddir": [24, 29, 30], "bashcompdir": [24, 29, 30], "bash_complet": [24, 29, 30], "firewallddir": [24, 29, 30], "wwclientdir": [24, 29, 30], "tee": 24, "99": [24, 28, 29, 30, 31], "execstart": 24, "ye": [24, 25, 28, 29, 30], "eth1": 24, "n0001": 24, "101": 24, "n0002": 24, "102": 24, "n000": 24, "autostart": 24, "boot_network": 24, "wait": 24, "warewlf": 25, "turnoff": 25, "24": 25, "vboxmanag": 25, "natnetwork": 25, "wwnatnetwork": 25, "7": [25, 27], "wwdev": [25, 27], "adapt": 25, "suffici": 25, "sl7": 25, "optic": 25, "15": [25, 27], "forward": 25, "127": 25, "2222": 25, "guest": 25, "prompt": 25, "upgrad": 25, "v2": 25, "enp0s9": 25, "bootproto": 25, "150": 25, "tftproot": [25, 31], "instanc": 25, "bzimag": 25, "floppi": 25, "consol": [25, 27], "dilemma": 26, "focu": 26, "love": 26, "nobodi": 26, "contribut": 26, "rais": [26, 27], "improv": 26, "send": 26, "docusauru": 26, "procedur": 26, "introduct": 27, "vision": 27, "hostlist": 27, "syncus": 27, "duplic": 27, "db": 27, "un": 27, "cascad": [27, 28, 29, 30, 31], "effect": [27, 28], "ignit": 27, "troubleshoot": 27, "usag": [27, 28, 29, 30, 31], "el9": 27, "join": 27, "vet": 27, "suit": 27, "delv": 27, "vagrant": 27, "vagrantfil": 27, "spin": 27, "kvm": 27, "master1": 27, "virtualbox": 27, "glossari": 27, "tftpd": 28, "hpa": 28, "concern": 28, "intarfac": 28, "dpkg": 28, "reconfigur": 28, "enter": 28, "enp2s0": 28, "essenti": 28, "unzip": 28, "libnf": 28, "libgpgm": 28, "zone": [28, 29, 30], "reload": [28, 29, 30], "perman": [28, 29, 30], "fresh": [28, 29, 30], "context": [28, 29, 30], "restorecon": [28, 29, 30], "rv": [28, 29, 30], "affect": [28, 29, 30], "accord": [28, 29, 30, 31], "uniqu": [28, 29, 30, 31], "dot": [28, 29, 30, 31], "notat": [28, 29, 30, 31], "powertool": 29, "devel_basi": 31, "srv": 31, "wrong": 31, "mv": 31, "warewulf4": 31, "openbuild": 31, "paramat": 31, "dhcp_interfac": 31, "prepopul": 31, "abid": 31, "extrem": 31, "acceler": 31}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"background": 0, "boot": 1, "manag": [1, 3, 4, 11], "ipx": 1, "grub": 1, "secur": [1, 16], "instal": [1, 5, 8, 17, 22, 23, 24, 28, 29, 30, 31], "shim": 1, "efi": 1, "http": 1, "warewulf": [2, 7, 8, 9, 13, 20, 21, 23, 24, 28, 29, 30, 31], "configur": [2, 4, 12, 28, 29, 30, 31], "conf": 2, "node": [2, 10, 11, 12, 14, 15, 19, 24, 28, 29, 30, 31], "default": [2, 23, 28, 29, 30, 31], "directori": 2, "contain": [3, 12, 28, 29, 30, 31], "tool": 3, "import": [3, 11, 13, 18], "privat": 3, "registri": 3, "local": 3, "file": [3, 19], "syncus": 3, "list": [3, 11, 12, 13], "all": [3, 11], "make": [3, 21], "chang": [3, 21], "To": [3, 14], "exclud": 3, "from": [3, 31], "prepar": 3, "build": [3, 13, 23, 28, 29, 30, 31], "creat": [3, 13, 19, 23, 24], "scratch": 3, "A": 3, "your": [3, 21], "host": [3, 13, 24], "us": [3, 13, 14, 22], "apptain": 3, "podman": 3, "size": 3, "consider": 3, "duplic": 3, "disk": 4, "requir": [4, 24], "rocki": [4, 8, 24, 29, 30], "linux": [4, 8, 24, 29, 30], "opensus": [4, 8, 31], "leap": [4, 8, 31], "storag": 4, "object": 4, "ignit": 4, "implement": 4, "exampl": [4, 19, 22], "troubleshoot": 4, "dnsmasq": 5, "usag": 5, "glossari": 6, "initi": 7, "system": [7, 13, 17, 24, 28, 29, 30, 31], "servic": [7, 28, 29, 30, 31], "log": 7, "binari": 8, "rpm": 8, "8": 8, "compil": 8, "sourc": 8, "code": [8, 21, 22], "releas": 8, "tarbal": 8, "git": 8, "runtim": [8, 13], "depend": [8, 28, 29, 30, 31], "introduct": [9, 14], "The": [9, 12, 15], "vision": 9, "about": 9, "featur": 9, "ipmi": 10, "set": [10, 12, 28, 29, 30, 31], "review": 10, "profil": [10, 14, 28, 29, 30, 31], "view": 10, "onli": 10, "power": 10, "command": [10, 19], "consol": 10, "kernel": [11, 12, 24, 28, 29, 30, 31], "overrid": [11, 14], "db": 12, "ad": 12, "new": [12, 21], "sever": 12, "name": 12, "attribut": 12, "": 12, "imag": 12, "network": [12, 17, 23], "addit": 12, "discoveri": 12, "un": 12, "overlai": [13, 31], "defin": 13, "wwinit": 13, "gener": 13, "combin": 13, "templat": [13, 19], "chmod": 13, "chown": 13, "delet": 13, "edit": 13, "show": 13, "an": [14, 21], "multipl": [14, 17, 19], "cascad": 14, "how": 14, "effect": 14, "provis": [15, 16, 18], "hardwar": 15, "setup": [15, 17, 24], "process": 15, "statu": 15, "selinux": 16, "summari": 16, "control": [17, 20, 28, 29, 30, 31], "server": [17, 23], "oper": 17, "address": 17, "stateless": 18, "why": 18, "i": 18, "overview": 18, "comment": 19, "rang": 19, "increment": 19, "variabl": 19, "In": 19, "loop": 19, "decrement": 19, "access": 19, "tag": 19, "special": 19, "includ": [19, 28, 29, 30], "includefrom": 19, "includeblock": 19, "abort": 19, "nobackup": 19, "split": 19, "specif": [19, 22], "wwctl": 20, "hostlist": 20, "contribut": [21, 27], "join": 21, "commun": 21, "slack": 21, "rais": 21, "issu": 21, "step": 21, "1": 21, "fork": 21, "repo": 21, "2": [21, 24], "checkout": 21, "branch": 21, "3": 21, "4": 21, "push": 21, "5": 21, "submit": 21, "pull": [21, 28, 29, 30, 31], "request": 21, "6": 21, "keep": 21, "sync": 21, "debug": 22, "valid": 22, "vet": 22, "run": 22, "full": 22, "test": 22, "suit": 22, "delv": 22, "against": 22, "session": 22, "develop": [23, 24, 25], "environ": [23, 24, 25], "kvm": [23, 24], "cento": 23, "7": 23, "virtual": [23, 24], "machin": 23, "under": 23, "turn": 23, "off": 23, "dhcp": 23, "master1": 23, "wwdev": 23, "vagrant": 24, "cpu": 24, "h": 24, "w": 24, "support": 24, "modul": 24, "9": 24, "qemu": 24, "libvirt": 24, "cockpit": 24, "option": 24, "plug": 24, "reload": 24, "box": 24, "vagrantfil": 24, "sandbox": 24, "spin": 24, "up": [24, 28, 29, 30, 31], "head": 24, "comput": 24, "virtualbox": 25, "document": 26, "user": 27, "guid": 27, "content": 27, "quickstart": [27, 28, 29, 30, 31], "debian": 28, "12": 28, "basic": 28, "firewalld": [28, 29, 30], "start": [28, 29, 30, 31], "enabl": [28, 29, 30, 31], "automat": [28, 29, 30, 31], "vnf": [28, 29, 30, 31], "add": [28, 29, 30, 31], "el8": 29, "rhel": [29, 30], "el9": 30, "sle": 31, "15": 31, "open": 31}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Background": [[0, "background"]], "Boot Management": [[1, "boot-management"]], "Booting with iPXE": [[1, "booting-with-ipxe"]], "Booting with GRUB": [[1, "booting-with-grub"]], "Secure boot": [[1, "secure-boot"]], "Install shim and efi": [[1, "install-shim-and-efi"]], "http boot": [[1, "http-boot"]], "Warewulf Configuration": [[2, "warewulf-configuration"]], "warewulf.conf": [[2, "warewulf-conf"]], "nodes.conf": [[2, "nodes-conf"]], "defaults.conf": [[2, "defaults-conf"]], "Directories": [[2, "directories"]], "Container Management": [[3, "container-management"]], "Container Tools": [[3, "container-tools"]], "Importing Containers": [[3, "importing-containers"]], "Private Registry": [[3, "private-registry"]], "Local Files": [[3, "local-files"]], "Syncuser": [[3, "syncuser"]], "Listing All Imported Containers": [[3, "listing-all-imported-containers"]], "Making Changes To Containers": [[3, "making-changes-to-containers"]], "Excluding Files from a Container": [[3, "excluding-files-from-a-container"]], "Preparing a container for build": [[3, "preparing-a-container-for-build"]], "Creating Containers From Scratch": [[3, "creating-containers-from-scratch"]], "Building A Container From Your Host": [[3, "building-a-container-from-your-host"]], "Building A Container Using Apptainer": [[3, "building-a-container-using-apptainer"]], "Building A Container Using Podman": [[3, "building-a-container-using-podman"]], "Container Size Considerations": [[3, "container-size-considerations"]], "Duplicating a container": [[3, "duplicating-a-container"]], "Disk Management": [[4, "disk-management"]], "Requirements": [[4, "requirements"]], "Rocky Linux": [[4, "rocky-linux"]], "openSuse Leap": [[4, "opensuse-leap"], [8, "opensuse-leap"]], "Storage objects": [[4, "storage-objects"]], "Ignition Implementation": [[4, "ignition-implementation"]], "Example disk configuration": [[4, "example-disk-configuration"]], "Troubleshooting": [[4, "troubleshooting"]], "Dnsmasq": [[5, "dnsmasq"]], "Usage": [[5, "usage"]], "Installation": [[5, "installation"]], "Glossary": [[6, "glossary"]], "Warewulf Initialization": [[7, "warewulf-initialization"]], "System Services": [[7, "system-services"]], "Warewulf Service": [[7, "warewulf-service"]], "Logs": [[7, "logs"]], "Warewulf Installation": [[8, "warewulf-installation"]], "Binary RPMs": [[8, "binary-rpms"]], "Rocky Linux 8": [[8, "rocky-linux-8"]], "Compiled Source code": [[8, "compiled-source-code"]], "Release Tarball": [[8, "release-tarball"]], "Git": [[8, "git"]], "Runtime Dependencies": [[8, "runtime-dependencies"]], "Introduction": [[9, "introduction"]], "The Warewulf Vision": [[9, "the-warewulf-vision"]], "About Warewulf": [[9, "about-warewulf"]], "Features": [[9, "features"]], "IPMI": [[10, "ipmi"]], "IPMI Settings": [[10, "ipmi-settings"]], "Reviewing Settings": [[10, "reviewing-settings"]], "Profile View": [[10, "profile-view"]], "Node View": [[10, "node-view"]], "Review Only IPMI Settings": [[10, "review-only-ipmi-settings"]], "Power Commands": [[10, "power-commands"]], "Console": [[10, "console"]], "Kernel Management": [[11, "kernel-management"]], "Node Kernels": [[11, "node-kernels"]], "Kernel Overrides": [[11, "kernel-overrides"]], "Listing All Imported Kernels": [[11, "listing-all-imported-kernels"]], "Node Configuration": [[12, "node-configuration"]], "The Node Configuration DB": [[12, "the-node-configuration-db"]], "Adding a New Node": [[12, "adding-a-new-node"]], "Adding several nodes": [[12, "adding-several-nodes"]], "Node Names": [[12, "node-names"]], "Listing Nodes": [[12, "listing-nodes"]], "Setting Node Attributes": [[12, "setting-node-attributes"]], "Configuring the Node\u2019s Container Image": [[12, "configuring-the-node-s-container-image"]], "Configuring the Node\u2019s Kernel": [[12, "configuring-the-node-s-kernel"]], "Configuring the Node\u2019s Network": [[12, "configuring-the-node-s-network"]], "Additional networks": [[12, "additional-networks"]], "Node Discovery": [[12, "node-discovery"]], "Un-setting Node Attributes": [[12, "un-setting-node-attributes"]], "Warewulf Overlays": [[13, "warewulf-overlays"], [31, "warewulf-overlays"]], "Defined Overlays": [[13, "defined-overlays"]], "System or wwinit overlay": [[13, "system-or-wwinit-overlay"]], "Runtime Overlay or generic Overlay": [[13, "runtime-overlay-or-generic-overlay"]], "Host Overlay": [[13, "host-overlay"]], "Combining Overlays": [[13, "combining-overlays"]], "Templates": [[13, "templates"]], "Using Overlays": [[13, "using-overlays"]], "Build": [[13, "build"]], "Chmod": [[13, "chmod"]], "Chown": [[13, "chown"]], "Create": [[13, "create"]], "Delete": [[13, "delete"]], "Edit": [[13, "edit"]], "Import": [[13, "import"]], "List": [[13, "list"]], "Show": [[13, "show"]], "Node Profiles": [[14, "node-profiles"]], "An Introduction To Profiles": [[14, "an-introduction-to-profiles"]], "Multiple Profiles": [[14, "multiple-profiles"]], "Cascading Profiles": [[14, "cascading-profiles"]], "Overriding Profiles": [[14, "overriding-profiles"]], "How To Use Profiles Effectively": [[14, "how-to-use-profiles-effectively"]], "Node Provisioning": [[15, "node-provisioning"]], "Node Hardware Setup": [[15, "node-hardware-setup"]], "The Provisioning Process": [[15, "the-provisioning-process"]], "Node status": [[15, "node-status"]], "Security": [[16, "security"]], "SELinux": [[16, "selinux"]], "Provisioning Security": [[16, "provisioning-security"]], "Summary": [[16, "summary"]], "Control Server Setup": [[17, "control-server-setup"]], "Operating System Installation": [[17, "operating-system-installation"]], "Network": [[17, "network"]], "Addressing": [[17, "addressing"]], "Multiple networks": [[17, "multiple-networks"]], "Stateless Provisioning": [[18, "stateless-provisioning"]], "Why is Provisioning Important": [[18, "why-is-provisioning-important"]], "Provisioning Overview": [[18, "provisioning-overview"]], "Why Stateless Provisioning": [[18, "why-stateless-provisioning"]], "Templating": [[19, "templating"]], "Examples": [[19, "examples"]], "Comment": [[19, "comment"]], "Range": [[19, "range"]], "Increment Variable In Loop": [[19, "increment-variable-in-loop"]], "Decrement": [[19, "decrement"]], "Access Tag": [[19, "access-tag"]], "Create Multiple Files": [[19, "create-multiple-files"]], "Special Commands": [[19, "special-commands"]], "Include": [[19, "include"]], "IncludeFrom": [[19, "includefrom"]], "IncludeBlock": [[19, "includeblock"]], "Abort": [[19, "abort"]], "Nobackup": [[19, "nobackup"]], "Split": [[19, "split"]], "Node specific files": [[19, "node-specific-files"]], "Controlling Warewulf (wwctl)": [[20, "controlling-warewulf-wwctl"]], "Hostlists": [[20, "hostlists"]], "Contributing": [[21, "contributing"], [27, null]], "Join the community": [[21, "join-the-community"]], "Warewulf on Slack": [[21, "warewulf-on-slack"]], "Raise an Issue": [[21, "raise-an-issue"]], "Contribute to the code": [[21, "contribute-to-the-code"]], "Step 1. Fork the repo": [[21, "step-1-fork-the-repo"]], "Step 2. Checkout a new branch": [[21, "step-2-checkout-a-new-branch"]], "Step 3. Make your changes": [[21, "step-3-make-your-changes"]], "Step 4. Push your branch to your fork": [[21, "step-4-push-your-branch-to-your-fork"]], "Step 5. Submit a Pull Request": [[21, "step-5-submit-a-pull-request"]], "Step 6. Keep your branch in sync": [[21, "step-6-keep-your-branch-in-sync"]], "Debugging": [[22, "debugging"]], "Validating the code with vet": [[22, "validating-the-code-with-vet"]], "Running the full test suite": [[22, "running-the-full-test-suite"]], "Using delve": [[22, "using-delve"]], "Installing delve": [[22, "installing-delve"]], "Running delve against a specific test": [[22, "running-delve-against-a-specific-test"]], "Example debugging session": [[22, "example-debugging-session"]], "Development Environment (KVM)": [[23, "development-environment-kvm"]], "Create CentOS 7 development virtual machine under KVM": [[23, "create-centos-7-development-virtual-machine-under-kvm"]], "Turn off default network dhcp on server master1": [[23, "turn-off-default-network-dhcp-on-server-master1"]], "Build and install Warewulf on wwdev": [[23, "build-and-install-warewulf-on-wwdev"]], "Development Environment (Vagrant)": [[24, "development-environment-vagrant"]], "Host system requirements": [[24, "host-system-requirements"]], "CPU H/W Virtualization support": [[24, "cpu-h-w-virtualization-support"]], "KVM kernel module": [[24, "kvm-kernel-module"]], "Setup development environment on Rocky Linux 9": [[24, "setup-development-environment-on-rocky-linux-9"]], "Install QEMU, libvirt": [[24, "install-qemu-libvirt"]], "Install Cockpit (Optional)": [[24, "install-cockpit-optional"]], "Install Vagrant, vagrant-libvirt plug-in and vagrant-reload plug-in": [[24, "install-vagrant-vagrant-libvirt-plug-in-and-vagrant-reload-plug-in"]], "Vagrant box and Vagrantfile for Warewulf sandbox": [[24, "vagrant-box-and-vagrantfile-for-warewulf-sandbox"]], "Create Rocky Linux 9.2 vagrant box": [[24, "create-rocky-linux-9-2-vagrant-box"]], "Vagrantfile": [[24, "vagrantfile"]], "Spin up head node": [[24, "spin-up-head-node"]], "Spin up compute nodes": [[24, "spin-up-compute-nodes"]], "Development Environment (VirtualBox)": [[25, "development-environment-virtualbox"]], "Documentation": [[26, "documentation"]], "User Guide": [[27, "user-guide"]], "Contents": [[27, null]], "Quickstart": [[27, null]], "Debian 12 Quickstart": [[28, "debian-12-quickstart"]], "Install the basic services": [[28, "install-the-basic-services"]], "Install Warewulf and dependencies": [[28, "install-warewulf-and-dependencies"], [29, "install-warewulf-and-dependencies"], [30, "install-warewulf-and-dependencies"], [31, "install-warewulf-and-dependencies"]], "Configure firewalld": [[28, "configure-firewalld"], [29, "configure-firewalld"], [30, "configure-firewalld"]], "Configure the controller": [[28, "configure-the-controller"], [29, "configure-the-controller"], [30, "configure-the-controller"], [31, "configure-the-controller"]], "Start and enable the Warewulf service": [[28, "start-and-enable-the-warewulf-service"], [29, "start-and-enable-the-warewulf-service"], [30, "start-and-enable-the-warewulf-service"], [31, "start-and-enable-the-warewulf-service"]], "Configure system services automatically": [[28, "configure-system-services-automatically"], [29, "configure-system-services-automatically"], [30, "configure-system-services-automatically"], [31, "configure-system-services-automatically"]], "Pull and build the VNFS container (including the kernel)": [[28, "pull-and-build-the-vnfs-container-including-the-kernel"], [29, "pull-and-build-the-vnfs-container-including-the-kernel"], [30, "pull-and-build-the-vnfs-container-including-the-kernel"]], "Set up the default node profile": [[28, "set-up-the-default-node-profile"], [29, "set-up-the-default-node-profile"], [30, "set-up-the-default-node-profile"], [31, "set-up-the-default-node-profile"]], "Add a node": [[28, "add-a-node"], [29, "add-a-node"], [30, "add-a-node"], [31, "add-a-node"]], "EL8 Quickstart (Rocky Linux and RHEL)": [[29, "el8-quickstart-rocky-linux-and-rhel"]], "EL9 Quickstart (Rocky Linux and RHEL)": [[30, "el9-quickstart-rocky-linux-and-rhel"]], "openSUSE Leap and SLES 15 Quickstart": [[31, "opensuse-leap-and-sles-15-quickstart"]], "Install Warewulf from the open build service": [[31, "install-warewulf-from-the-open-build-service"]], "Pull and build the VNFS container and kernel": [[31, "pull-and-build-the-vnfs-container-and-kernel"]]}, "indexentries": {}}) \ No newline at end of file